ASP.NET MVC 3: Creating HttpStatusCodeResult with view based body
My last posts described new action results in ASP.NET MVC 3 – HttpNotFoundResult and HttpStatusCodeResult. Unfortunately these result have no body to send to client but there are times we need it to inform our visitor about problems the way that we don’t go out of information context where visitor is. In this example I will show you how to write your own HttpStatusCodeResult that has also body.
We cannot use HttpStatusCodeResult because it doesn’t contain information about current view and there is no way how to attach views to this action result. Instead, I wrote my own implementation of HttpStatusCodeResult that extends ViewResult class and has therefore support for views. This is important thing because body of response is defined same way as other views in ASP.NET MVC framework.
Okay, here is my HttpStatusCodeWithBodyResult class in its very first form.
public class HttpStatusCodeWithBodyResult : ViewResult
{
private int _statusCode;
private string _description;
public HttpStatusCodeWithBodyResult(int statusCode,
string description = null)
: this(null, statusCode, description)
{
}
public HttpStatusCodeWithBodyResult(string viewName, int statusCode,
string description = null)
{
_statusCode = statusCode;
_description = description;
ViewName = viewName;
}
public override void ExecuteResult(ControllerContext context)
{
var httpContext = context.HttpContext;
var response = httpContext.Response;
response.StatusCode = _statusCode;
response.StatusDescription = _description;
base.ExecuteResult(context);
}
}
And here is how you can use it in you controller methods. The examples are given for 404 – Not Found and 410 – Gone responses.
public ActionResult NotFound()
{
var msg = "I cannot find this resource!";
// there must be view called NotFound.aspx or NotFound.cshtml
var result = new HttpStatusCodeResultWithBody("NotFound", 404, msg);
return result;
}
public ActionResult GoneForever()
{
var msg = "This resource is dead and buried!";
// there must be view called GoneForever.aspx or GoneForever.cshtml
var result = new HttpStatusCodeResultWithBody(410, msg);
return result;
}
You can read more about HttpNotFoundResult class from my posting ASP.NET MVC 3: Using HttpNotFoundResult action result and about HttpStatusCodeResult from my posting ASP.NET MVC 3: Using HttpStatusCodeResult.
Conclusion
In this posting I showed you how to create action result that works like HttpSthatusCodeResult but supports also body for result returned to browser. This way we can tell to both technical clients (browsers, search engine spiders etc) and visitors that there was problem and what one or another of them has to do now. Consider it also as good SEO and usability practices.
Any ideas on returning a 401 without ASP taking over and trying to redirect to login page? I simply want to return a view with a content-type of application/xml and a statusCode of 401. There seems to be a hole here.
Why doesn’t HttpStatusCodeResult include this ability? Is there some rationale for this or is it just not fully baked?
Thanks for question, ChrisLamont. MVC framework just changes status code and let’s lower levels to manage the error. In my solution here, by example, Application_Error is not triggered and settings in web.config are ignored.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var user = filterContext.HttpContext.User;
if (user.Identity.IsAuthenticated)
{
filterContext.Result = new RedirectResult(“Your Not Authorized page or ~/{controller}/{action}”);
}
else
{ base.HandleUnauthorizedRequest(filterContext);
}
}
}