I am having a problem binding a model from both custom headers and the request body at the same time.
This is my model:
public class TestModel
{
public int Id { get; set; }
public string Name { get; set; }
public HeaderModel HeaderModel { get; set; }
}
public class HeaderModel
{
public int Version { get; set; }
public string Test { get; set; }
}
I have a simple test page that posts the following:
$(function() {
var go = function() {
$.ajax({
type: 'POST',
url: '/api/values',
data: { id: 1, name: 'theValue2' },
headers: { HeaderModel: JSON.stringify({version: 1, test:"roar"}) }
}).always();
};
$('input').click(go);
});
I have created the following header value provider:
public class HeaderValueProvider<T> : IValueProvider where T : class
{
private readonly HttpRequestHeaders _headers;
public HeaderValueProvider(HttpRequestHeaders headers)
{
_headers = headers;
}
public bool ContainsPrefix(string prefix)
{
var test = typeof (T).Name == prefix;
return test;
}
public ValueProviderResult GetValue(string key)
{
if (typeof (T).Name == key)
{
IEnumerable<string> headerStrings;
_headers.TryGetValues(key, out headerStrings);
var strings = headerStrings.ToArray();
if (headerStrings != null && strings.Any())
{
var value = strings.First();
var obj = JsonConvert.DeserializeObject<T>(value,
new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
return new ValueProviderResult(obj, value, CultureInfo.InvariantCulture);
}
}
return null;
}
}
public class HeaderValueProviderFactory<T> : ValueProviderFactory where T : class
{
public override IValueProvider GetValueProvider(HttpActionContext actionContext)
{
var headers = actionContext.ControllerContext.Request.Headers;
return new HeaderValueProvider<T>(headers);
}
}
And it has been registered in the config:
config.Services.Add(typeof(ValueProviderFactory), new HeaderValueProviderFactory<HeaderModel>());
If I use my controller like the following I get my model bound, but not my header. It uses a media formatter:
public IHttpActionResult Post(TestModel model)
{
return Ok(model);
}
If I include the ModelBinder attribute I get the HeaderModel bound, but not the rest of the model from the request body:
public IHttpActionResult Post([ModelBinder]TestModel model)
{
return Ok(model);
}
What is the cleanest way to get both to work?