2016-07-24 10 views
10

jestem przekształcając HttpContent w następującym DTO:HttpContent Główki niespójne wyliczenie

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 
    } 
} 

I używam kilka testów jednostkowych na nim:

[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); 
} 

I że test nie powiedzie się, ponieważ nagłówek Content-Length nie jest złapany na moim dto. Jeśli jednak to zrobię:

[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); 
} 

Test przechodzi i wszystkie nagłówki są przechwytywane. Jeszcze bardziej ja też próbowałem to:

[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); 
} 

i to nie od dto nie posiada nagłówka Content-Length, ale dto1 robi. Próbowałem nawet coraz nagłówki wewnątrz Fabrycznie jak sposobu jak ten:

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

aby zobaczyć, czy jest coś specjalnego w klasie StringContent dotyczących nagłówków Content-Length, ale to nie miało znaczenia, nie ważne czy ja użył konstruktora (który używa klasy bazowej HttpContent) lub ogólnej metody FromContent (używając w tym przypadku rzeczywistej StringContent) wynik był taki sam.

Więc moje pytania to:

Czy to zamierzone zachowanie HttpContent.Headers?
Czy są jakieś nagłówki właściwe dla rzeczywistego typu HttpContent?
Czego tu mi brakuje?

Uwaga: Jest to kod dla metody Flatten rozszerzenia:

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

Kolejność pozycji w ToDictionary nie jest gwarantowana, czy to daje taki sam wynik 'headers.ToDictionary (h => h.Key, h => string.Join ("; ", h.Value)) .Orderby (x => x.Key). Wybierz (kvp => $ "{kvp.Key}: {kvp.Value}") '? –

+0

@AkashKava problem nie dotyczy zamówienia. Problemem są nagłówki "Content-Length", które nie zawsze istnieją. – Luiso

+0

@Luiso, czy możesz pokazać [mcve], aby Twój problem mógł być dokładnie replikowany. Pomoże to w znalezieniu rozwiązania Twojego problemu. – Nkosi

Odpowiedz

4

Twój przykład jest niekompletny. Byłem w stanie odtworzyć twój problem dopiero po uzyskaniu dostępu do właściwości ContentLength przed wywołaniem metody rozszerzenia. Gdzieś w kodzie (najprawdopodobniej // reszta konfiguracji) jesteś bezpośrednio lub pośrednio wywołuje tę właściwość, która najprawdopodobniej następuje po leniwym wzorzec ładowania, a następnie jest zawarty w nagłówku, gdy następnym razem wywołasz metodę rozszerzenia i jest zawarty w skonstruowanym łańcuchu. Nie są one zgodne, ponieważ generujesz ciąg ręczny przed uzyskaniem dostępu do właściwości length content.

W kodzie źródłowym dla 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; 
    } 
} 

Widać, że jeśli nie jawnie ustawić długość zawartości następnie doda je (lazy load) do nagłówków przy pierwszej próbie do niego dostęp.

Dowodzi to, że moja oryginalna teoria jest dodawana po wygenerowaniu/spłaszczeniu łańcucha, a następnie uzyskała dostęp do właściwości ContentLength i wyjaśnia niespójne wyliczenie.

+0

Po prostu podwoiłem sprawdzanie kodu i nie widzę, gdzie mógłbym uzyskać dostęp do właściwości "Content-Length", przynajmniej nie jest to oczywiste, ale może po prostu jej brakuje. Bardzo dziękuję – Luiso

+1

Zauważyłem w twoim 'ContentDto' masz właściwość' Data'. jak i gdzie wypełniasz tę właściwość. Jeśli czytasz strumień lub ciąg treści htto, kod źródłowy pokazuje, że tuż przed odczytaniem strumienia wywołuje długość zawartości, aby wiedzieć, ile przeczytać. To może być twój winowajca. – Nkosi

+0

tak, masz rację, dokładnie tak się stało. Jesteś bardzo pomocny, dziękuję bardzo – Luiso

0

Wydaje się, że klasa HttpContent ma dość dziwne zachowanie z właściwości nagłówków. W jakiś sposób długość zawartości wydaje się być obliczona tak, jak jest to podane: here. Nie dotyczy to konkretnie problemu, ale można wykonać test z nowym obiektem httpContent podobnym do pierwszego. Jestem pewien, że będziesz w stanie uzyskać długość treści bez problemu.