.net-core - 如何使用 MVC 的内容协商在 ASP.NET Core MVC 中间件中返回响应?

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

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

虽然很容易只是httpContext.Response.WriteAsync写一个字符串,例如使用 JsonSerializer要将对象序列化为字符串,我想使用标准序列化设置和内容协商,以便如果我将默认输出格式更改为 XML 或 text/xml当我配置了多个输出格式化程序时会发送接受 header ,然后返回 XML,就像我返回 ObjectResult 一样从 Controller 。

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

这是我目前只写 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 中是不可能的.
这将是可能的 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; }
    }

关于.net-core - 如何使用 MVC 的内容协商在 ASP.NET Core MVC 中间件中返回响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48228167/

相关文章:

c# - 如何阻止选择标签助手自动添加 'multiple' 属性

c# - 为什么我的表单不将参数传递给我的 Controller ?

asp.net-core-mvc - 使用 ASP.NET Core MVC 6 将编辑器模板放在 View 的文件夹中

go - 在goLang中使用julienschmidt/httprouter时如何使用中间件?

node.js - Express中如何依赖其他中间件?

ruby-on-rails - 为什么添加这样的 Rails 中间件会导致无休止的重定向?

c# - 如何使用 .Net Core 创建 PKCS#7 分离签名?

c# - 多目标 .net core 2.2 和 .net 4.6.1

c# - .NET Core 中的 win/any 运行时是什么意思

iis - 允许升级的 Asp.Net Core 魔术文件