Dot-Net-Core

如何使用 MVC 的內容協商在 ASP.NET Core MVC 中間件中返迴響應?

  • June 16, 2021

我有一些 ASP.NET Core MVC 中間件來擷取我想從中返迴響應的未處理異常。

雖然只httpContext.Response.WriteAsync寫一個字元串並例如用於JsonSerializer將對象序列化為字元串很容易,但我想使用標準的序列化設置和內容協商,以便如果我將預設輸出格式更改為 XML 或text/xml發送接受標頭當我配置了多個輸出格式化程序時,會返回 XML,就像我ObjectResult從控制器返回一個一樣。

有誰知道如何在中間件中實現這一點?

到目前為止,這是我的程式碼,它只寫 JSON:

public class UnhandledExceptionMiddleware
{
   private readonly RequestDelegate _next;
   private readonly IOutputFormatter _outputFormatter;
   private readonly IHttpResponseStreamWriterFactory _streamWriterFactory;

   public UnhandledExceptionMiddleware(RequestDelegate next, JsonOutputFormatter outputFormatter, IHttpResponseStreamWriterFactory streamWriterFactory)
   {
       _next = next;
       _outputFormatter = outputFormatter;
       _streamWriterFactory = streamWriterFactory;
   }

   public async Task Invoke(HttpContext context)
   {
       try
       {
           await _next(context);
       }
       catch (Exception ex)
       {
           await HandleExceptionAsync(context, ex);
       }
   }

   private async Task HandleExceptionAsync(HttpContext context, Exception exception)
   {
       var error = new ErrorResultModel("Internal Server Error", exception.Message, exception.StackTrace);
       context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
       await _outputFormatter.WriteAsync(new OutputFormatterWriteContext(context, _streamWriterFactory.CreateWriter, typeof(ErrorResultModel), error));
   }
}

其中ErrorResultModel定義為:

public class ErrorResultModel
{
   public string ResultMessage { get; };
   public string ExceptionMessage { get; };
   public string ExceptionStackTrace { get; };

   public ErrorResultModel(string resultMessage, string exceptionMessage, string exceptionStackTrace)
   {
       ResultMessage = resultMessage;
       ExceptionMessage = exceptionMessage;
       ExceptionStackTrace = exceptionStackTrace;
   }
}

這在ASP.NET Core 2.0 MVC中是不可能的。

這將在 2.1 中成為可能:

   public static class HttpContextExtensions
   {
       private static readonly RouteData EmptyRouteData = new RouteData();
   
       private static readonly ActionDescriptor EmptyActionDescriptor = new ActionDescriptor();
   
       public static Task WriteResultAsync<TResult>(this HttpContext context, TResult result)
           where TResult : IActionResult
       {
           if (context == null)
           {
               throw new ArgumentNullException(nameof(context));
           }
   
           var executor = context.RequestServices.GetService<IActionResultExecutor<TResult>>();
   
           if (executor == null)
           {
               throw new InvalidOperationException($"No result executor for '{typeof(TResult).FullName}' has been registered.");
           }
   
           var routeData = context.GetRouteData() ?? EmptyRouteData;
   
           var actionContext = new ActionContext(context, routeData, EmptyActionDescriptor);
   
           return executor.ExecuteAsync(actionContext, result);
       }
   }

   public class Program : StartupBase
   {
       public static Task Main(string[] args)
       {
           return BuildWebHost(args).RunAsync();
       }
   
       public static IWebHost BuildWebHost(string[] args)
       {
           return new WebHostBuilder().UseStartup<Program>().UseKestrel().Build();
       }
   
       public override void ConfigureServices(IServiceCollection services)
       {
           services.AddMvcCore().AddJsonFormatters();
       }
   
       public override void Configure(IApplicationBuilder app)
       {
           app.Use((ctx, next) =>
           {
               var model = new Person("Krisian", "Hellang");
   
               var result = new ObjectResult(model);
   
               return ctx.WriteResultAsync(result);
           });
       }
   }
   
   public class Person
   {
       public Person(string firstName, string lastName)
       {
           FirstName = firstName;
           LastName = lastName;
       }
   
       public string FirstName { get; }
   
       public string LastName { get; }
   }

引用自:https://stackoverflow.com/questions/48228167