title: Passing arguments to Web API model binder
body: <p>I am trying to create Web API model binder that will bind URL parameters sent by a grid component of a javascript framework.
  Grid sends URL parameters indicating standard page, pageSize, and JSON formatted sorters, filters, and groupers.
  The URL string looks like this:</p>
  
  <pre><code>http://localhost/api/inventory?page=1&amp;start=0&amp;limit=10sort=[{"property":"partName","direction":"desc"},{"property":"partStatus","direction":"asc"}]&amp;group=[{"property":"count","direction":"asc"}]
  </code></pre>
  
  <p>The model in question is Inventory which has simple, Count (int) property and a reference, Part (Part) peoperty (which in turn has Name, Status).
  The view model/dto is flattened (InventoryViewModel .Count, .PartName, .PartStatus, etc, etc.)
  I use <a href="http://nuget.org/packages/DynamicQuery" rel="nofollow">Dynamic Expression Api</a> then to query domain model, map the result to view model and send it back as JSON.
  During model binding I need to build the expressions by examining model and view model that are being used.</p>
  
  <p><strong>In order to keep model binder reusable, how can I pass/specify model and view model types being used?</strong>
  I need this in order to build valid sort,filter,and grouping expsessions
  Note: I don't want to pass these as part of the grid url params!</p>
  
  <p>One idea I had was to make StoreRequest generic (e.g. StoreRequest) but I am not sure if or how model binder would work.</p>
  
  <p>Sample API Controller</p>
  
  <pre><code>// 1. model binder is used to transform URL params into StoreRequest. Is there a way to "pass" types of model &amp; view model to it?
      public HttpResponseMessage Get(StoreRequest storeRequest)
      {
              int total;
              // 2. domain entites are then queried using StoreRequest properties and Dynamic Expression API (e.g. "Order By Part.Name DESC, Part.Status ASC")
              var inventoryItems = _inventoryService.GetAll(storeRequest.Page, out total, storeRequest.PageSize, storeRequest.SortExpression); 
              // 3. model is then mapped to view model/dto
              var inventoryDto = _mapper.MapToDto(inventoryItems);
              // 4. response is created and view model is wrapped into grid friendly JSON
              var response = Request.CreateResponse(HttpStatusCode.OK, inventoryDto.ToGridResult(total));
              response.Content.Headers.Expires = DateTimeOffset.UtcNow.AddMinutes(5);
              return response;
      }
  </code></pre>
  
  <p>StoreRequestModelBinder</p>
  
  <pre><code>public class StoreRequestModelBinder : IModelBinder
  {
      private static readonly ILog Logger = LogManager.GetCurrentClassLogger();
  
      public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
      {
          Logger.Debug(m =&gt; m("Testing model binder for type: {0}", bindingContext.ModelType));
          if (bindingContext.ModelType != typeof(StoreRequest))
          {
              return false;
          }
          var storeRequest = new StoreRequest();
          // ----------------------------------------------------------------
          int page;
          if (TryGetValue(bindingContext, StoreRequest.PageParameter, out page))
          {
              storeRequest.Page = page;
          }
          // ----------------------------------------------------------------
          int pageSize;
          if (TryGetValue(bindingContext, StoreRequest.PageSizeParameter, out pageSize))
          {
              storeRequest.PageSize = pageSize;
          }
          // ----------------------------------------------------------------
          string sort;
          if (TryGetValue(bindingContext, StoreRequest.SortParameter, out sort))
          {
              try
              {
                  storeRequest.Sorters = JsonConvert.DeserializeObject&lt;List&lt;Sorter&gt;&gt;(sort);
                  // TODO: build sort expression using model and viewModel types
              } 
              catch(Exception e)
              {
                 Logger.Warn(m=&gt;m("Unable to parse sort parameter: \"{0}\"", sort), e);
              }
          }
          // ----------------------------------------------------------------
          bindingContext.Model = storeRequest;
          return true;
      }
  
      private bool TryGetValue&lt;T&gt;(ModelBindingContext bindingContext, string key, out T result)
      {
          var valueProviderResult = bindingContext.ValueProvider.GetValue(key);
          if (valueProviderResult == null)
          {
              result = default(T);
              return false;
          }
          result = (T)valueProviderResult.ConvertTo(typeof(T));
          return true;
      }
  }
  </code></pre>