21

I've created a custom MVC Model Binder which gets called for every HttpPost that comes into the server. But does not get called for HttpGet requests.

  • Should my custom model binder get called during a GET? If so, what did I miss?
  • If not, How can I write custom code handling the QueryString from a GET Request?

Here's my implementation...

public class CustomModelBinder : DefaultModelBinder
{
   public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
   {
      // This only gets called for POST requests. But I need this code for GET requests.
   }
}

Global.asax

protected void Application_Start()
{
   ModelBinders.Binders.DefaultBinder = new CustomModelBinder();
   //...
}

I've looked into these solutions, but they don't quite work for what I'm looking for:

  • Persisting complex types via TempData
  • Using the default binder to build up complex types (?Name=John&Surname=Doe)

Remark on answer

Thanks to @Felipe for the help. Just in case someone struggles with the same, I learnt:

  • The custom model binder CAN be used for GET requests
  • You CAN use DefaultModelBinder class
  • My snag was that the action method MUST have a parameter (otherwise the model binder is skipped for GET Requests, which makes sense when you think about it)
Community
  • 1
  • 1
Niels Filter
  • 4,430
  • 3
  • 28
  • 42
  • you can use [OnActionExecuting](https://msdn.microsoft.com/en-us/library/dd493080%28v=vs.98%29.aspx) to filter each request and in that method you can get query string using `Request`. – J Santosh Sep 03 '15 at 11:33
  • @JSantosh, let's say I did that and got hold of my `QueryString` in the `OnActionExecuting`. I wouldn't be able to translate the QueryString into an object and pass it as a parameter to the action method right? Which leaves me with the same predicament. – Niels Filter Sep 03 '15 at 11:38
  • In post request you get data as object that is automatically parsed into respective model, but in get you get data as string , i am not sure that you can achieve this . and good question :) – J Santosh Sep 03 '15 at 11:40
  • Thanks @JSantosh :) the code I have works in translating the QueryString from a string to my custom object, that's fine. It's just a matter of now getting that built up object to the Action parameter... – Niels Filter Sep 03 '15 at 11:47

1 Answers1

21

Let's supose you have your own type you want to bind.

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    // other properties you need
}

You can create a custom model bind for this specific type, inherithing from DefaultModelBinder, for sample:

public class PersonModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var request = controllerContext.HttpContext.Request;

        int id = Convert.ToInt32(request.QueryString["id"]);
        string name = request.QueryString["name"];
        int age = Convert.ToInt32(request.QueryString["age"]);
        // other properties

        return new Person { Id = id, Name = name, Age = age };
    }
}

In the Global.asax in the Application_Start event, you can registry this model bind, for sample:

// for Person type, bind with the PersonModelBinder
ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder());

In the BindModel method from the PersonModelBinder, make sure you have all parameters in the querystring and give them the ideal treatment.

Since you have this action method:

public ActionResult Test(Person person)
{
  // process...
}

You can access this action with an url something like this:

Test?id=7&name=Niels&age=25
Felipe Oriani
  • 37,948
  • 19
  • 131
  • 194
  • Thanks for the detailed answer. I am using `DefaultModelBinder` (see my question) and it doesn't seem to get hit during a **GET** request, only for **POST**. Does your `BindModel` method get called for an `HttpGet` as well? – Niels Filter Sep 03 '15 at 11:44
  • I've tested here and in the `Test` action method I'v got the `person` parameter filled ok. Make sure you have registred the custom bind for the your custom type. Remember you also need to read from `request.QueryString`. – Felipe Oriani Sep 03 '15 at 11:46
  • Fantastic, then I've missed something on my side. Let me play around and get back to you. Thanks. – Niels Filter Sep 03 '15 at 11:48
  • Thanks Felipe, it's working now. Turns out if you use do a `Get` request to `Action` method without any parameters, it doesn't go via the model binder (why would it need to I guess) – Niels Filter Sep 03 '15 at 12:08
  • 1
    @Niels Filter thank you for your point " Turns out if you use do a Get request to Action method without any parameters, it doesn't go via the model binder ". That parameter seems to be needed to trigger the MVC model binding even though it is a dummy parameter. – Thomas.Benz Nov 27 '17 at 16:18
  • In my project `IModelBinder` and `DafaultModelBinder` are ambiguous between `System.Web.Http.ModelBinding ` & `System.Web.Mvc` & `System.Web.ModelBinging` which one is correct for asp.net mvc? – Hamed Zakery Miab May 28 '18 at 05:11