So arbeiten Sie mit Nachrichtenhandlern in der Web-API

Nachrichtenhandler in der Web-API bieten Ihnen die Möglichkeit, eine eingehende Anforderung zu verarbeiten, zu bearbeiten oder abzulehnen, bevor sie den HttpControllerDispatcher erreicht. Nachrichtenhandler werden viel früher in der Anforderungsverarbeitungspipeline ausgeführt, daher sind sie ein großartiger Ort, um Querschnittsprobleme in der Web-API zu implementieren.

Implementieren eines benutzerdefinierten Nachrichtenhandlers

Alle Nachrichtenhandler stammen von der Klasse HttpMessageHandler. Um Ihren eigenen Nachrichtenhandler zu erstellen, sollten Sie die DelegatingHandler-Klasse erweitern. Beachten Sie, dass die DelegatingHandler-Klasse wiederum von der HttpMessageHandler-Klasse abgeleitet ist.

Betrachten Sie den folgenden Web-API-Controller.

public class DefaultController : ApiController

    {

        public HttpResponseMessage Get()

        {

            return Request.CreateResponse(HttpStatusCode.OK, "Inside the Default Web API Controller...");           

        }

    }

Um einen Nachrichtenhandler zu erstellen, müssen Sie die DelegatingHandler-Klasse erweitern und die SendAsync-Methode überschreiben.

public class Handler : DelegatingHandler

    {

        protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

        {

           return base.SendAsync(request, cancellationToken);

        }

    }

Die Pipeline zur Verarbeitung von Web-API-Anforderungen enthält einige integrierte Nachrichtenhandler. Dazu gehören die folgenden:

  • HttpServer - Hiermit wird die Anforderung vom Host abgerufen
  • HttpRoutingDispatcher - Hiermit wird die Anforderung basierend auf der konfigurierten Route versendet
  • HttpControllerDispatcher - Hiermit wird die Anforderung an den jeweiligen Controller gesendet

Sie können der Pipeline Nachrichtenhandler hinzufügen, um einen oder mehrere der folgenden Vorgänge auszuführen.

  • Führen Sie die Authentifizierung und Autorisierung durch
  • Protokollierung der eingehenden Anforderungen und der ausgehenden Antworten
  • Fügen Sie den Antwortobjekten Antwortheader hinzu
  • Lesen oder ändern Sie die Anforderungsheader

Das folgende Codefragment zeigt, wie Sie einen einfachen Nachrichtenhandler in der Web-API implementieren können.

public class Handler : DelegatingHandler

{

protected async override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

        {

            var response = new HttpResponseMessage(HttpStatusCode.OK)

            {

                Content = new StringContent("Inside the message handler...")

            };

            var task = new TaskCompletionSource();

            task.SetResult(response);

            return await task.Task;

        }

}

Der Nachrichtenhandler verarbeitet die Anforderungsnachricht nicht - er erstellt eine Antwortnachricht und gibt sie dann zurück. Sie können auch die Basisversion der SendAsync-Methode aufrufen, wenn Sie mit der eingehenden Anforderung nichts tun möchten, wie in der folgenden Codeliste gezeigt.

public class Handler : DelegatingHandler

{

protected async override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

        {

            return await base.SendAsync(request, cancellationToken);

        }

}

Sie können auch Code schreiben, um die HTTP-Anforderungen und die Antworten zu protokollieren, die in der SendAsync-Methode ausgegeben werden.

Um die Web-API auszuführen, können Sie eine Testmethode wie die unten angegebene verwenden.

 [TestMethod]

        public void WebAPIControllerTest()

        {

            HttpClient client = new HttpClient();

            var result = client.GetAsync(new Uri("//localhost//api/default/")).Result;

            string responseMessage = result.Content.ReadAsStringAsync().Result;

            Assert.IsTrue(result.IsSuccessStatusCode);

        }

Wenn Sie die Testmethode ausführen, wird die Meldung "Innerhalb des Standard-Web-API-Controllers ..." als Antwortnachricht zurückgegeben und der Test besteht. Oh! Wir haben einen Nachrichtenhandler erstellt, müssen ihn jedoch noch in der Nachrichtenbehandlungspipeline registrieren.

Sie müssen jetzt der Web-API-Infrastruktur mitteilen, wo Ihr benutzerdefinierter Handler vorhanden ist. Dazu sollten Sie Ihren benutzerdefinierten Handler in der Pipeline registrieren. Sie können den soeben erstellten benutzerdefinierten Nachrichtenhandler in der Register-Methode der WebApiConfig-Klasse wie unten gezeigt registrieren.

public static void Register(HttpConfiguration config)

{

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

}

Wenn Sie die Testmethode erneut ausführen, wird die Textnachricht "Inside the logging message handler ..." als Antwortnachricht zurückgegeben und der Test besteht.

Beachten Sie, dass Sie auch mehrere Nachrichtenhandler in der Nachrichtenbehandlungspipeline registrieren können, wie im folgenden Codeausschnitt gezeigt.

public static void Register(HttpConfiguration config)

{

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

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

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

}

Die Nachrichtenhandler würden in der Reihenfolge ausgeführt, in der sie der Pipeline hinzugefügt wurden, und die Antwort würde in umgekehrter Reihenfolge zurückgegeben. Mit anderen Worten, zum Zeitpunkt der eingehenden Anforderung werden die Nachrichtenhandler in der Reihenfolge ausgeführt, in der sie registriert sind. Während der ausgehenden Antwort wird der Prozess nur umgekehrt. Daher werden die Nachrichtenhandler in umgekehrter Reihenfolge ihrer Registrierung in der Pipeline ausgeführt.

Sie können auch einen Nachrichtenhandler implementieren, der die eingehende Anforderung überprüft und prüft, ob die Anforderung einen gültigen API-Schlüssel enthält. Wenn der API-Schlüssel nicht vorhanden oder ungültig ist, wird eine entsprechende Fehlermeldung zurückgegeben. Die folgende Codeliste zeigt, wie Sie dies tun können - ich überlasse es Ihnen, den Code zu schreiben, um den API-Schlüssel trotzdem zu validieren.

protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

        {

            string key = HttpUtility.ParseQueryString(request.RequestUri.Query).Get("key");

            string errorMessage = "You need to specify the api key to access the Web API.";

            try

            {

                if (!string.IsNullOrWhiteSpace(key))

                {

                    return base.SendAsync(request, cancellationToken);

                }

                else

                {

                    HttpResponseMessage response = request.CreateErrorResponse(HttpStatusCode.Forbidden, errorMessage);

                    throw new HttpResponseException(response);

                }

            }

            catch

            {

                HttpResponseMessage response = request.CreateErrorResponse(HttpStatusCode.InternalServerError, "An unexpected error occured...");

                throw new HttpResponseException(response);

            }

        }