web-dev-qa-db-fra.com

DelegatingHandler pour la réponse dans Web Api

J'utilise actuellement plusieurs gestionnaires de délégation (classes dérivées de DelegatingHandler) pour travailler sur la demande avant son envoi, pour des choses comme la validation d'une signature, etc. Tout cela est très agréable, car je n'ai pas à dupliquer validation de la signature sur tous les appels (par exemple).

Je voudrais utiliser le même principe sur la réponse de la même demande Web. Y a-t-il quelque chose de similaire au DelegatingHandler pour la réponse? Un moyen d'attraper la réponse avant qu'elle ne revienne à la méthode, en quelque sorte?

Informations supplémentaires: j'appelle une API Web à l'aide de HttpClient.PutAsync(...)

25
Halvard

Oui. Vous pouvez le faire dans la tâche de continuation.

Je l'explique ici .

Par exemple, ce code (du blog ci-dessus) trace l'URI de la demande et ajoute un en-tête factice à la réponse.

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

       var response = await base.SendAsync(request, cancellationToken);
       response.Headers.Add("X-Dummy-Header", Guid.NewGuid().ToString());
       return response;
    }
}
44
Aliostad

Voici un exemple d'interception de la demande et de la réponse. la méthode substituée SendAsync est utilisée pour capturer la demande d'origine, tandis que la méthode appelée ResponseHandler est utilisée pour capturer la réponse.

Exemple pour capturer la demande et la réponse d'origine

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

Pour utiliser cette méthode, la classe doit être identifiée et enregistrée en tant que MessageHandler. J'ai ajouté la ligne suivante à mon fichier Global.asax ...

Exemple comment enregistrer la nouvelle classe MessageInterceptor

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

Voici mon fichier Global.asax complet. Remarquez comment le MessageInterceptor est référencé ...

Version complète de Global.asax montrant l'intégration de 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());
        }
    }
}
18
barrypicker