21

Attualmente sto usando diversi gestori di deleghe (classi derivate da DelegatingHandler) per lavorare sulla richiesta prima che venga inviata, per cose come la convalida di una firma ecc. Tutto questo è molto bello, perché non lo faccio duplicare la convalida della firma su tutte le chiamate (ad esempio).DelegatingHandler per la risposta in WebApi

Vorrei utilizzare lo stesso principio sulla risposta dalla stessa richiesta web. C'è qualcosa di simile a DelegatingHandler per la risposta? Un modo per cogliere la risposta prima che sia tornata al metodo, in un certo senso?

Ulteriori informazioni: che io chiamo un'API web utilizzando HttpClient.PutAsync(...)

risposta

37

Sì. Puoi farlo nel compito di continuazione.

Lo spiego here.

Ad esempio, questo codice (dal blog sopra) traccia l'URI della richiesta e aggiunge un'intestazione fittizia alla risposta.

public class DummyHandler : DelegatingHandler 
{ 
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     // work on the request 
     Trace.WriteLine(request.RequestUri.ToString()); 

     return base.SendAsync(request, cancellationToken) 
      .ContinueWith(task => 
      { 
       // work on the response 
       var response = task.Result; 
       response.Headers.Add("X-Dummy-Header", Guid.NewGuid().ToString()); 
       return response; 
      }); 
    } 
} 
+0

Ah, ora capisco gli esempi che utilizzano ContinueWith. Funziona alla grande Grazie (e scusa per la risposta lenta) – Halvard

+0

Come procederesti a leggere il contenuto della risposta qui? Provo a leggerlo, tuttavia getta un'eccezione disposed object. –

+0

@RossJones Che è bizzarro ... puoi inviare una riproduzione? – Aliostad

13

Ecco un esempio per intercettare la richiesta e la risposta. il metodo sottoposto a override SendAsync viene utilizzato per acquisire la richiesta originale, mentre il metodo chiamato ResponseHandler viene utilizzato per acquisire la risposta.

Esempio per catturare richiesta originale e la risposta

using System.Net.Http; 
using System.Threading.Tasks; 
namespace webAPI_Test 
{ 
    public class MessageInterceptor : DelegatingHandler 
    { 
     protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) 
     { 
      // CATCH THE REQUEST BEFORE SENDING TO THE ROUTING HANDLER 
      var headers = request.ToString(); 
      var body = request.Content.ReadAsStringAsync().Result; 
      var fullRequest = headers + "\n" + body; 

      // SETUP A CALLBACK FOR CATCHING THE RESPONSE - AFTER ROUTING HANDLER, AND AFTER CONTROLLER ACTIVITY 
      return base.SendAsync(request, cancellationToken).ContinueWith(
         task => 
         { 
          // GET THE COPY OF THE TASK, AND PASS TO A CUSTOM ROUTINE 
          ResponseHandler(task); 

          // RETURN THE ORIGINAL RESULT 
          var response = task.Result; 
          return response; 
         } 
      ); 
     } 

     public void ResponseHandler(Task<HttpResponseMessage> task) 
     { 
      var headers = task.Result.ToString(); 
      var body = task.Result.Content.ReadAsStringAsync().Result; 

      var fullResponse = headers + "\n" + body; 
     } 
    } 
} 

Per utilizzare questo metodo, la classe deve essere identificato e registrato come messageHandler. Ho aggiunto la seguente riga al mio file Global.asax ...

Esempio di come registrare la nuova classe MessageInterceptor

GlobalConfiguration.Configuration.MessageHandlers.Add(new MessageInterceptor()); 

Ecco il mio file Global.asax completa. Si noti come il MessageInterceptor viene fatto riferimento ...

versione completa di Global.asax che mostra l'integrazione MessageInterceptor

using System.Web.Http; 
using System.Web.Mvc; 
using System.Web.Optimization; 
using System.Web.Routing; 
namespace webAPI_Test 
{ 
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801 

    public class WebApiApplication : System.Web.HttpApplication 
    { 
     protected void Application_Start() 
     { 
      AreaRegistration.RegisterAllAreas(); 

      WebApiConfig.Register(GlobalConfiguration.Configuration); 
      FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 
      RouteConfig.RegisterRoutes(RouteTable.Routes); 
      BundleConfig.RegisterBundles(BundleTable.Bundles); 

      GlobalConfiguration.Configuration.MessageHandlers.Add(new MessageInterceptor()); 
     } 
    } 
}