Dot-Net-Core
如何使用 MVC 的內容協商在 ASP.NET Core MVC 中間件中返迴響應?
我有一些 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; } }