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

Если я использую мой контроллер, как следующий я получить мою модель узником, но не мой заголовок. Он использует media formatter:

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

Если я включаю ModelBinder атрибут я получаю HeaderModel связанный, но не остальные модели из тела запроса:

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

Что такое чистый способ заставить оба работать?

ответ

2

Это было очень легко решить. Как правильно сказано Бадри, вы не можете использовать тело запроса и заголовки для той же привязки. Однако вы можете иметь два параметра и привязывать их отдельно.

Я оставил 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(); 
} 

Я бы не назвал это идеальное решение, но она хорошо работает.

2

Веб-интерфейс связывает сложный тип, например TestModel, с телом по умолчанию с использованием media formatters. Указав ModelBinder, вы попросите Web API использовать привязку к модели, которая работает с URI, строка запроса, но поскольку у вас есть поставщик значений, она также является обязательной для заголовка. Но в принципе вы не сможете получить модель TestModel, созданную как из тела, так и из других мест, таких как заголовок, строка запроса и т. Д., Если вы не пишете настраиваемое связующее значение параметра. Проверьте пример this.

+0

Спасибо, что нашли время, чтобы посмотреть на это. То, что вы говорите, правильно. Однако я нашел очень простой способ решить проблему. См. Отмеченный ответ. – TheGwa

Смежные вопросы