MVC 6 HttpResponseException

6

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

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

现在在MVC6中不支持这个,这很糟糕,因为使用IActionResult对我来说似乎非常愚蠢,而且不太直观。我找到了以下两篇文章onetwo。第一个链接无法访问,第二个链接适用于MVC应用程序。
我意识到我需要创建一个中间件来解决这个问题,但我不确定从哪里开始,既然这是非常有用的东西,我希望能有一些开源的解决方案或者代码片段可用。
记录一下,我正在使用ASP.net 5 rc1 update 1 MVC 6。

StatusCodeResult有什么问题吗?https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Core/StatusCodeResult.cs - Andreas
据我所知,你必须将操作的返回值设置为IActionResult,而我不想这样做。 - gilmishal
1
我认为你应该返回正确的 IActionResult (HttpUnauthorizedResult),因为这样可以将控制器的关注点保持在控制器内部,而不是从域深处抛出异常。你是否希望在抛出异常后仍然让请求被其他中间件处理?此外,这个异常是从每个控制器中抛出的吗? - Dr Rob Lang
我必须说我不同意,我认为控制器的责任是管理资源,并且该资源应该在控制器中每个方法的头部中看到。当存在无效的工作流程(例如无效凭据)时,抛出异常并让中间件解决异常更有意义。无论如何,这在MVC5中有效,这是我最困扰的地方。 - gilmishal
1个回答

6
我认为这种变化是由于.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;
}

这很简单,可能有人写了一个更完整的版本,但我找不到或得到一个清晰的答案,解释为什么这个被删除了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接