2013-03-19 9 views
9

Ich versuche, Web API Request Content abzumelden - d. H. Die JSON-Zeichenfolge. Ich habe eine ITraceWriter-Klasse() implementiert und sie so konfiguriert, dass die Web-API sie in der Pipeline aufruft. Aber wenn ich die request.Content lesen oder in einen Stream kopieren, um es zu lesen, ist für die Methode nicht verfügbar, was zu einem Nullmodell führt. This post spricht über dieses Problem ein wenig. Jeder hat Erfahrung beim Abmelden eingehender Web-API-Anfrage-Inhalte und weiß, was der beste Ansatz ist?ASP.NET-Web-API Protokollieren eingehender Anfrage Inhalt

Dank

Ein Update

habe ich ein einfaches Web-API-Projekt Probe etwas in meinem Projekt, um auszuschließen, und ich sehe immer noch, dass das Modell, weil die Protokollierung null sein wird. Ich teste einfach ein paar Mal hintereinander, indem ich über Fidder poste und sehe, dass mein Modell in null kommt. Wenn die Breakpoints an Ort und Stelle sind, könnte es funktionieren, weshalb ich denke, dass es ein Sync/Timing-Problem gibt. Irgendwelche Gedanken, wie man das zur Arbeit bringt?

Rubrik:

User-Agent: Fiddler 
Host: localhost:56824 
Content-Type: application/json 
Content-Length: 22 

Körper:

{ 
"A":1,"B":"test" 
} 

Hier ist der Code:

Controller:

public class ValuesController : ApiController 
{ 
    [HttpPost] 
    public void Post(ValuesModel model) 
    { 
     if (model == null) 
     { 
      Debug.WriteLine("model was null!"); 
     } 
     else 
     { 
      Debug.WriteLine("model was NOT null!"); 
     } 
    } 
} 

Modell:

public class ValuesModel 
{ 
    public int A { get; set; } 
    public string B { get; set; } 
} 

Logger:

public class APITraceLogger : DelegatingHandler 
    { 
     protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) 
     { 
      if (request.Content != null) 
      { 
       // This can cause model to be null 
       request.Content.ReadAsStringAsync().ContinueWith(s => 
       { 
        string requestText = s.Result; 
        Debug.WriteLine(requestText); 
       }); 

       // and so can this 
       //request.Content.ReadAsByteArrayAsync() 
       // .ContinueWith((task) => 
       // { 
       //  string requestText = System.Text.UTF8Encoding.UTF8.GetString(task.Result); 
       //  Debug.WriteLine(requestText); 
       // }); 
      } 
      // Execute the request, this does not block 
      var response = base.SendAsync(request, cancellationToken); 

      // TODO: 
      // Once the response is processed asynchronously, log the response data 
      // to the database 


      return response; 
     } 


    } 

Verdrahten Logger in WebApiConfig Klasse:

config.MessageHandlers.Add(new APITraceLogger()); 

aktualisieren B

Es scheint, wie es jetzt funktioniert, wenn ich den Logger, um die Änderung Der folgende Code fügt die Antwort hinzu, async und gibt das Ergebnis zurück. Scheint so, als würde ich etwas nicht verstehen im Async-Code oder wirklich ein Timing-Problem oder etwas.

Antwort

5

Wie Filip in diesem Post erwähnt, packen ReadAsStringAsync- oder ReadAsByteArrayAsync-Methoden den Anforderungsinhalt intern. Dies bedeutet, dass Sie selbst dann, wenn der Stream-Typ Ihrer eingehenden Anfrage ein nicht gepufferter Stream ist, problemlos ein ReadAsStringAsync/ReadAsByteArrayAsync an einem Message-Handler ausführen und außerdem erwarten können, dass die Modellbindung funktioniert.

Standardmäßig wird der Stream einer Anfrage sowohl in Webhost- als auch in Selfhost-Fällen gepuffert. Aber wenn Sie ReadAsStringAsync/ReadAsByteArrayAsync und Modell Abwartens funktioniert auch in ungepufferten Modus bei Verwendung überprüfen möchten, können Sie die folgenden erzwingen ungepufferten Modus tun:

public class CustomBufferPolicySelector : WebHostBufferPolicySelector 
{ 
    public override bool UseBufferedInputStream(object hostContext) 
    { 
     //NOTE: by default, the request stream is always in buffered mode. 
     //return base.UseBufferedInputStream(hostContext); 

     return false; 
    } 
} 

config.Services.Replace(typeof(IHostBufferPolicySelector), new CustomBufferPolicySelector()); 

Gerade FYI ... die oben Der Richtlinien-Selektor funktioniert derzeit nur für den Web-Host.Wenn Sie möchten, einen ähnlichen Test in Selfhost tun, gehen Sie wie folgt:

//NOTE: by default, the transfer mode is TransferMode.Buffered 
config.TransferMode = System.ServiceModel.TransferMode.StreamedRequest; 

Nach einem Update B der Beitrag oben:

Sie Ihre Handler unten wie ändern könnte:

public class LoggingHandler : DelegatingHandler 
{ 
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     if (request.Content != null) 
     { 
      string requestContent = await request.Content.ReadAsStringAsync(); 
     } 

     HttpResponseMessage response = await base.SendAsync(request, cancellationToken); 

     if (response.Content != null) 
     { 
      string responseContent = await response.Content.ReadAsStringAsync(); 
     } 

     return response; 
    } 
} 
+0

Ich wurde von diesem Kommentar von Filip geworfen. Ich habe ReadAsStringAsync verwendet und mein Modell wäre null. Hier ist der grundlegende Code, den ich in der ITraceWriter Implementierung verwendet: request.Content.ReadAsStringAsync() ContinueWith (s => { String request = s.Result; Logger.log (request); });. – Bryan

+0

Ich kann das Problem nicht wiederholen, das Sie erwähnen. Zum Beispiel (nicht der beste Weg, es zu tun), habe ich den folgenden Code in der WriteTrace-Methode von SimpleTracer aus Mike Wassons Beispiel: if (rec.Request! = Null) {Console.WriteLine (rec.Category + "," + rec.Request.Content.ReadAsStringAsync(). Ergebnis); } –

+0

Danke für den Versuch zu repro. Versuchen herauszufinden, was anders ist. Ich verwende MVC 4 und laufe in IIS Express für meinen lokalen Entwickler. Vielleicht ist IIS Express der Unterschied. Ich versuche etwas anderes und werde zurück posten. – Bryan

Verwandte Themen