RefactoringDI

This commit is contained in:
2026-04-13 14:37:21 +02:00
parent 9a93920b71
commit cf20bd94d0
541 changed files with 26821 additions and 243 deletions
@@ -0,0 +1,54 @@
using Microsoft.EntityFrameworkCore;
using TrafagSalesExporter.Data;
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public class ConsolidatedExportService : IConsolidatedExportService
{
private readonly IDbContextFactory<AppDbContext> _dbFactory;
private readonly IExcelExportService _excelService;
private readonly ISharePointUploadService _sharePointService;
public ConsolidatedExportService(
IDbContextFactory<AppDbContext> dbFactory,
IExcelExportService excelService,
ISharePointUploadService sharePointService)
{
_dbFactory = dbFactory;
_excelService = excelService;
_sharePointService = sharePointService;
}
public async Task<string?> ExportAsync(List<SalesRecord> records)
{
if (records.Count == 0)
return null;
using var db = await _dbFactory.CreateDbContextAsync();
var spConfig = await db.SharePointConfigs.FirstOrDefaultAsync();
var outputDir = Path.Combine(AppContext.BaseDirectory, "output");
var consolidatedPath = _excelService.CreateConsolidatedExcelFile(
outputDir,
DateTime.UtcNow.Date,
records
.OrderBy(r => r.Land)
.ThenBy(r => r.Tsc)
.ThenByDescending(r => r.InvoiceDate ?? DateTime.MinValue)
.ThenBy(r => r.InvoiceNumber)
.ThenBy(r => r.PositionOnInvoice)
.ToList());
if (spConfig is not null &&
!string.IsNullOrWhiteSpace(spConfig.TenantId) &&
!string.IsNullOrWhiteSpace(spConfig.ClientId) &&
!string.IsNullOrWhiteSpace(spConfig.ClientSecret))
{
await _sharePointService.UploadAsync(
spConfig.TenantId, spConfig.ClientId, spConfig.ClientSecret,
spConfig.SiteUrl, spConfig.ExportFolder, "Alle", consolidatedPath);
}
return consolidatedPath;
}
}
@@ -0,0 +1,121 @@
using System.Data;
using Microsoft.EntityFrameworkCore;
using TrafagSalesExporter.Data;
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public class DatabaseInitializationService : IDatabaseInitializationService
{
private readonly IDbContextFactory<AppDbContext> _dbFactory;
public DatabaseInitializationService(IDbContextFactory<AppDbContext> dbFactory)
{
_dbFactory = dbFactory;
}
public async Task InitializeAsync()
{
using var db = await _dbFactory.CreateDbContextAsync();
await db.Database.EnsureCreatedAsync();
EnsureSchema(db);
SeedIfEmpty(db);
}
private static void EnsureSchema(AppDbContext db)
{
AddColumnIfMissing(db, "HanaServers", "DatabaseName", "TEXT NOT NULL DEFAULT ''");
AddColumnIfMissing(db, "HanaServers", "UseSsl", "INTEGER NOT NULL DEFAULT 0");
AddColumnIfMissing(db, "HanaServers", "ValidateCertificate", "INTEGER NOT NULL DEFAULT 0");
AddColumnIfMissing(db, "HanaServers", "AdditionalParams", "TEXT NOT NULL DEFAULT ''");
AddColumnIfMissing(db, "Sites", "SourceSystem", "TEXT NOT NULL DEFAULT 'SAP'");
EnsureTransformationTable(db);
}
private static void AddColumnIfMissing(AppDbContext db, string table, string column, string type)
{
var conn = db.Database.GetDbConnection();
if (conn.State != ConnectionState.Open)
conn.Open();
var exists = false;
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = $"PRAGMA table_info({table})";
using var reader = cmd.ExecuteReader();
while (reader.Read())
{
if (string.Equals(reader["name"]?.ToString(), column, StringComparison.OrdinalIgnoreCase))
{
exists = true;
break;
}
}
}
if (!exists)
{
using var alter = conn.CreateCommand();
alter.CommandText = $"ALTER TABLE {table} ADD COLUMN {column} {type}";
alter.ExecuteNonQuery();
}
}
private static void EnsureTransformationTable(AppDbContext db)
{
var conn = db.Database.GetDbConnection();
if (conn.State != ConnectionState.Open)
conn.Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = @"
CREATE TABLE IF NOT EXISTS FieldTransformationRules (
Id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
SourceSystem TEXT NOT NULL DEFAULT 'SAP',
SourceField TEXT NOT NULL,
TargetField TEXT NOT NULL,
TransformationType TEXT NOT NULL,
Argument TEXT NOT NULL DEFAULT '',
SortOrder INTEGER NOT NULL DEFAULT 0,
IsActive INTEGER NOT NULL DEFAULT 1
);";
cmd.ExecuteNonQuery();
}
private static void SeedIfEmpty(AppDbContext db)
{
if (db.HanaServers.Any())
return;
var serverInternal = new HanaServer { Name = "Internal", Host = "travtrp0", Port = 30015, Username = "", Password = "" };
var serverIndia = new HanaServer { Name = "India", Host = "20.197.20.60", Port = 30015, Username = "", Password = "" };
db.HanaServers.AddRange(serverInternal, serverIndia);
db.SaveChanges();
db.Sites.AddRange(
new Site { HanaServerId = serverInternal.Id, Schema = "fr01_p", TSC = "TRFR", Land = "Frankreich", IsActive = true },
new Site { HanaServerId = serverInternal.Id, Schema = "it01_p", TSC = "TRIT", Land = "Italien", IsActive = true },
new Site { HanaServerId = serverInternal.Id, Schema = "us01_p", TSC = "TRUS", Land = "USA", IsActive = true },
new Site { HanaServerId = serverIndia.Id, Schema = "TRAFAG_LIVE", TSC = "TRIN", Land = "Indien", IsActive = true }
);
db.SharePointConfigs.Add(new SharePointConfig
{
SiteUrl = "https://trafagag.sharepoint.com/sites/WorldwideBIPlatform",
ExportFolder = "/Shared Documents/Exports/",
TenantId = "",
ClientId = "",
ClientSecret = ""
});
db.ExportSettings.Add(new ExportSettings
{
DateFilter = "2025-01-01",
TimerHour = 3,
TimerMinute = 0,
TimerEnabled = true
});
db.SaveChanges();
}
}
@@ -3,7 +3,7 @@ using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public class ExcelExportService
public class ExcelExportService : IExcelExportService
{
public string CreateExcelFile(string outputDirectory, string tsc, DateTime fileDate, List<SalesRecord> records)
{
@@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore;
using TrafagSalesExporter.Data;
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public class ExportLogService : IExportLogService
{
private readonly IDbContextFactory<AppDbContext> _dbFactory;
public ExportLogService(IDbContextFactory<AppDbContext> dbFactory)
{
_dbFactory = dbFactory;
}
public async Task WriteAsync(ExportLog log)
{
using var db = await _dbFactory.CreateDbContextAsync();
db.ExportLogs.Add(log);
await db.SaveChangesAsync();
}
}
@@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore;
using System.Diagnostics;
using TrafagSalesExporter.Data;
using TrafagSalesExporter.Models;
@@ -8,11 +7,9 @@ namespace TrafagSalesExporter.Services;
public class ExportOrchestrationService
{
private readonly IDbContextFactory<AppDbContext> _dbFactory;
private readonly HanaQueryService _hanaService;
private readonly ExcelExportService _excelService;
private readonly SharePointUploadService _sharePointService;
private readonly RecordTransformationService _transformationService;
private readonly ILogger<ExportOrchestrationService> _logger;
private readonly ISiteExportService _siteExportService;
private readonly IConsolidatedExportService _consolidatedExportService;
private readonly IExportLogService _exportLogService;
public event Action? OnExportStatusChanged;
@@ -21,18 +18,14 @@ public class ExportOrchestrationService
public ExportOrchestrationService(
IDbContextFactory<AppDbContext> dbFactory,
HanaQueryService hanaService,
ExcelExportService excelService,
SharePointUploadService sharePointService,
RecordTransformationService transformationService,
ILogger<ExportOrchestrationService> logger)
ISiteExportService siteExportService,
IConsolidatedExportService consolidatedExportService,
IExportLogService exportLogService)
{
_dbFactory = dbFactory;
_hanaService = hanaService;
_excelService = excelService;
_sharePointService = sharePointService;
_transformationService = transformationService;
_logger = logger;
_siteExportService = siteExportService;
_consolidatedExportService = consolidatedExportService;
_exportLogService = exportLogService;
}
public bool IsExporting(int siteId)
@@ -64,31 +57,7 @@ public class ExportOrchestrationService
consolidatedRecords.AddRange(result.Records);
}
if (consolidatedRecords.Count > 0)
{
var spConfig = await db.SharePointConfigs.FirstOrDefaultAsync();
var outputDir = Path.Combine(AppContext.BaseDirectory, "output");
var consolidatedPath = _excelService.CreateConsolidatedExcelFile(
outputDir,
DateTime.UtcNow.Date,
consolidatedRecords
.OrderBy(r => r.Land)
.ThenBy(r => r.Tsc)
.ThenByDescending(r => r.InvoiceDate ?? DateTime.MinValue)
.ThenBy(r => r.InvoiceNumber)
.ThenBy(r => r.PositionOnInvoice)
.ToList());
if (spConfig is not null &&
!string.IsNullOrWhiteSpace(spConfig.TenantId) &&
!string.IsNullOrWhiteSpace(spConfig.ClientId) &&
!string.IsNullOrWhiteSpace(spConfig.ClientSecret))
{
await _sharePointService.UploadAsync(
spConfig.TenantId, spConfig.ClientId, spConfig.ClientSecret,
spConfig.SiteUrl, spConfig.ExportFolder, "Alle", consolidatedPath);
}
}
await _consolidatedExportService.ExportAsync(consolidatedRecords);
}
public async Task ExportSiteByIdAsync(int siteId)
@@ -102,6 +71,7 @@ public class ExportOrchestrationService
private async Task<SiteExportResult?> ExportSiteAsync(Site site)
{
if (site.HanaServer is null) return null;
SiteExportResult? result = null;
lock (_lock)
{
@@ -110,75 +80,17 @@ public class ExportOrchestrationService
}
NotifyChanged();
var sw = Stopwatch.StartNew();
var log = new ExportLog
{
Timestamp = DateTime.Now,
SiteId = site.Id,
Land = site.Land,
TSC = site.TSC
};
try
{
using var db = await _dbFactory.CreateDbContextAsync();
var settings = await db.ExportSettings.FirstOrDefaultAsync() ?? new ExportSettings();
var spConfig = await db.SharePointConfigs.FirstOrDefaultAsync();
UpdateStatus(site.Id, "HANA Abfrage...");
var records = await Task.Run(() => _hanaService.GetSalesRecords(
site.HanaServer, site.Schema, site.TSC, site.Land, settings.DateFilter));
UpdateStatus(site.Id, "Transformationen anwenden...");
var rules = await db.FieldTransformationRules
.Where(r => r.IsActive && r.SourceSystem == (string.IsNullOrWhiteSpace(site.SourceSystem) ? "SAP" : site.SourceSystem))
.OrderBy(r => r.SortOrder)
.ToListAsync();
_transformationService.Apply(records, rules);
UpdateStatus(site.Id, "Excel erstellen...");
var outputDir = Path.Combine(AppContext.BaseDirectory, "output");
var filePath = _excelService.CreateExcelFile(outputDir, site.TSC, DateTime.UtcNow.Date, records);
var fileName = Path.GetFileName(filePath);
if (spConfig is not null &&
!string.IsNullOrWhiteSpace(spConfig.TenantId) &&
!string.IsNullOrWhiteSpace(spConfig.ClientId) &&
!string.IsNullOrWhiteSpace(spConfig.ClientSecret))
{
UpdateStatus(site.Id, "SharePoint Upload...");
await _sharePointService.UploadAsync(
spConfig.TenantId, spConfig.ClientId, spConfig.ClientSecret,
spConfig.SiteUrl, spConfig.ExportFolder, site.Land, filePath);
}
sw.Stop();
log.Status = "OK";
log.RowCount = records.Count;
log.FileName = fileName;
log.DurationSeconds = sw.Elapsed.TotalSeconds;
_logger.LogInformation("Export OK: {Land} ({TSC}) - {Rows} Zeilen in {Duration:F1}s",
site.Land, site.TSC, records.Count, sw.Elapsed.TotalSeconds);
return new SiteExportResult(records, filePath);
}
catch (Exception ex)
{
sw.Stop();
log.Status = "Error";
log.ErrorMessage = ex.Message;
log.FileName = string.Empty;
log.DurationSeconds = sw.Elapsed.TotalSeconds;
_logger.LogError(ex, "Export Fehler: {Land} ({TSC})", site.Land, site.TSC);
return null;
result = await _siteExportService.ExportAsync(site, status => UpdateStatus(site.Id, status));
return result;
}
finally
{
using var db = await _dbFactory.CreateDbContextAsync();
db.ExportLogs.Add(log);
await db.SaveChangesAsync();
if (result is not null)
{
await _exportLogService.WriteAsync(result.Log);
}
lock (_lock)
{
@@ -201,6 +113,4 @@ public class ExportOrchestrationService
{
OnExportStatusChanged?.Invoke();
}
private sealed record SiteExportResult(List<SalesRecord> Records, string FilePath);
}
@@ -3,7 +3,7 @@ using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public class HanaQueryService
public class HanaQueryService : IHanaQueryService
{
public List<SalesRecord> GetSalesRecords(HanaServer server,
string schema, string tsc, string land, string dateFilter)
@@ -0,0 +1,8 @@
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public interface IConsolidatedExportService
{
Task<string?> ExportAsync(List<SalesRecord> records);
}
@@ -0,0 +1,6 @@
namespace TrafagSalesExporter.Services;
public interface IDatabaseInitializationService
{
Task InitializeAsync();
}
@@ -0,0 +1,9 @@
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public interface IExcelExportService
{
string CreateExcelFile(string outputDirectory, string tsc, DateTime fileDate, List<SalesRecord> records);
string CreateConsolidatedExcelFile(string outputDirectory, DateTime fileDate, List<SalesRecord> records);
}
@@ -0,0 +1,8 @@
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public interface IExportLogService
{
Task WriteAsync(ExportLog log);
}
@@ -0,0 +1,10 @@
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public interface IHanaQueryService
{
List<SalesRecord> GetSalesRecords(HanaServer server, string schema, string tsc, string land, string dateFilter);
ConnectionTestResult TestConnectionDetailed(HanaServer server);
void TestConnection(HanaServer server);
}
@@ -0,0 +1,8 @@
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public interface IRecordTransformationService
{
void Apply(List<SalesRecord> records, IEnumerable<FieldTransformationRule> rules);
}
@@ -0,0 +1,7 @@
namespace TrafagSalesExporter.Services;
public interface ISharePointUploadService
{
Task UploadAsync(string tenantId, string clientId, string clientSecret, string siteUrl, string exportFolder, string land, string localFilePath);
Task TestConnectionAsync(string tenantId, string clientId, string clientSecret, string siteUrl);
}
@@ -0,0 +1,8 @@
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public interface ISiteExportService
{
Task<SiteExportResult> ExportAsync(Site site, Action<string>? updateStatus = null);
}
@@ -0,0 +1,7 @@
namespace TrafagSalesExporter.Services;
public interface ITransformationStrategy
{
string TransformationType { get; }
object? Transform(object? sourceValue, string? argument);
}
@@ -3,12 +3,19 @@ using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public class RecordTransformationService
public class RecordTransformationService : IRecordTransformationService
{
private static readonly Dictionary<string, PropertyInfo> PropertyMap = typeof(SalesRecord)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.ToDictionary(p => p.Name, p => p, StringComparer.OrdinalIgnoreCase);
private readonly IReadOnlyDictionary<string, ITransformationStrategy> _strategies;
public RecordTransformationService(IEnumerable<ITransformationStrategy> strategies)
{
_strategies = strategies.ToDictionary(s => s.TransformationType, StringComparer.OrdinalIgnoreCase);
}
public void Apply(List<SalesRecord> records, IEnumerable<FieldTransformationRule> rules)
{
var orderedRules = rules.Where(r => r.IsActive).OrderBy(r => r.SortOrder).ToList();
@@ -23,37 +30,19 @@ public class RecordTransformationService
}
}
private static void ApplyRule(SalesRecord record, FieldTransformationRule rule)
private void ApplyRule(SalesRecord record, FieldTransformationRule rule)
{
if (!PropertyMap.TryGetValue(rule.SourceField, out var sourceProp)) return;
if (!PropertyMap.TryGetValue(rule.TargetField, out var targetProp)) return;
var sourceValue = sourceProp.GetValue(record);
object? result = rule.TransformationType switch
{
"Copy" => sourceValue,
"Uppercase" => sourceValue?.ToString()?.ToUpperInvariant(),
"Lowercase" => sourceValue?.ToString()?.ToLowerInvariant(),
"Prefix" => $"{rule.Argument}{sourceValue}",
"Suffix" => $"{sourceValue}{rule.Argument}",
"Replace" => ApplyReplace(sourceValue?.ToString(), rule.Argument),
"Constant" => rule.Argument,
_ => sourceValue
};
object? result = _strategies.TryGetValue(rule.TransformationType, out var strategy)
? strategy.Transform(sourceValue, rule.Argument)
: sourceValue;
SetPropertyValue(record, targetProp, result);
}
private static string ApplyReplace(string? input, string? argument)
{
if (string.IsNullOrEmpty(input)) return string.Empty;
if (string.IsNullOrWhiteSpace(argument)) return input;
var parts = argument.Split("=>", 2, StringSplitOptions.TrimEntries);
if (parts.Length != 2) return input;
return input.Replace(parts[0], parts[1], StringComparison.OrdinalIgnoreCase);
}
private static void SetPropertyValue(SalesRecord record, PropertyInfo property, object? value)
{
try
@@ -3,7 +3,7 @@ using Microsoft.Graph;
namespace TrafagSalesExporter.Services;
public class SharePointUploadService
public class SharePointUploadService : ISharePointUploadService
{
public async Task UploadAsync(string tenantId, string clientId, string clientSecret,
string siteUrl, string exportFolder, string land, string localFilePath)
@@ -0,0 +1,10 @@
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public sealed class SiteExportResult
{
public required List<SalesRecord> Records { get; init; }
public required ExportLog Log { get; init; }
public string? FilePath { get; init; }
}
@@ -0,0 +1,114 @@
using Microsoft.EntityFrameworkCore;
using System.Diagnostics;
using TrafagSalesExporter.Data;
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public class SiteExportService : ISiteExportService
{
private readonly IDbContextFactory<AppDbContext> _dbFactory;
private readonly IHanaQueryService _hanaService;
private readonly IExcelExportService _excelService;
private readonly ISharePointUploadService _sharePointService;
private readonly IRecordTransformationService _transformationService;
private readonly ILogger<SiteExportService> _logger;
public SiteExportService(
IDbContextFactory<AppDbContext> dbFactory,
IHanaQueryService hanaService,
IExcelExportService excelService,
ISharePointUploadService sharePointService,
IRecordTransformationService transformationService,
ILogger<SiteExportService> logger)
{
_dbFactory = dbFactory;
_hanaService = hanaService;
_excelService = excelService;
_sharePointService = sharePointService;
_transformationService = transformationService;
_logger = logger;
}
public async Task<SiteExportResult> ExportAsync(Site site, Action<string>? updateStatus = null)
{
if (site.HanaServer is null)
throw new InvalidOperationException($"Standort '{site.Land}' hat keinen HANA-Server.");
var sw = Stopwatch.StartNew();
var log = new ExportLog
{
Timestamp = DateTime.Now,
SiteId = site.Id,
Land = site.Land,
TSC = site.TSC
};
try
{
using var db = await _dbFactory.CreateDbContextAsync();
var settings = await db.ExportSettings.FirstOrDefaultAsync() ?? new ExportSettings();
var spConfig = await db.SharePointConfigs.FirstOrDefaultAsync();
updateStatus?.Invoke("HANA Abfrage...");
var records = await Task.Run(() => _hanaService.GetSalesRecords(
site.HanaServer, site.Schema, site.TSC, site.Land, settings.DateFilter));
updateStatus?.Invoke("Transformationen anwenden...");
var rules = await db.FieldTransformationRules
.Where(r => r.IsActive && r.SourceSystem == (string.IsNullOrWhiteSpace(site.SourceSystem) ? "SAP" : site.SourceSystem))
.OrderBy(r => r.SortOrder)
.ToListAsync();
_transformationService.Apply(records, rules);
updateStatus?.Invoke("Excel erstellen...");
var outputDir = Path.Combine(AppContext.BaseDirectory, "output");
var filePath = _excelService.CreateExcelFile(outputDir, site.TSC, DateTime.UtcNow.Date, records);
var fileName = Path.GetFileName(filePath);
if (spConfig is not null &&
!string.IsNullOrWhiteSpace(spConfig.TenantId) &&
!string.IsNullOrWhiteSpace(spConfig.ClientId) &&
!string.IsNullOrWhiteSpace(spConfig.ClientSecret))
{
updateStatus?.Invoke("SharePoint Upload...");
await _sharePointService.UploadAsync(
spConfig.TenantId, spConfig.ClientId, spConfig.ClientSecret,
spConfig.SiteUrl, spConfig.ExportFolder, site.Land, filePath);
}
sw.Stop();
log.Status = "OK";
log.RowCount = records.Count;
log.FileName = fileName;
log.DurationSeconds = sw.Elapsed.TotalSeconds;
_logger.LogInformation("Export OK: {Land} ({TSC}) - {Rows} Zeilen in {Duration:F1}s",
site.Land, site.TSC, records.Count, sw.Elapsed.TotalSeconds);
return new SiteExportResult
{
Records = records,
Log = log,
FilePath = filePath
};
}
catch (Exception ex)
{
sw.Stop();
log.Status = "Error";
log.ErrorMessage = ex.Message;
log.FileName = string.Empty;
log.DurationSeconds = sw.Elapsed.TotalSeconds;
_logger.LogError(ex, "Export Fehler: {Land} ({TSC})", site.Land, site.TSC);
return new SiteExportResult
{
Records = [],
Log = log,
FilePath = null
};
}
}
}
@@ -0,0 +1,58 @@
namespace TrafagSalesExporter.Services;
public sealed class CopyTransformationStrategy : ITransformationStrategy
{
public string TransformationType => "Copy";
public object? Transform(object? sourceValue, string? argument) => sourceValue;
}
public sealed class UppercaseTransformationStrategy : ITransformationStrategy
{
public string TransformationType => "Uppercase";
public object? Transform(object? sourceValue, string? argument) => sourceValue?.ToString()?.ToUpperInvariant();
}
public sealed class LowercaseTransformationStrategy : ITransformationStrategy
{
public string TransformationType => "Lowercase";
public object? Transform(object? sourceValue, string? argument) => sourceValue?.ToString()?.ToLowerInvariant();
}
public sealed class PrefixTransformationStrategy : ITransformationStrategy
{
public string TransformationType => "Prefix";
public object? Transform(object? sourceValue, string? argument) => $"{argument}{sourceValue}";
}
public sealed class SuffixTransformationStrategy : ITransformationStrategy
{
public string TransformationType => "Suffix";
public object? Transform(object? sourceValue, string? argument) => $"{sourceValue}{argument}";
}
public sealed class ReplaceTransformationStrategy : ITransformationStrategy
{
public string TransformationType => "Replace";
public object? Transform(object? sourceValue, string? argument)
{
var input = sourceValue?.ToString();
if (string.IsNullOrEmpty(input))
return string.Empty;
if (string.IsNullOrWhiteSpace(argument))
return input;
var parts = argument.Split("=>", 2, StringSplitOptions.TrimEntries);
if (parts.Length != 2)
return input;
return input.Replace(parts[0], parts[1], StringComparison.OrdinalIgnoreCase);
}
}
public sealed class ConstantTransformationStrategy : ITransformationStrategy
{
public string TransformationType => "Constant";
public object? Transform(object? sourceValue, string? argument) => argument;
}