Bagaimana bekerja dengan penangan pesan di Web API

Penangan pesan di Web API memberi Anda kesempatan untuk memproses, mengedit, atau menolak permintaan masuk sebelum mencapai HttpControllerDispatcher. Penangan pesan dijalankan jauh lebih awal di pipeline pemrosesan permintaan, oleh karena itu mereka adalah tempat yang tepat untuk mengimplementasikan masalah lintas sektoral di Web API.

Menerapkan penangan pesan khusus

Semua penangan pesan berasal dari kelas HttpMessageHandler. Untuk membuat penangan pesan Anda sendiri, Anda harus memperluas kelas DelegatingHandler. Perhatikan bahwa kelas DelegatingHandler pada gilirannya berasal dari kelas HttpMessageHandler.

Pertimbangkan pengontrol API Web berikut.

public class DefaultController : ApiController

    {

        public HttpResponseMessage Get()

        {

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

        }

    }

Untuk membuat penangan pesan, Anda perlu memperluas kelas DelegatingHandler dan mengganti metode SendAsync.

public class Handler : DelegatingHandler

    {

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

        {

           return base.SendAsync(request, cancellationToken);

        }

    }

Pipeline pemrosesan permintaan API Web menyertakan beberapa penangan pesan bawaan. Ini termasuk yang berikut:

  • HttpServer - ini digunakan untuk mengambil permintaan dari host
  • HttpRoutingDispatcher - ini digunakan untuk mengirimkan permintaan berdasarkan rute yang dikonfigurasi
  • HttpControllerDispatcher - ini digunakan untuk mengirim permintaan ke pengontrol masing-masing

Anda dapat menambahkan penangan pesan ke pipeline untuk melakukan satu atau beberapa operasi berikut.

  • Lakukan otentikasi dan otorisasi
  • Mencatat permintaan masuk dan tanggapan keluar
  • Tambahkan header respons ke objek respons
  • Baca atau ubah header permintaan

Cuplikan kode berikut menunjukkan bagaimana Anda dapat mengimplementasikan penangan pesan sederhana di API Web.

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;

        }

}

Penangan pesan tidak memproses pesan permintaan - itu membuat pesan tanggapan dan kemudian mengembalikannya. Anda juga dapat memanggil versi dasar metode SendAsync jika Anda tidak ingin melakukan apa pun dengan permintaan masuk seperti yang ditunjukkan dalam daftar kode di bawah ini.

public class Handler : DelegatingHandler

{

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

        {

            return await base.SendAsync(request, cancellationToken);

        }

}

Anda juga dapat menulis kode untuk mencatat permintaan Http dan tanggapan yang keluar dalam metode SendAsync.

Untuk menjalankan API Web Anda dapat menggunakan metode pengujian seperti yang diberikan di bawah ini.

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

        }

Saat Anda menjalankan metode pengujian, pesan "Di dalam Pengontrol API Web Default ..." dikembalikan sebagai pesan respons dan pengujian berhasil. Oh! Kami memang membuat penangan pesan, tetapi kami belum mendaftarkannya ke pipa penanganan pesan.

Anda sekarang harus memberi tahu infrastruktur API Web di mana ada pengendali khusus Anda. Untuk melakukannya, Anda harus mendaftarkan penangan kustom Anda di pipeline. Anda dapat mendaftarkan penangan pesan khusus yang baru saja kita buat dalam metode Register kelas WebApiConfig seperti yang ditunjukkan di bawah ini.

public static void Register(HttpConfiguration config)

{

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

}

Saat Anda menjalankan metode pengujian lagi, pesan teks "Di dalam penangan pesan logging ..." dikembalikan sebagai pesan respons dan pengujian berhasil.

Perhatikan bahwa Anda juga dapat mendaftarkan beberapa penangan pesan ke pipa penanganan pesan seperti yang ditunjukkan dalam cuplikan kode di bawah ini.

public static void Register(HttpConfiguration config)

{

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

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

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

}

Penangan pesan akan dieksekusi dalam urutan di mana mereka telah ditambahkan ke pipa dan tanggapan akan dikembalikan dalam urutan terbalik. Dengan kata lain, pada saat permintaan masuk, penangan pesan dijalankan sesuai urutan pendaftarannya. Selama respon keluar, prosesnya dibalik. Jadi, penangan pesan dieksekusi dalam urutan terbalik dari pendaftarannya ke pipeline.

Anda juga bisa mengimplementasikan penangan pesan yang memeriksa permintaan masuk dan memeriksa apakah permintaan tersebut berisi kunci api yang valid. Jika kunci api tidak ada atau tidak valid, ia mengembalikan pesan kesalahan yang sesuai. Daftar kode berikut menunjukkan bagaimana Anda dapat melakukan ini - Saya menyerahkan kepada Anda untuk menulis kode untuk memvalidasi kunci api.

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

            }

        }