DontVoteMeDown
DontVoteMeDown

Reputation: 21465

Custom model binding for generic type

I have a ASP.Net MVC 4 app where I'm trying to create a custom model binder. The model it has to deal is this:

public class CompressedJsonViewModel<T>
    where T : ViewModel

To receive it as a param in the Action as:

public ActionResult ImportData(CompressedJsonViewModel<ImportDataViewModel> input)

And (for now) I have a simple binder, which I will improve when the config is fine:

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

The problem starts here. If the CompressedJsonViewModel is not set as generic, the below assignment to model binders works:

binders.Add(typeof(CompressedJsonViewModel), new CompressedJsonModelBinder());

But when I add the generic T to the class signarture, the BindModel method is not called anymore. I can't figure out how to set the right binding. I tried two things:

  1. Binding as

    binders.Add(typeof(CompressedJsonViewModel<>), new CompressedJsonModelBinder());
    
  2. Creating an interface as CompressedJsonViewModel : ICompressedJsonViewModel and set the binding to it as

    binders.Add(typeof(ICompressedJsonViewModel), new CompressedJsonModelBinder());
    

Both didn't works. Found this but it seems somewhat overkill to me. I would like to avoid using something like [ModelBinder(typeof(CompressedJsonModelBinder))] in the parameters, I would like to make something more automatic than that.

Upvotes: 2

Views: 1133

Answers (1)

Pedro
Pedro

Reputation: 2310

Use a custom ModelBinderProvider:

public class CompressedJsonBinderProvider : IModelBinderProvider
{
   public IModelBinder GetBinder(Type modelType)
   {
       if(!modelType.IsGenericType)
            return null;

       var genericType =  modelType.GetGenericTypeDefinition();

       if(genericType == typeof(CompressedJsonViewModel<>))
           return new CompressedJsonModelBinder();

       return null;        
   }
}

By the way, this shows you the mechanics, but I'd also cache te=he type check in to avoid having to do the type reflection on every single request.

Upvotes: 1

Related Questions