Add local blob-triggered CSV validation with Azurite
This commit is contained in:
1 parent
b72aa278a5
commit
2075bcb2c3
7 files changed
+153
-27
No files matched your search
@@ -17,39 +17,19 @@ if (!File.Exists(path))
|
||||
return;
|
||||
}
|
||||
|
||||
var lines = File.ReadAllLines(path);
|
||||
IReadOnlyList<InvoiceRow> rows;
|
||||
|
||||
if (lines.Length == 0 ||
|
||||
lines[0] != "InvoiceId;CustomerId;Amount;Currency")
|
||||
try
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
"Die Datei ist leer oder die Kopfzeile stimmt nicht.");
|
||||
rows = InvoiceCsvParser.Parse(File.ReadAllText(path));
|
||||
}
|
||||
catch (FormatException exception)
|
||||
{
|
||||
Console.Error.WriteLine(exception.Message);
|
||||
Environment.ExitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
var rows = new List<InvoiceRow>();
|
||||
|
||||
for (var index = 1; index < lines.Length; index++)
|
||||
{
|
||||
var line = lines[index];
|
||||
var columns = line.Split(';');
|
||||
|
||||
if (line.Contains('"') || columns.Length != 4)
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"Zeile {index + 1}: Erwartet werden vier Spalten ohne Anführungszeichen.");
|
||||
Environment.ExitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
rows.Add(new InvoiceRow(
|
||||
columns[0],
|
||||
columns[1],
|
||||
columns[2],
|
||||
columns[3]));
|
||||
}
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var errors = InvoiceValidator.Validate(row);
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace ImportAssist.Core;
|
||||
|
||||
public static class InvoiceCsvParser
|
||||
{
|
||||
public static IReadOnlyList<InvoiceRow> Parse(string csv)
|
||||
{
|
||||
using var reader = new StringReader(csv);
|
||||
|
||||
var header = reader.ReadLine()?.TrimStart('\uFEFF');
|
||||
|
||||
if (header != "InvoiceId;CustomerId;Amount;Currency")
|
||||
{
|
||||
throw new FormatException(
|
||||
"Die Datei ist leer oder die Kopfzeile stimmt nicht.");
|
||||
}
|
||||
|
||||
var rows = new List<InvoiceRow>();
|
||||
var lineNumber = 1;
|
||||
|
||||
while (reader.ReadLine() is { } line)
|
||||
{
|
||||
lineNumber++;
|
||||
|
||||
var columns = line.Split(';');
|
||||
|
||||
if (line.Contains('"') || columns.Length != 4)
|
||||
{
|
||||
throw new FormatException(
|
||||
$"Zeile {lineNumber}: Erwartet werden vier Spalten ohne Anführungszeichen.");
|
||||
}
|
||||
|
||||
rows.Add(new InvoiceRow(
|
||||
columns[0],
|
||||
columns[1],
|
||||
columns[2],
|
||||
columns[3]));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.52.0" />
|
||||
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs" Version="6.8.2" />
|
||||
<PackageReference Include="Microsoft.Azure.Functions.Worker.OpenTelemetry" Version="1.2.0" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
|
||||
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.7.0" />
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using ImportAssist.Core;
|
||||
using Microsoft.Azure.Functions.Worker;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ImportAssist_Functions;
|
||||
|
||||
public sealed class InvoiceBlobTrigger(
|
||||
ILogger<InvoiceBlobTrigger> logger)
|
||||
{
|
||||
[Function("InvoiceBlobTrigger")]
|
||||
public void Run(
|
||||
[BlobTrigger(
|
||||
"imports/{name}",
|
||||
Connection = "AzureWebJobsStorage")]
|
||||
string content,
|
||||
string name)
|
||||
{
|
||||
IReadOnlyList<InvoiceRow> rows;
|
||||
|
||||
try
|
||||
{
|
||||
rows = InvoiceCsvParser.Parse(content);
|
||||
}
|
||||
catch (FormatException exception)
|
||||
{
|
||||
logger.LogWarning(
|
||||
"Datei {BlobName} wegen CSV-Formatfehler abgewiesen: {Reason}",
|
||||
name,
|
||||
exception.Message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var validCount = 0;
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var errors = InvoiceValidator.Validate(row);
|
||||
|
||||
if (errors.Count == 0)
|
||||
{
|
||||
validCount++;
|
||||
}
|
||||
|
||||
var invoiceId = string.IsNullOrWhiteSpace(row.InvoiceId)
|
||||
? "(ohne Rechnungsnummer)"
|
||||
: row.InvoiceId;
|
||||
|
||||
logger.LogInformation(
|
||||
"{BlobName}: {InvoiceId}: {Result}",
|
||||
name,
|
||||
invoiceId,
|
||||
errors.Count == 0
|
||||
? "Gültig"
|
||||
: string.Join("; ", errors));
|
||||
}
|
||||
|
||||
logger.LogInformation(
|
||||
"Dateiprüfung abgeschlossen: {BlobName}, " +
|
||||
"{TotalCount} Rechnungen, {ValidCount} gültig, {InvalidCount} fehlerhaft.",
|
||||
name,
|
||||
rows.Count,
|
||||
validCount,
|
||||
rows.Count - validCount);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user