2016-07-24 42 views
10

I HttpContent in die folgenden dto bin Umwandlung:HttpContent Header inkonsistent Aufzählung

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

und leite einige Unit-Tests darauf:

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

Und das Test nicht besteht, da die Content-Length Header nicht werden gefangen auf meinem dto. Aber wenn ich das tue:

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

Der Test vergeht und alle Header werden erfasst. Noch habe ich versucht, auch diese:

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

und es scheitert, da dto hat nicht die Content-Length Header, aber dto1 tut. Ich habe sogar versucht, die Header in einer Werk wie Methode wie folgt erhalten:

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

zu sehen, ob es etwas Besonderes über die StringContent Klasse in Bezug auf die Content-Length Header war, aber es machte keinen Unterschied, egal ob ich verwendet den Konstruktor (der die Basisklasse HttpContent verwendet) oder die generische Methode FromContent (in diesem Fall den tatsächlichen StringContent), das Ergebnis war das gleiche.

Also meine Fragen sind:

Ist das das gewünschte Verhalten von HttpContent.Headers?
Gibt es einige Header, die für den tatsächlichen HttpContent Typ spezifisch sind?
Was fehlt mir hier?

Hinweis: Dies ist der Code für die Flatten Erweiterungsmethode:

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

Reihenfolge der Elemente in ToDictionary ist nicht garantiert, erzeugt dies das gleiche Ergebnis 'headers.ToDictionary (h => h.Key, h => string.Join ("; ", h.Value)) .Orderby (x => x.Key) .Wählen Sie (kvp => $ "{kvp.Key}: {kvp.Value}") '? –

+0

@AkashKava das Problem ist nicht über die Reihenfolge. Das Problem sind die Header 'Content-Length', die nicht immer vorhanden sind. – Luiso

+0

@Luiso, können Sie eine [mcve] zeigen, damit Ihr Problem genau repliziert werden kann. Dies hilft bei der Suche nach einer Lösung für Ihr Problem. – Nkosi

Antwort

4

Ihr Beispiel ist unvollständig. Ich konnte Ihr Problem nur wiederherstellen, wenn ich vor dem Aufruf der Erweiterungsmethode auf die Eigenschaft ContentLength zugegriffen habe. Irgendwo in Ihrem Code (höchstwahrscheinlich // Rest der Einrichtung) Sie rufen entweder direkt oder indirekt diese Eigenschaft, die höchstwahrscheinlich nach einem Lazy Loading-Muster folgt und es ist dann in der Kopfzeile enthalten, wenn Sie als nächstes Ihre Erweiterungsmethode und es aufrufen ist in der konstruierten Zeichenfolge enthalten. Sie stimmen nicht überein, weil Sie Ihre manuelle Zeichenfolge generieren, bevor Sie auf die Eigenschaft content length zugreifen.

Im Quellcode für 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; 
    } 
} 

Sie können sehen, dass, wenn Sie nicht explizit hinzufügen wird es festgelegt haben (faul Last) eine Inhaltslänge dann auf die Header, wenn Sie zuerst auf sie zugreifen versuchen.

Dies beweist meine ursprüngliche Theorie darüber, dass es hinzugefügt wird, nachdem Sie Ihre Zeichenfolge generiert/abgeflacht und dann auf die ContentLength-Eigenschaft zugegriffen und die inkonsistente Enumeration erläutert.

+0

Ich verdoppelte nur meinen Code und ich kann nicht sehen, wo ich auf die 'Content-Length'-Eigenschaft zugreifen könnte, zumindest keine offensichtliche, aber ich könnte es einfach vermissen. Vielen Dank – Luiso

+1

Ich bemerkte in Ihrem 'ContentDto' haben Sie eine' Data' Eigenschaft. Wie und wo bevölkern Sie diese Eigenschaft? Wenn Sie den Stream oder die Zeichenfolge des HTTO-Inhalts lesen, zeigt der Quellcode, dass er kurz vor dem Lesen des Streams die Inhaltslänge aufruft, um zu wissen, wie viel gelesen werden soll. Das könnte dein Schuldiger sein. – Nkosi

+0

ja, du hast recht, genau das ist passiert. Sie waren sehr hilfreich, vielen Dank – Luiso

0

Es scheint, dass die HttpContent Klasse mit den Header-Eigenschaften ein ziemlich seltsames Verhalten hat. Irgendwie scheint die Inhaltslänge so zu berechnen, wie es angegeben ist here. Es behandelt Ihr Problem nicht speziell, aber Sie können einen Test mit einem neuen httpContent-Objekt ähnlich dem ursprünglichen durchführen. Ich bin mir ziemlich sicher, dass Sie die inhaltliche Länge problemlos erreichen können.