我在同时从自定义标头和请求主体绑定模型时遇到问题。
这是我的模特:
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; }
}
我有一个简单的测试页面,发布以下内容:
$(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);
});
我创建了以下标头值提供程序:
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);
}
}
它已在配置中注册:
config.Services.Add(typeof(ValueProviderFactory), new HeaderValueProviderFactory<HeaderModel>());
如果我使用我的控制器,如下所示,我的模型绑定,但不是我的标题。它使用media formatter:
public IHttpActionResult Post(TestModel model)
{
return Ok(model);
}
如果我包含ModelBinder属性,我会绑定HeaderModel,但不会从请求正文中获取模型的其余部分:
public IHttpActionResult Post([ModelBinder]TestModel model)
{
return Ok(model);
}
让两者兼得的最简洁方法是什么?
答案 0 :(得分:3)
Web API默认使用媒体格式化程序从正文绑定复杂类型,如TestModel
。通过指定ModelBinder
,您要求Web API使用模型绑定,该模型绑定适用于URI,查询字符串,但由于您具有值提供程序,因此它也是从标头绑定的。但基本上,除非您编写自定义参数绑定器,否则您将无法从主体和其他位置(如标题,查询字符串等)创建TestModel
模型。请查看this以获取示例。
答案 1 :(得分:2)
这令人沮丧地轻松解决。正如Badri正确陈述的那样,您不能将请求正文和标题用于相同的绑定。但是,您可以使用两个参数并将它们分开绑定。
我已将HeaderModel作为其自己的独立类,并为其添加了ModelBinder属性。
public class TestModel
{
public int Id { get; set; }
public string Name { get; set; }
}
[ModelBinder]
public class HeaderModel
{
public int Version { get; set; }
public string Test { get; set; }
}
我现在在Post中有两个参数。
public IHttpActionResult Post(HeaderModel headerModel, TestModel model)
{
return Ok();
}
我不认为这是一个完美的解决方案,但它运作良好。