如何结束响应并返回HTTP状态码404?

10
我正在使用Castle Windsor工厂根据请求的URL实例化一个对象。
类似这样:
    public FooViewModel Get()
    {
        if (HttpContext.Current == null)
        {
            return new FooViewModel();
        }

        var currentContext = new HttpContextWrapper(HttpContext.Current);

        // resolve actual view model.

在某些情况下,我实际上想返回一个404状态码并停止请求,目前的代码如下:

        throw new HttpException(404, "HTTP/1.1 404 Not Found");
        currentContext.Response.End();

然而请求并没有结束,它仍然命中了Action并尝试解析视图?

我的控制器看起来类似于这样:

public class HomeController : Controller
{
    public FooViewModel Foo { get; set; }

    public ActionResult Index()
    {
        ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";

        return View();
    }

我考虑的是否有误?或者说有没有一种方法可以实现这个目标?

我想到的替代方法是,在操作中设置一个属性来检查Foo属性的状态?

2个回答

12

我认为使用操作筛选器的方法可以实现您想要的:

public class RequiresModelAttribute : ActionFilterAttribute
{
    private readonly string _modelName;

    public RequiresModelAttribute(string modelName)
    {
        _modelName = modelName;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var property = filterContext.Controller.GetType().GetProperty(_modelName);
        var model = property.GetValue(filterContext.Controller);
        if (model == null)
        {
            filterContext.Result = new HttpStatusCodeResult(404);
        }
    }
}

然后,在你的控制器中,你可以这样做:

public class HomeController : Controller
{
    public FooViewModel Foo { get; set; }

    [RequiresModel("Foo")]
    public ActionResult Index()
    {
        ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";

        return View();
    }
}

编辑:也许可以使用全局过滤器来处理任何抛出的HttpExceptions?

public class HonorHttpExceptionAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var httpException = filterContext.HttpContext.AllErrors.FirstOrDefault(x => x is HttpException) as HttpException;
        if (httpException != null)
        {
            filterContext.Result = new HttpStatusCodeResult(httpException.GetHttpCode());
        }
    }
}

然后在 Global.asax 中:

  public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  {
      filters.Add(new HandleErrorAttribute());
      filters.Add(new HonorHttpExceptionAttribute());
  }

是的,我已经改成这样了,让我们看看是否有其他建议。 - shenku
@shenku 我已经更新了我的回复,提供了另一种方法,也许在你的情况下会更好用? - armen.shimoon

2
另一种选择是在控制器上重写OnException方法。
 public ActionResult Index()
    {
        ViewBag.Message = "Welcome to ASP.NET MVC!";
        Get();
        return View();
    }

    public int Get()
    {
        throw new HttpException(404, "HTTP/1.1 404 Not Found");
        // we don't need end the response here, we need go to result step
        // currentContext.Response.End();

    }

    protected override void OnException(ExceptionContext filterContext)
    {
        base.OnException(filterContext);
        if (filterContext.Exception is HttpException)
        {
            filterContext.Result = this.HttpNotFound(filterContext.Exception.Message);
        }
    }

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