【问题标题】:How can I return a response in ASP.NET Core MVC middleware using MVC's content negotiation?如何使用 MVC 的内容协商在 ASP.NET Core MVC 中间件中返回响应?
【发布时间】:2018-01-12 14:23:22
【问题描述】:

我有一些 ASP.NET Core MVC 中间件来捕获我想从中返回响应的未处理异常。

虽然httpContext.Response.WriteAsync 很容易写一个字符串,例如使用JsonSerializer 将对象序列化为字符串,我想使用标准的序列化设置和内容协商,以便如果我将默认输出格式更改为XML 或text/xml 在我有多个输出格式化程序时发送接受标头如果我从控制器返回 ObjectResult,则会返回 XML。

有谁知道如何在中间件中实现这一点?

这是我目前只写 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;
    }
}

【问题讨论】:

    标签: .net-core asp.net-core-mvc middleware asp.net-core-2.0


    【解决方案1】:

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

    这将是可能的in 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; }
        }
    

    【讨论】:

    • 知道为什么var executor = context.RequestServices.GetService&lt;IActionResultExecutor&lt;TResult&gt;&gt;(); 这段代码会失败吗?我尝试了所有变体,包括仅解析 ObjectResultExecutor。没有任何效果。但是我可以看到它在services.AddMvc()之后注册。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 2019-02-07
    • 1970-01-01
    • 1970-01-01
    • 2014-06-15
    相关资源
    最近更新 更多