【问题标题】:MVC 6 HttpResponseExceptionMVC 6 HttpResponseException
【发布时间】:2016-02-21 13:24:37
【问题描述】:

我正在尝试通过以下方式返回状态码

throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized) { ReasonPhrase = "invalid username/password" });

现在 MVC6 不支持此功能,这很糟糕,因为使用 IActionResult 对我来说似乎真的很愚蠢,而且不太直观。 我发现了以下帖子onetwo。 第一个导致链接断开,第二个适用于 MVC 应用程序。

我确实意识到我需要创建一个中间件来解决这个问题,但我不确定从哪里开始,因为这是非常有用的东西,我希望有一些我可以使用的开源解决方案,或者也许一个代码 sn-p。

作为记录,我使用的是 ASP.net 5 rc1 update 1 MVC 6

【问题讨论】:

  • StatusCodeResult 有什么问题? github.com/aspnet/Mvc/blob/dev/src/…
  • 据我所知,您必须将操作的返回值设置为 IActionResult,我不希望这样
  • 我认为您应该返回正确的IActionResult (HttpUnauthorizedResult),因为这样可以将控制器的关注点保留在控制器内部,而不是从域的深处抛出异常。您是否希望在抛出异常后请求仍由其他中间件处理?另外,每个控制器都会抛出这个异常吗?
  • 我不得不说我不同意,在我看来,控制器的职责是管理一个资源,并且该资源应该在控制器中每个方法的标题中看到。当存在无效的工作流程(例如无效的凭据)时,抛出异常并让中间件解决异常更有意义。无论如何,这在 MVC5 中有效,这就是我最困扰的地方。

标签: c# asp.net asp.net-core asp.net-core-mvc


【解决方案1】:

我认为这种变化是由于 .NET Core - ASP.NET 尝试开箱即用地做所有事情,而 ASP.NET Core 只做你明确告诉它的事情(这是它如此重要的一个重要部分更快、更便携)。

如果您希望在 Core 中实现此行为,则需要将其添加为某人为您编写的包或滚动您自己的包。

这很简单。首先,您需要一个自定义异常来检查:

public class StatusCodeException : Exception
{
    public StatusCodeException(HttpStatusCode statusCode)
    {
        StatusCode = statusCode;
    }

    public HttpStatusCode StatusCode { get; set; }
}

然后您需要一个RequestDelegate 处理程序来检查新异常并将其转换为 HTTP 响应状态代码:

public class StatusCodeExceptionHandler
{
    private readonly RequestDelegate request;

    public StatusCodeExceptionHandler(RequestDelegate next)
    {
        this.request = next;
    }

    public Task Invoke(HttpContext context) => this.InvokeAsync(context); // Stops VS from nagging about async method without ...Async suffix.

    async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await this.request(context);
        }
        catch (StatusCodeException exception)
        {
            context.Response.StatusCode = (int)exception.StatusCode;
            context.Response.Headers.Clear();
        }
    }
}

然后你在你的启动中注册这个中间件:

public class Startup
{
    ...

    public void Configure(IApplicationBuilder app)
    {
        ...
        app.UseMiddleware<StatusCodeExceptionHandler>();

最后,您可以在您的操作中抛出 HTTP 状态代码异常,同时仍然返回一个您可以轻松进行单元测试的显式类型:

public Thing Get(int id) {
    Thing thing = GetThingFromDB();

    if (thing == null)
        throw new StatusCodeException(HttpStatusCode.NotFound);

    return thing;
}

这相当简单,可能有人已经写了一个更完整的,但我无法找到一个或得到一个明确的答案,为什么它被放弃了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-18
    • 1970-01-01
    相关资源
    最近更新 更多