Web API에서 메시지 처리기로 작업하는 방법

Web API의 메시지 처리기는 들어오는 요청이 HttpControllerDispatcher에 도달하기 전에 처리, 편집 또는 거부 할 수있는 기회를 제공합니다. 메시지 처리기는 요청 처리 파이프 라인에서 훨씬 더 일찍 실행되므로 Web API에서 교차 절단 문제를 구현할 수있는 좋은 장소입니다.

사용자 지정 메시지 처리기 구현

모든 메시지 핸들러는 HttpMessageHandler 클래스에서 파생됩니다. 고유 한 메시지 핸들러를 빌드하려면 DelegatingHandler 클래스를 확장해야합니다. DelegatingHandler 클래스는 차례로 HttpMessageHandler 클래스에서 파생됩니다.

다음 Web API 컨트롤러를 고려하십시오.

public class DefaultController : ApiController

    {

        public HttpResponseMessage Get()

        {

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

        }

    }

메시지 처리기를 만들려면 DelegatingHandler 클래스를 확장하고 SendAsync 메서드를 재정의해야합니다.

public class Handler : DelegatingHandler

    {

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

        {

           return base.SendAsync(request, cancellationToken);

        }

    }

Web API 요청 처리 파이프 라인에는 몇 가지 기본 제공 메시지 처리기가 포함됩니다. 여기에는 다음이 포함됩니다.

  • HttpServer-호스트에서 요청을 검색하는 데 사용됩니다.
  • HttpRoutingDispatcher-구성된 경로에 따라 요청을 발송하는 데 사용됩니다.
  • HttpControllerDispatcher-각 컨트롤러에 요청을 보내는 데 사용됩니다.

파이프 라인에 메시지 핸들러를 추가하여 다음 작업 중 하나 이상을 수행 할 수 있습니다.

  • 인증 및 권한 부여 수행
  • 수신 요청 및 발신 응답 로깅
  • 응답 개체에 응답 헤더 추가
  • 요청 헤더 읽기 또는 수정

다음 코드 조각은 Web API에서 간단한 메시지 처리기를 구현하는 방법을 보여줍니다.

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;

        }

}

메시지 핸들러는 요청 메시지를 처리하지 않고 응답 메시지를 생성 한 다음 반환합니다. 아래 코드 목록에 표시된대로 들어오는 요청에 대해 아무것도 수행하지 않으려는 경우 SendAsync 메서드의 기본 버전을 호출 할 수도 있습니다.

public class Handler : DelegatingHandler

{

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

        {

            return await base.SendAsync(request, cancellationToken);

        }

}

SendAsync 메서드에서 나가는 Http 요청 및 응답을 기록하는 코드를 작성할 수도 있습니다.

Web API를 실행하기 위해 아래와 같은 테스트 방법을 사용할 수 있습니다.

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

        }

테스트 메서드를 실행하면 "Inside the Default Web API Controller ..."라는 메시지가 응답 메시지로 반환되고 테스트가 통과됩니다. 오! 메시지 처리기를 만들었지 만 아직 메시지 처리 파이프 라인에 등록하지 않았습니다.

이제 웹 API 인프라에 사용자 지정 처리기가있는 위치를 알려야합니다. 이렇게하려면 파이프 라인에 사용자 지정 처리기를 등록해야합니다. 아래와 같이 WebApiConfig 클래스의 Register 메서드에서 방금 만든 사용자 지정 메시지 처리기를 등록 할 수 있습니다.

public static void Register(HttpConfiguration config)

{

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

}

테스트 메서드를 다시 실행하면 "Inside the logging message handler ..."라는 텍스트 메시지가 응답 메시지로 반환되고 테스트가 통과됩니다.

아래 코드 스 니펫에 표시된대로 여러 메시지 핸들러를 메시지 처리 파이프 라인에 등록 할 수도 있습니다.

public static void Register(HttpConfiguration config)

{

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

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

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

}

메시지 핸들러는 파이프 라인에 추가 된 순서대로 실행되고 응답은 역순으로 반환됩니다. 즉, 요청이 수신 될 때 등록 된 순서대로 메시지 핸들러가 실행됩니다. 나가는 응답 중에는 프로세스가 반전됩니다. 따라서 메시지 처리기는 파이프 라인 등록의 역순으로 실행됩니다.

수신 요청을 검사하고 요청에 유효한 API 키가 포함되어 있는지 확인하는 메시지 핸들러를 구현할 수도 있습니다. API 키가 없거나 유효하지 않은 경우 적절한 오류 메시지를 반환합니다. 다음 코드 목록은이를 수행하는 방법을 보여줍니다. 어쨌든 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);

            }

        }