7

In a C# controller, I have a function defined with an optional parameter which is set to default to null (see code example below). The first time the page loads, the function is called and the filter is passed in as an initialized object, despite the default value being null. I would like it to be null the first time the page loads. Is there a way to do this?

public ActionResult MyControllerFunction(CustomFilterModel filter = null)
{
    if (filter == null)
         doSomething(); // We never make it inside this "if" statement.

    // Do other things...
}

This action is resolved by the following route definition:

routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Project", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );
yeapiekiyay
  • 113
  • 6
  • Are you calling it with an argument? You probably aren't call it in a way that allows the default parameter. – BradleyDotNET Jul 23 '14 at 19:46
  • @BradleyDotNET, TimSchemelter, it's a MVC action, the method is called by the MVC framework, not by user code – Thomas Levesque Jul 23 '14 at 19:49
  • 1
    What does your route definition look like? – adam0101 Jul 23 '14 at 19:51
  • @ThomasLevesque is right. It's a MVC action. So, it's called upon loading the page. I'm not sure where the CustomFilterModel object is getting initialized or how to stop it from doing so. – yeapiekiyay Jul 23 '14 at 19:52
  • A similar question: http://stackoverflow.com/questions/3863678/asp-net-mvc-controller-parameter-optional-i-e-indexint-id – GVashist Jul 23 '14 at 19:53
  • @adam0101 - I added the route into the original post for you to see, since code doesn't display well in comments. – yeapiekiyay Jul 23 '14 at 20:02
  • Have you tried using two different methods - one with no parameter and one with the CustomFilterModel parameter? What happens then? – Jay Otterbein Jul 23 '14 at 20:06
  • @JayOtterbein - I just defining two different methods as per your suggestion. It just bombs out in this case and doesn't end up calling either method. – yeapiekiyay Jul 23 '14 at 20:16
  • 2
    I don't see a very easy way to do this without a custom model binder. You can possibly accept a string, check if the string is null or empty, then deserialize it yourself. Or maybe there's some property that must always be there? Such as filter.Id? – Jay Otterbein Jul 23 '14 at 20:31
  • Can we see the code that you are using to call MyControllerFunction? – Seige Jul 23 '14 at 21:14

2 Answers2

5

The default model binder (DefaultModelBinder) will create an instance of CustomFilterModel and then attempt to fill the object with data from the request. Even if the default model binder finds no properties of your model in the request it will still return the empty model, hence you will never get a null object for your parameter. There seems to be nothing in the source [1] that will return a null model.

[1] https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/DefaultModelBinder.cs

0

Here is the replacement for DefaultModelBinder:

public class OptionalClassInstanceBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        bindingContext.FallbackToEmptyPrefix = false;
        return base.BindModel(controllerContext, bindingContext);
    }
}

[ModelBinder(typeof(OptionalClassInstanceBinder))]
public class CustomFilterModel
{
    ...
}

Beware though that with the binder in place you have to prefix the parameter name to any inner property, e.g. ?filter.range=1 instead of ?range=1.

Herman Kan
  • 1,873
  • 1
  • 20
  • 28