using System.Text.Json;
using System.Text.Json.Serialization;
namespace Avalonia_Services.Core
{
///
/// Binds unified endpoint request models from JSON bodies or query parameters.
///
internal static class ServiceRequestBinder
{
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web)
{
NumberHandling = JsonNumberHandling.AllowReadingFromString,
};
///
/// Bind a JSON request body. Empty bodies are treated as an empty JSON object.
///
public static T BindBody(ServiceEndpointContext context)
{
var json = string.IsNullOrWhiteSpace(context.Body) ? "{}" : context.Body;
return Deserialize(json, "body");
}
///
/// Bind route and query parameters to a request DTO.
///
public static T BindQuery(ServiceEndpointContext context)
{
var values = new Dictionary(context.Query, StringComparer.OrdinalIgnoreCase);
foreach (var routeValue in context.RouteValues)
{
values[routeValue.Key] = routeValue.Value;
}
var json = JsonSerializer.Serialize(values, JsonOptions);
return Deserialize(json, "query");
}
private static T Deserialize(string json, string source)
{
try
{
return JsonSerializer.Deserialize(json, JsonOptions)
?? throw new ArgumentException($"Request {source} cannot be bound to {typeof(T).Name}.");
}
catch (JsonException ex)
{
throw new ArgumentException($"Request {source} cannot be bound to {typeof(T).Name}.", ex);
}
}
}
}