Restructure solution layout by module

This commit is contained in:
master
2025-10-28 15:10:40 +02:00
parent 95daa159c4
commit d870da18ce
4103 changed files with 192899 additions and 187024 deletions

View File

@@ -0,0 +1,9 @@
using System.Text.Json;
using Json.Schema;
namespace StellaOps.Concelier.Connector.Common.Json;
public interface IJsonSchemaValidator
{
void Validate(JsonDocument document, JsonSchema schema, string documentName);
}

View File

@@ -0,0 +1,7 @@
namespace StellaOps.Concelier.Connector.Common.Json;
public sealed record JsonSchemaValidationError(
string InstanceLocation,
string SchemaLocation,
string Message,
string Keyword);

View File

@@ -0,0 +1,15 @@
namespace StellaOps.Concelier.Connector.Common.Json;
public sealed class JsonSchemaValidationException : Exception
{
public JsonSchemaValidationException(string documentName, IReadOnlyList<JsonSchemaValidationError> errors)
: base($"JSON schema validation failed for '{documentName}'.")
{
DocumentName = documentName;
Errors = errors ?? Array.Empty<JsonSchemaValidationError>();
}
public string DocumentName { get; }
public IReadOnlyList<JsonSchemaValidationError> Errors { get; }
}

View File

@@ -0,0 +1,92 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Json.Schema;
using Microsoft.Extensions.Logging;
namespace StellaOps.Concelier.Connector.Common.Json;
public sealed class JsonSchemaValidator : IJsonSchemaValidator
{
private readonly ILogger<JsonSchemaValidator> _logger;
private const int MaxLoggedErrors = 5;
public JsonSchemaValidator(ILogger<JsonSchemaValidator> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public void Validate(JsonDocument document, JsonSchema schema, string documentName)
{
ArgumentNullException.ThrowIfNull(document);
ArgumentNullException.ThrowIfNull(schema);
ArgumentException.ThrowIfNullOrEmpty(documentName);
var result = schema.Evaluate(document.RootElement, new EvaluationOptions
{
OutputFormat = OutputFormat.List,
RequireFormatValidation = true,
});
if (result.IsValid)
{
return;
}
var errors = CollectErrors(result);
if (errors.Count == 0)
{
_logger.LogWarning("Schema validation failed for {Document} with unknown errors", documentName);
throw new JsonSchemaValidationException(documentName, errors);
}
foreach (var violation in errors.Take(MaxLoggedErrors))
{
_logger.LogWarning(
"Schema violation for {Document} at {InstanceLocation} (keyword: {Keyword}): {Message}",
documentName,
string.IsNullOrEmpty(violation.InstanceLocation) ? "#" : violation.InstanceLocation,
violation.Keyword,
violation.Message);
}
if (errors.Count > MaxLoggedErrors)
{
_logger.LogWarning("{Count} additional schema violations for {Document} suppressed", errors.Count - MaxLoggedErrors, documentName);
}
throw new JsonSchemaValidationException(documentName, errors);
}
private static IReadOnlyList<JsonSchemaValidationError> CollectErrors(EvaluationResults result)
{
var errors = new List<JsonSchemaValidationError>();
Aggregate(result, errors);
return errors;
}
private static void Aggregate(EvaluationResults node, List<JsonSchemaValidationError> errors)
{
if (node.Errors is { Count: > 0 })
{
foreach (var kvp in node.Errors)
{
errors.Add(new JsonSchemaValidationError(
node.InstanceLocation?.ToString() ?? string.Empty,
node.SchemaLocation?.ToString() ?? string.Empty,
kvp.Value,
kvp.Key));
}
}
if (node.Details is null)
{
return;
}
foreach (var child in node.Details)
{
Aggregate(child, errors);
}
}
}