Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to change ASP.NET MVC 3 route constraints such that they return 400 Bad Request with JSON bodies?

I am developing some REST resources using the ASP.NET MVC 3 platform. So far, its been great, I love the flexibility of MVC 3, and it is a breeze to build REST services with it. One area where I have been having a difficult time are the route constraints in Global.asax. For one, they never seem to work properly (including one ALWAYS returns 404, even if the input most definitely meets the requirements of the constraint...but thats another question).

Second, and more importantly, the result returned when a constraint fails is always an HTML page. Assuming the constraints work, having the result be HTML really throws a wrench in the mix when all of the consumers of these REST services will be accepting data types, such as application/json, text/xml, possibly bson, etc. I really need to be able to address errors in our clients directly, rather than simply blowing up and logging the html for sideband resolution.

Is it possible to change what gets returned in response to a route constraint? Is it possible to make whats returned dynamic, such that if the client issuing the request only accepts application/bson, we can generate an acceptable response, rather than simply generating a canned response of a single mime type?

like image 425
jrista Avatar asked Feb 29 '12 17:02

jrista


2 Answers

About returning a code error instead of going to a controller you have to implemet a custom RouteHandler. This link resumes all thing you can put the finger on ...and that you might modify this way. About "adapting" the return type...you can do this in the controller. It is enough to put som if and in some cases you return Json(...) and in other cases you return View or PartialView.

However it is nice to do this in a controller filter...!

I implemented a Control filter that allows the controller to negotiate the return type with the client. I is very simple...the client just declare the type that i would like to receive either in a route parameter (a piece of the url, or of the query string) or by posting a field that contains this info. The use is very simple...you rcontroller can return a View thai the "default" return type if no infos come from the client. Then the filter "change" automatically the result type before the View is invoked transformig it in what the client required. The possibilties handled by the filter are a view whose name is chosen by the client or Json

The code is here(It contains some controls on the "hint" provided by the client to prevent attacks by malicious users):

public class AcceptViewHintAttribute : ActionFilterAttribute
{
    private JsonRequestBehavior jsBehavior;
    public AcceptViewHintAttribute(JsonRequestBehavior jsBehavior = JsonRequestBehavior.DenyGet)
    {
        this.jsBehavior = jsBehavior;
    }
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        string hint = filterContext.RequestContext.HttpContext.Request.Params["ViewHint"];
        if (hint == null) hint = filterContext.RequestContext.RouteData.Values["ViewHint"] as string;
        if (!string.IsNullOrWhiteSpace(hint) && hint.Length<=100 && new Regex(@"^\w+$").IsMatch(hint) )
        {


                ViewResultBase res = filterContext.Result as ViewResultBase;
                if (res != null)
                {
                    if (hint == "json")
                    {
                        JsonResult jr = new JsonResult();
                        jr.Data = res.ViewData.Model;
                        jr.JsonRequestBehavior = jsBehavior;
                        filterContext.Result = jr;
                    }
                    else
                    {
                        res.ViewName = hint;
                    }
                }

        }
        base.OnActionExecuted(filterContext);
    }
}
like image 177
Francesco Abbruzzese Avatar answered Oct 09 '22 00:10

Francesco Abbruzzese


Errlusion might be of some help here.

You may be able to write some custom logic to check the HTTP Accept header and/or use [SomeContext].Request.IsAjaxRequest() to see if JSON or BSON would be appropriate to return -- or just return JSON or BSON for all types of requests if you prefer.

like image 44
kendaleiv Avatar answered Oct 08 '22 23:10

kendaleiv