Search code examples
c#asp.net-mvcasp.net-mvc-routingmodel-binding

What's the WebApi [FromUri] equivalent in ASP.NET MVC?


In WebApi I can decorate a parameter on a controller action with [FromUri] to have the components of the URI 'deserialized', if you will, into a POCO model; aka model-binding.

Despite using MVC since 2.0, I've never used it for websites (I don't know why). What's the equivalent of it in ASP.NET MVC 5?

The attribute doesn't seem to be recognised in the IDE unless I need to reference a library.

I'd like ~/thing/2014/9 to bind to the model below:

public class WhateverModel
{
    public int Year { get; set; }
    public int Month { get; set; }
}

Thanks

Update

In the other question (link above), the OP says:

However, switch this to plain MVC not WebApi and the default model binder breaks down and cannot bind the properties on objects in the nested array

Which implies that he's using the attribute from the WebApi. I guess. I don't have those references, because I'm in MVC, so is (ab)using WebApi's version the accepted way to do this in MVC?

Update 2

In the answer to that question is:

You need to construct your query string respecting MVC model binder naming conventions.

Additionally [FromUri] attribute in your example action is completely ignored, since it's not known to MVC DefaultModelBinder

So I'm still left not knowing what to do or what on Earth the OP was even talking about in that question, if he was getting some success with the wrong attribute.

I guess I'm hoping for a clear answer and not the mud of that other question.


Solution

  • It'll Just Work™:

    [HttpGet]
    public ActionResult Thing(WhateverModel model)
    {
        // use model
        return View();
    }
    

    At least, when using the URL /thing?Year=2014&Month=9.

    The problem is your routing. The URL /thing/2014/9 won't map using MVC's default route, as that is /{controller}/{action}/{id}, where {id} is an optional int.

    The easiest would be to use attribute routing:

    [HttpGet]
    [Route("/thing/{Year}/{Month}"]
    public ActionResult Thing(WhateverModel model)
    {
        // use model
        return View();
    }
    

    This will map the URL to your model.