title: How to: Parameter binding from multiple sources
body: <p>Currently I'm trying to create a web api based on asp.net core 2.0 and I'd like to create a nested route. In case of a put request it sends a part of the information in the route and another part in the body.</p>
  <h3>Requirements</h3>
  <p>The desired url to call would be</p>
  <pre><code>https://localhost/api/v1/master/42/details
  </code></pre>
  <p>If we'd like to create a new detail below our <em>master 42</em> I would expect to send the data of the details in the body while the id of the master comes out of the route.</p>
  <pre><code>curl -X POST --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  -d '{ \ 
     &quot;name&quot;: &quot;My detail name&quot;, \ 
     &quot;description&quot;: &quot;Just some kind of information&quot; \ 
   }' 'https://localhost/api/v1/master/42/details'
  </code></pre>
  <p>The outcoming response of the request would be</p>
  <pre><code>{
      &quot;name&quot;: &quot;My detail name&quot;,
      &quot;description&quot;: &quot;Just some kind of information&quot;,
      &quot;masterId&quot;: 42,
      &quot;id&quot;: 47
  }
  </code></pre>
  <p>and a location url within the response header like</p>
  <pre><code>{
      &quot;location&quot;: &quot;https://localhost/api/v1/master/42/details/47
  }
  </code></pre>
  <h3>Work done so far</h3>
  <p>To get this to work I created this controller:</p>
  <pre><code>[Produces(&quot;application/json&quot;)]
  [Route(&quot;api/v1/master/{masterId:int}/details&quot;)]
  public class MasterController : Controller
  {
      [HttpPost]
      [Produces(typeof(DetailsResponse))]
      public async Task&lt;IActionResult&gt; Post([FromBody, FromRoute]DetailCreateRequest request)
      {
          if(!ModelState.IsValid)
              return BadRequest(ModelState);
  
          var response = await Do.Process(request);
  
          return CreatedAtAction(nameof(Get), new { id = response.Id }, response);
      }
  }
  </code></pre>
  <p>Which uses these classes:</p>
  <pre><code>public class DetailCreateRequest
  {
      public int MasterId { get; set; }
      public string Name { get; set; }
      public string Description { get; set; }
  }
  
  public class DetailResponse
  {
      public int Id { get; set; }
      public int MasterId { get; set; }
      public string Name { get; set; }
      public string Description { get; set; }
  }
  </code></pre>
  <h3>The problem</h3>
  <p>So far most of the stuff works as expected. The only thing that really doesn't work is merging the MasterId from the route into the <code>DetailCreateRequest</code> that comes from the body.</p>
  <h3>First try: Use two attributes on the parameter</h3>
  <p>I tried to combine these two things by this action call:</p>
  <pre><code>public async Task&lt;IActionResult&gt; Post([FromBody, FromRoute]DetailCreateRequest request)
  </code></pre>
  <p>But the incoming object only had a <code>MasterId</code> of zero. If I change the order of the two attributes, then only the id from the route will be taken and all values within the body are ignored (so seems to be first attribute wins).</p>
  <h3>Second try: Use two different parameters in action</h3>
  <p>Another approach that I tried was this action call:</p>
  <pre><code>public async Task&lt;IActionResult&gt; Post([FromRoute]int masterId, [FromBody]DetailCreateRequest request)
  </code></pre>
  <p>In the first spot this looks okay, cause now I have both values within the controller action. But my big problem with this approach is the model validation. As you can see in the above code I check <code>ModelState.IsValid</code> which was filled through some checks from <code>FluentValidation</code>, but these checks can't be really done, cause the object wasn't build up correctly due to the missing master id.</p>
  <h3>(Not-working) Idea: Create own attribute with merge parameters</h3>
  <p>Tried to implement something like this:</p>
  <pre><code>public async Task&lt;IActionResult&gt; Post([FromMultiple(Merge.FromBody, Merge.FromRoute)]DetailCreateRequest request)
  </code></pre>
  <p>If we already would have something like this, that would be great. The order of the arguments within the attribute would give out the order in which the merge (and possible overwrites) would happen.</p>
  <p>I already started with implementing this attribute and creating the skeleton for the needed <code>IValueProvider</code> and <code>IValueProviderFactory</code>. But it seems to be a quite lot of work. Especially finding all the nifty details to make this work seamlessly with the whole pipeline of asp.net core and other libraries I'm using (like swagger through swashbuckle).</p>
  <p>So my question would be, if there already exists some mechanism within asp.net core to achieve such a merge or if anybody is aware about an already existing solution or about a good example on how to implement such a beast.</p>
  <h3>Solution so far: Custom ModelBinder</h3>
  <p>After getting the answer from <a href="https://stackoverflow.com/a/46218076/1838048">Merchezatter</a> I look into how to create a <a href="https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding" rel="nofollow noreferrer">custom model binder</a> and came up with this implementation:</p>
  <pre><code>public class MergeBodyAndValueProviderBinder : IModelBinder
  {
      public Task BindModelAsync(ModelBindingContext bindingContext)
      {
          if (bindingContext == null)
              throw new ArgumentNullException(nameof(bindingContext));
  
          var body = bindingContext.HttpContext.Request.Body;
          var type = bindingContext.ModelMetadata.ModelType;
          var instance = TryCreateInstanceFromBody(body, type, out bool instanceChanged);
          var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
          var setters = type.GetProperties(bindingFlags).Where(property =&gt; property.CanWrite);
  
          foreach (var setter in setters)
          {
              var result = bindingContext.ValueProvider.GetValue(setter.Name);
  
              if (result != ValueProviderResult.None)
              {
                  try
                  {
                      var value = Convert.ChangeType(result.FirstValue, setter.PropertyType);
                      setter.SetMethod.Invoke(instance, new[] { value });
                      instanceChanged = true;
                  }
                  catch
                  { }
              }
          }
  
          if (instanceChanged)
              bindingContext.Result = ModelBindingResult.Success(instance);
  
          return Task.CompletedTask;
      }
  
      private static object TryCreateInstanceFromBody(Stream body, Type type, out bool instanceChanged)
      {
          try
          {
              using (var reader = new StreamReader(body, Encoding.UTF8, false, 1024, true))
              {
                  var data = reader.ReadToEnd();
                  var instance = JsonConvert.DeserializeObject(data, type);
                  instanceChanged = true;
                  return instance;
              }
          }
          catch
          {
              instanceChanged = false;
              return Activator.CreateInstance(type);
          }
      }
  }
  </code></pre>
  <p>It tries to deserialize the body into the desired object type and afterwards tries to apply further values from the available value providers. To get this model binder to work I had to decorate the destination class with the ModelBinderAttribute and made the MasterId internal, so that swagger doesn't announce it and JsonConvert doesn't deserialize it:</p>
  <pre><code>[ModelBinder(BinderType = typeof(MergeBodyAndValueProviderBinder))]
  public class DetailCreateRequest
  {
      internal int MasterId { get; set; }
      public string Name { get; set; }
      public string Description { get; set; }
  }
  </code></pre>
  <p>Within my controller the action method parameters are still containing the <code>[FromBody]</code> flag, cause it is used by swagger to announce on how the method can be called, but it never will be called, cause my model binder has a higher priority.</p>
  <pre><code>public async Task&lt;IActionResult&gt; Post([FromBody]DetailCreateRequest request)
  </code></pre>
  <p>So it is not perfect, but works good so far.</p>