3

我在同时从自定义标头和请求正文绑定模型时遇到问题。

这是我的模型:

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>());

如果我像下面这样使用我的控制器,我会得到我的模型绑定,但不是我的标题。它使用媒体格式化程序

public IHttpActionResult Post(TestModel model)
{
    return Ok(model);
}

如果我包含 ModelBinder 属性,我会得到 HeaderModel 绑定,但不是来自请求正文的模型的其余部分:

public IHttpActionResult Post([ModelBinder]TestModel model)
{
    return Ok(model);
}

让两者都工作的最干净的方法是什么?

4

2 回答 2

3

默认情况下, Web API 使用媒体格式化程序绑定一个复杂的类型,例如TestModel来自 body。通过指定ModelBinder,您要求 Web API 使用模型绑定,它适用于 URI、查询字符串,但由于您有一个值提供者,它也从标头绑定。但基本上,除非您编写自定义参数绑定器,否则您将无法TestModel从正文和其他地方(如标题、查询字符串等)创建模型。看看这个例子。

于 2013-12-10T11:58:22.127 回答
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; }
}

现在我的帖子中有两个参数。

public IHttpActionResult Post(HeaderModel headerModel, TestModel model)
{
    return Ok();
}

我不会称这是一个完美的解决方案,但它运作良好。

于 2013-12-16T20:10:19.697 回答