在MVC3中,如何同时返回状态码、状态描述和文本?

17

从我的MVC3控制器操作中,我想返回HTTP 403,将“状态描述”设置为特定的字符串,并在结果内容中返回该字符串,以便在浏览器中可见。

我可以返回ContentResult来指定内容,但无法返回状态码(例如403)和状态描述。我可以使用HttpStatusCodeResult来指定状态码和状态描述,但不能指定结果内容。

我如何创建一个包含所有三个参数的操作结果?


1
为什么不使用自定义的Json({code: descr:})调用呢? - Tigran
1
@Tigran:对于这个简单的目的来说,那将是过度杀伤力。 - sharptooth
据我所知,这是不可能的,因此您需要创建明确的组合对象。在这种情况下,我认为最简单的解决方案是自定义Json对象。但我不是ASP.NET专家,也许有更简单的解决方案。 - Tigran
3个回答

19

通常你会看到这样做的方式是设置响应代码,然后返回一个常规的ActionResult。

public ActionResult Foo() 
{ 
    Response.StatusCode = 403;
    Response.StatusDescription = "Some custom message";

    return View(); // or Content(), Json(), etc
}
如果你真的需要将此作为一个ActionResult,你可以创建自己的ActionResult。
例子:
public class HttpStatusContentResult : ActionResult
{
    private string _content;
    private HttpStatusCode _statusCode;
    private string _statusDescription;

    public HttpStatusContentResult(string content, 
                                   HttpStatusCode statusCode = HttpStatusCode.OK,
                                   string statusDescription = null)
    {
        _content = content;
        _statusCode = statusCode;
        _statusDescription = statusDescription;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        var response = context.HttpContext.Response;
        response.StatusCode = (int) _statusCode;
        if (_statusDescription != null)
        {
            response.StatusDescription = _statusDescription;
        }

        if (_content != null)
        {
            context.HttpContext.Response.Write(_content);
        }
    }
}

3
如果_statusDescription为空,您可以将其赋值为HttpWorkerRequest.GetStatusDescription(response.StatusCode)。其背后是在string[][] s_HTTPStatusDescriptions中进行非常快速的查找,例如s_HTTPStatusDescriptions[StatusCode / 100][StatusCode % 100]。获取的值始终是状态代码的简短描述,例如“OK”或“Forbidden”,如果没有匹配的描述,则为空字符串。 - Triynko
我尝试了这个解决方案,当我在IIS Express上运行它时,它运行得很好,但是当我在我的生产环境上运行它时,它就无法工作了。发生的情况是,从我的Ajax请求中,我期望将_content值映射到responseText,但是在生产服务器IIS上,它也将其映射到statusText,请参考https://www.experts-exchange.com/questions/26457716/Response-write-not-working-when-deployed-to-IIS-Works-locally.html,他们也遇到了同样的问题。 - Saad A
现在提醒一下关于http2的事情。Http2不支持状态描述。https://tools.ietf.org/html/rfc7540#section-8.1.2.4说:“HTTP/2没有定义一种方法来传递包含在HTTP/1.1状态行中的版本或原因短语。” - Kevin

11

如果这不太脏的话

Response.Clear();
Response.Write("Some specific string");
return new HttpStatusCodeResult(403, "another specific string");

2
或者类似地,Response.StatusCode = 403; Response.StatusDescription="foo"; return Content("bad request mate"); - drch
2
如果您在代码之前对响应进行了更改,请不要忘记首先清除响应:Response.Clear(); - Haney

-1

在意识到问题是GetAwaiter().OnCompleted(...)之后,我试图让这段代码工作起来,结果把自己逼疯了。这是我最终成功的版本:

public class ApiControllerBase : ApiController
{
   ...
   // Other code
   ...

   public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
   {
      return base
         .ExecuteAsync(controllerContext, cancellationToken)
         .ContinueWith(t =>
         {
            t.Result.Headers.CacheControl = new CacheControlHeaderValue()
            {
               NoStore = true,
               NoCache = true,
               MaxAge = new TimeSpan(0),
               MustRevalidate = true
            };
            t.Result.Headers.Pragma.Add(new NameValueHeaderValue("no-cache"));
            t.Result.Content.Headers.Expires = DateTime.Parse("01 Jan 1990 00:00:00 GMT");

            return t.Result;
         }, cancellationToken);
   }
}

ApiController不在MVC3中,它在Web API中,直到.NET Core才与MVC合并。 - Jon Davis

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