57 lines
2.3 KiB
C#
57 lines
2.3 KiB
C#
using System.IO.Pipelines;
|
|
using AyCode.Core.Serializers.Binaries;
|
|
using Microsoft.AspNetCore.Mvc.Formatters;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace AyCode.Services.Mvc;
|
|
|
|
/// <summary>
|
|
/// ASP.NET Core MVC InputFormatter for AcBinary wire format. Reads request body via PipeReader,
|
|
/// drains into AsyncPipeReaderInput, deserializes to ModelType. Standard ProblemDetails error
|
|
/// flow on failure (ModelState.AddModelError → 400 + application/problem+json).
|
|
/// </summary>
|
|
public class AcBinaryInputFormatter : InputFormatter
|
|
{
|
|
/// <summary>Vendor media type. <c>application/vnd.acbinary</c> by default.</summary>
|
|
public const string DefaultMediaType = "application/vnd.acbinary";
|
|
|
|
private readonly AcBinarySerializerOptions _options;
|
|
private readonly ILogger<AcBinaryInputFormatter>? _logger;
|
|
|
|
public AcBinaryInputFormatter(AcBinarySerializerOptions? options = null, ILogger<AcBinaryInputFormatter>? logger = null)
|
|
{
|
|
_options = options ?? AcBinarySerializerOptions.Default;
|
|
_logger = logger;
|
|
SupportedMediaTypes.Add(DefaultMediaType);
|
|
}
|
|
|
|
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
|
|
{
|
|
if (context is null) throw new ArgumentNullException(nameof(context));
|
|
|
|
var ct = context.HttpContext.RequestAborted;
|
|
var reader = PipeReader.Create(context.HttpContext.Request.Body);
|
|
try
|
|
{
|
|
var model = await AcBinaryDeserializer.DeserializeFromPipeReaderAsync(reader, context.ModelType, _options, ct).ConfigureAwait(false);
|
|
return await InputFormatterResult.SuccessAsync(model).ConfigureAwait(false);
|
|
}
|
|
catch (OperationCanceledException) when (ct.IsCancellationRequested)
|
|
{
|
|
throw;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger?.LogWarning(ex, "AcBinary deserialization failed for type {ModelType}", context.ModelType);
|
|
context.ModelState.TryAddModelError(context.ModelName ?? string.Empty, ex.Message);
|
|
return await InputFormatterResult.FailureAsync().ConfigureAwait(false);
|
|
}
|
|
finally
|
|
{
|
|
await reader.CompleteAsync().ConfigureAwait(false);
|
|
}
|
|
}
|
|
|
|
protected override bool CanReadType(Type type) => true;
|
|
}
|