I'm hoping to get some advice about the best way to share a custom model-binder between MVC and WebAPI. The way I've done it, while functional, seems overly complex, and I'm fairly sure there must be a better way.
I have a hybrid application that's using MVC to serve up the application UI, and partial views for dynamic sections of the site, and API's serving the same models as JSON to be consumed by 3rd party apps. What I want is to be able to use the same code to filter my model lists for both Web API and MVC.
Currently I have a binder class that implements both Web.Mvc.IModelBinder (for MVC) and Http.ModelBinding.IModelBinder (for Web API). This class then defines the two BindModel functions for each of these interfaces...
Public Function BindModel(actionContext As Http.Controllers.HttpActionContext, bindingContext As Http.ModelBinding.ModelBindingContext) As Boolean Implements Http.ModelBinding.IModelBinder.BindModel
Dim request As System.Net.Http.HttpRequestMessage = actionContext.Request
Dim qs = request.GetQueryNameValuePairs.ToLookup(Function(x) x.Key.ToLower, Function(x) x.Value)
bindingContext.Model = GetFilter(qs)
Return True
End Function
Public Function BindModel(controllerContext As Web.Mvc.ControllerContext, bindingContext As Web.Mvc.ModelBindingContext) As Object Implements Web.Mvc.IModelBinder.BindModel
Dim request As HttpRequestBase = controllerContext.RequestContext.HttpContext.Request
Dim qs = request.QueryString
Return GetFilter(qs.ToLookup)
End Function
These functions basically extract from their respective Request collections an ILookup, so that I can then get the filtering parameters using a single function. The GetFilter function is defined as...
Public Function GetFilter(lookup As ILookup(Of String, String)) As MyCustomFilter
Dim filter As New MyCustomFilter
filter.Offset = ConvertToInteger(lookup("offset").FirstOrDefault())
filter.Count = ConvertToInteger(lookup("count").FirstOrDefault())
filter.Keyword = lookup("q").FirstOrDefault()
filter.Country = ConvertToInteger(lookup("country").FirstOrDefault())
filter.State = ConvertToInteger(lookup("state").FirstOrDefault())
'etc...
Return filter
End Function
To attach the binder for WebAPI I have to then create a BinderProvider class, like so...
Public Class MyCustomFilterBinderProvider
Inherits Http.ModelBinding.ModelBinderProvider
Public Overrides Function GetBinder(configuration As Http.HttpConfiguration, modelType As Type) As Http.ModelBinding.IModelBinder
Return New MyCustomFilterBinder
End Function
End Class
... and decorate the filter class to make it stick...
<System.Web.Http.ModelBinding.ModelBinderAttribute(GetType(MyCustomFilterBinderProvider))>
Public Class MyCustomFilter
To attach the custom binder to MVC, I add the following to my startup code...
ModelBinders.Binders.Add(GetType(MyNamespace.MyCustomFilter), New MyNamespace.MyCustomFilterBinder)
While this all works correctly, it seems overly complex. Am I on wrong track somehow? Is there a 'right way' to do this that I've missed?
Any suggestions would be most appreciated.