2016-07-24 2 views
10

Я преобразуя HttpContent в следующем DTO:HttpContent Заголовки несовместимого перечисление

public class ContentDto 
{ 
    public string ContentType {get; set;} 
    public string Headers {get; set; } 
    public object Data { get; set; } 

    public ContentDto(HttpContent content) 
    { 
      Headers = content.Headers.Flatten(); 
      // rest of the setup 
    } 
} 

И я бег несколько модульных тестов на нем:

[Fact] 
public void CanBuild() 
{ 
    var content = new StringContent("some json", Enconding.UTF8, "application/json"); 
    var dto = new ContentDto(content); 

    var contentHeaders = content.Headers.Flatten(); 

    Assert.Equal(contentHeaders, dto.Headers); 
} 

И что тест не пройден, так как заголовок Content-Length не является захвачен на моем д. Однако, если я это сделаю:

[Fact] 
public void CanBuild() 
{ 
    var content = new StringContent("some json", Enconding.UTF8, "application/json"); 

    var contentHeaders = content.Headers.Flatten(); 

    var dto = new ContentDto(content); 

    Assert.Equal(contentHeaders, dto.Headers); 
} 

Тест проходит, и все заголовки захватываются. Еще я попытался это:

[Fact] 
public void CanBuild() 
{ 
    var content = new StringContent("some json", Enconding.UTF8, "application/json"); 

    var dto = new ContentDto(content); 

    var contentHeaders = content.Headers.Flatten(); 

    var dto1 = new ContentDto(content); 

    Assert.Equal(contentHeaders, dto.Headers);     
    Assert.Equal(contentHeaders, dto1.Headers); 
} 

и он терпит неудачу, поскольку dto не имеет заголовок Content-Length, но dto1 делает. Я даже пытался получать заголовки внутри на заводе, как метод, как это:

public static ContentDto FromContent<T>(T content) where T : HttpContent 
{ 
     // same as the constructor 
} 

, чтобы увидеть, если есть что-то особенное о StringContent класса в отношении к Content-Length заголовков, но это не имело никакого значения, независимо от того, если бы я использовал конструктор (который использует базовый класс HttpContent) или общий метод FromContent (с использованием фактического StringContent в этом случае), результат был таким же.

Так что мои вопросы:

Это предполагаемое поведение HttpContent.Headers?
Есть ли некоторые заголовки, специфичные для фактического HttpContent?
Что мне здесь не хватает?

Примечание: Это код для метода Flatten расширения:

public static string Flatten(this HttpHeaders headers) 
{ 
     var data = headers.ToDictionary(h => h.Key, h => string.Join("; ", h.Value)) 
         .Select(kvp => $"{kvp.Key}: {kvp.Value}"); 

     return string.Join(Environment.NewLine, data) 
} 
+0

Порядок элементов в ToDictionary не гарантируется, делает ли это тот же результат 'headers.ToDictionary (h => h.Key, h => string.Join ("; ", h.Value)) .Orderby (x => x.Key) .Выберите (kvp => $ "{kvp.Key}: {kvp.Value}") '? –

+0

@AkashKava вопрос не о заказе. Проблема заключается в заголовках 'Content-Length', которые не всегда существуют. – Luiso

+0

@ Luiso, можете ли вы показать [mcve], чтобы ваша проблема могла быть точно реплицирована. Это поможет найти решение вашей проблемы. – Nkosi

ответ

4

Ваш пример неполный. Я только смог воссоздать вашу проблему, когда я обратился к свойству ContentLength перед вызовом метода расширения. Где-то в вашем коде (скорее всего, // остальной настройке) вы прямо или косвенно называете это свойство, которое, скорее всего, следует за ленивым шаблоном загрузки, а затем включается в заголовок, когда вы вызываете ваш метод расширения, и он включен в построенную строку. Они не совпадают, потому что вы генерируете свою ручную строку перед доступом к свойству длины содержимого.

В исходном коде для HttpContentHeaders.ContentLength

public long? ContentLength 
{ 
    get 
    { 
     // 'Content-Length' can only hold one value. So either we get 'null' back or a boxed long value. 
     object storedValue = GetParsedValues(HttpKnownHeaderNames.ContentLength); 

     // Only try to calculate the length if the user didn't set the value explicitly using the setter. 
     if (!_contentLengthSet && (storedValue == null)) 
     { 
      // If we don't have a value for Content-Length in the store, try to let the content calculate 
      // it's length. If the content object is able to calculate the length, we'll store it in the 
      // store. 
      long? calculatedLength = _calculateLengthFunc(); 

      if (calculatedLength != null) 
      { 
       SetParsedValue(HttpKnownHeaderNames.ContentLength, (object)calculatedLength.Value); 
      } 

      return calculatedLength; 
     } 

     if (storedValue == null) 
     { 
      return null; 
     } 
     else 
     { 
      return (long)storedValue; 
     } 
    } 
    set 
    { 
     SetOrRemoveParsedValue(HttpKnownHeaderNames.ContentLength, value); // box long value 
     _contentLengthSet = true; 
    } 
} 

вы можете увидеть, что если вы не в явном виде установить длину содержимого, то это добавит его (ленивых нагрузки) к коллекторам при первой попытке доступа к нему.

Это подтверждает мою первоначальную теорию о том, что она добавляется после того, как вы сгенерировали/сгладили строку и затем получили доступ к свойству и объяснили несогласованное перечисление.

+0

Я просто дважды проверял свой код, и я не вижу, где я мог бы получить доступ к свойству Content-Length, по крайней мере, не очевидному, но я мог бы просто пропустить его. Большое спасибо – Luiso

+1

Я заметил, что в вашем 'ContentDto' есть свойство' Data'. как и где вы заполняете это свойство. Если вы читаете поток или строку содержимого htto, исходный код показывает, что перед чтением потока он вызывает длину содержимого, чтобы узнать, сколько читать. Это может быть ваш преступник. – Nkosi

+0

Да, вы правы, это именно то, что произошло. Вы очень помогли, спасибо вам большое – Luiso

0

кажется, что класс HttpContent имеет довольно странное поведение со свойствами заголовков. Как бы то ни было, длина контента вычисляется, как указано here. Это не касается конкретной проблемы, но вы можете сделать тест с новым объектом httpContent, аналогичным исходному. Я уверен, что вы сможете получить длину контента без проблем.

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