Asp.Net WebApi 핵심 객체 해결(다음)

34176 단어
이어서 Asp.를 쓰세요.Net WebApi 핵심 대상 해석(다음 편) 전까지만 해도 여느 때와 다름없었다. 설날이 막 지났는데도 온몸이 어지러운 상태였다. 아침 일찍 시스템 BUG를 처리하러 왔다. 그야말로 갱부였다. (설날에 이 BUG를 오라고 하지 않았는데) 팀원들이 파낸 갱도 눈물을 머금고 메웠다.BUG를 바꾸기 전에 팀원들이 쓴 코드를 보면 여기서 평가를 안 해요. 어차피 바꾸면서 욕을 하면 제 입이 멈추지 않아요. 개발자로서 제 기분은 더 이상 묘사하지 않아요. 어차피 좋은 단어를 찾을 수 없어요.
새해 전망에 대해 저는 좋은 전망이 없다고 생각합니다. 어쨌든 작년의 전망은 하나도 실현되지 않았습니다. 일을 어떻게 해야 할지 어떻게 해야 할지 대다수 사람들은 저와 차이가 많지 않을 것입니다. 어떤 일도 강요할 수 없고 사전에 열심히 해야 합니다. 사후에 얻지 못하면 좀 싱겁게 보고 너무 가혹하게 요구하면 조만간 심신이 모두 피곤합니다.
잡담을 끝내고 이어서 본론을 이야기했는데, 전편에 쓴 것은 Asp이다.Net WebApi 핵심 대상 해석(상편), 본문은 하편이므로 어떻게 쓰든지 많은 지적을 바랍니다.
하나.WebApi 처리 아키텍처:
Asp.를 공부하고 있습니다.Net WebApi의 경우 Asp.Net WebApi의 내부 운영 체제에 대해 대체적으로 알고 있다. 많은 사람들이 이러한 기본 원리를 이해하는 의미가 크지 않고 실제 개발에서 응용하지 못하고 시간도 낭비한다고 말한다. 이런 말은 일리가 있다. 그러나 우리의 안목을 길게 두면 이렇게 이야기하고 싶지 않다. 우리가 기본 원리를 이해한 후에어느 정도에 우리가 프로그램 밑바닥의 버그를 처리하는 데 도움을 줄 수 있을 뿐만 아니라 그 중에서 사고를 습득하고 디자이너의 의도를 깊이 이해하게 함으로써 우리가 더욱 숙련된 운용에 유리하다.
WebApi 처리 구조에 대해 이야기하기 전에 마이크로소프트가 WebApi를 위해 제공한 포스터를 살펴보자. 여기는 그림을 가져오지 않고 볼 것은 다운로드를 클릭할 수 있다. 다운로드 주소
    Asp.Net Web Api 처리 아키텍처는 트랜잭션 레이어, 메시징 파이핑, 컨트롤러 처리 레이어로 나눌 수 있습니다.
관리층: WebApi와 밑바닥 HTTP 창고 사이에 위치하고 밑바닥이 WebApi 관리층을 담당한다.
메시지 처리 프로그램 파이프층: 로그와 캐시 같은 메시지의 횡단 관심사를 사용합니다.
컨트롤러 처리 층: 컨트롤러와 조작은 이 층에서 호출되고 파라미터가 다시 연결되고 검증되며 HTTP 응답 메시지도 이곳에서 생성됩니다.
위탁 관리층 측정 설명은 아래에서 설명할 것이다.메시지 처리 프로그램은 HTTP 요청 메시지를 받아들여 HTTP 응답 메시지로 돌아가는 동작을 추상적으로 처리합니다.메시지 처리 프로그램 파이프와 컨트롤러 처리층을 연결하는 다리는 컨트롤러 배달 프로그램이다.컨트롤러 배달은 또한 메시지 처리 프로그램으로 주로 정확한 컨트롤러를 선택하고 만들고 호출하여 요청을 처리한다.
둘.WebApi 관리형 해결 방법:
Asp.Net Web Api의 호스팅 방식은 세 가지입니다. 세 가지 호스팅 방식에 대해 간략하게 살펴보겠습니다.
       (1).모든 Windows 프로세스에서 호스팅됩니다.
       (2).웹 호스팅(IIS에서 ASP 사용)NET 파이프를 호스팅합니다.(IIS와 ASPI.NET 파이프라인에 대한 지식이 필요하면 스스로 검색하여 볼 수 있다. 필자는 웹 개발자가 그 운영 체제에 대해 알아보면 asp.net 웹 프로그램에 대해 깊이 있게 이해할 수 있다고 제안한다.)
       (3).OWIN이 호스팅합니다.(owin 호환 서버에 웹api층 구축)
웹 트랜잭션을 사용할 때 ASP를 사용합니다.NET의 파이프 및 라우팅 기능으로 HTTP 요청을 새 ASP로 전달합니다.NET 프로세서, HttpControllerHandler에 있습니다.이 프로그램은 Htpp Request 실례를 받아서 Http Request Message 실례로 변환한 다음 WebApi 파이프로 전송하여 전통적인 asp.net 파이프와 새로운 asp.netwebapi 구조 간에 링크를 만듭니다.
Http Controller Handler 클래스에 대해 자세히 살펴보겠습니다.
HttpControllerHandler 클래스는 System에 있습니다.Web.Http.WebHost 네임스페이스에서 네임스페이스의 이름에 따라 웹 호스팅을 만드는 데 주로 사용되는 네임스페이스를 명확하게 알 수 있습니다.
public class HttpControllerHandler : IHttpAsyncHandler, IHttpHandler

이 클래스는 IHttpAsyncHandler, IHttpHandler 인터페이스에서 계승되었다. 우리는 베이스 코드에서 알 수 있듯이 이 클래스는 실제적으로 HttpTaskAsyncHandler 클래스에서 계승되고 Http 작업과 비동기 처리 프로그램을 사용한다.다음은 이와 같은 몇 가지 방법을 살펴보겠습니다.
  1.ProcessRequestasync 메서드: 비동기 작업을 처리하는 코드를 제공합니다.
    /// <summary>
    ///            
    /// </summary>
    /// <returns>
    ////// </returns>
    /// <param name="context">HTTP    。</param>
    public override Task ProcessRequestAsync(HttpContext context)
    {
      return this.ProcessRequestAsyncCore((HttpContextBase) new HttpContextWrapper(context));
    }

    internal async Task ProcessRequestAsyncCore(HttpContextBase contextBase)
    {
      HttpRequestMessage request = HttpContextBaseExtensions.GetHttpRequestMessage(contextBase) ?? HttpControllerHandler.ConvertRequest(contextBase);
      System.Net.Http.HttpRequestMessageExtensions.SetRouteData(request, this._routeData);
      CancellationToken cancellationToken = HttpResponseBaseExtensions.GetClientDisconnectedTokenWhenFixed(contextBase.Response);
      HttpResponseMessage response = (HttpResponseMessage) null;
      try
      {
        response = await this._server.SendAsync(request, cancellationToken);
        await HttpControllerHandler.CopyResponseAsync(contextBase, request, response, HttpControllerHandler._exceptionLogger.Value, HttpControllerHandler._exceptionHandler.Value, cancellationToken);
      }
      catch (OperationCanceledException ex)
      {
        contextBase.Request.Abort();
      }
      finally
      {
        System.Net.Http.HttpRequestMessageExtensions.DisposeRequestResources(request);
        request.Dispose();
        if (response != null)
          response.Dispose();
      }
    }

이 방법은 비동기적인 방법이고 수신된 매개 변수는 HttpContext로 http 상하문 내용을 표시하고 GetHttpRequestMessage()를 호출하여 HttpRequestMessage 대상의 실례를 얻으며 SetRouteData() 방법을 호출하여 루트 정보를 설정하고 GetClientDisconnectedTokenWhenFixed() 방법을 호출하여 클라이언트가 영패를 끊을 때 복원하고 취소 영패를 되돌려준다.이 방법은 http 요청을 생성한 후 메시지를 비동기적으로 발송 처리합니다.
   2.GetStreamContent 메서드: 스트림 컨텐트 가져오기 요청을 가져옵니다.
 private static HttpContent GetStreamContent(HttpRequestBase requestBase, bool bufferInput)
    {
      if (bufferInput)
        return (HttpContent) new HttpControllerHandler.LazyStreamContent((Func<Stream>) (() =>
        {
          if (requestBase.ReadEntityBodyMode == ReadEntityBodyMode.None)
            return (Stream) new SeekableBufferedRequestStream(requestBase);
          if (requestBase.ReadEntityBodyMode == ReadEntityBodyMode.Classic)
          {
            requestBase.InputStream.Position = 0L;
            return requestBase.InputStream;
          }
          if (requestBase.ReadEntityBodyMode == ReadEntityBodyMode.Buffered)
          {
            if (requestBase.GetBufferedInputStream().Position <= 0L)
              return (Stream) new SeekableBufferedRequestStream(requestBase);
            requestBase.InputStream.Position = 0L;
            return requestBase.InputStream;
          }
          throw new InvalidOperationException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, SRResources.RequestBodyAlreadyReadInMode, new object[1]
          {
            (object) ReadEntityBodyMode.Bufferless
          }));
        }));
      return (HttpContent) new HttpControllerHandler.LazyStreamContent((Func<Stream>) (() =>
      {
        if (requestBase.ReadEntityBodyMode == ReadEntityBodyMode.None)
          return requestBase.GetBufferlessInputStream();
        if (requestBase.ReadEntityBodyMode == ReadEntityBodyMode.Classic)
          throw new InvalidOperationException(SRResources.RequestStreamCannotBeReadBufferless);
        if (requestBase.ReadEntityBodyMode == ReadEntityBodyMode.Bufferless)
        {
          Stream bufferlessInputStream = requestBase.GetBufferlessInputStream();
          if (bufferlessInputStream.Position > 0L)
            throw new InvalidOperationException(SRResources.RequestBodyAlreadyRead);
          return bufferlessInputStream;
        }
        throw new InvalidOperationException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, SRResources.RequestBodyAlreadyReadInMode, new object[1]
        {
          (object) ReadEntityBodyMode.Buffered
        }));
      }));
    }

이 방법은 HTTP 요청의 흐름 내용을 가져오는 것과 같이 매개 변수인 Http Request Base에 따라 알 수 있듯이 이 방법은 HTTP 요청을 받아들인 후 메시지를 처리한다. buffer Input 매개 변수는 전송된 것이 흐름 대상인지 아닌지를 판단하고 전송된 흐름 대상은 Lazy Stream Content 클래스에 들어가 처리하며 Lazy Stream Content 클래스의 구조 함수는 반환 값을 포함하는 의뢰를 받는다.
public LazyStreamContent(Func<Stream> getStream)
      {
        this._getStream = getStream;
      }

GetStreamContent 메서드와 관련된 작업은 주로 HTTP 요청 내용을 해석하는 작업입니다.
셋.WebApi 핵심 객체 HttpRequestMessage 및 HttpResponseMessage:
   1.HttpRequestMessageExtensions: HTTP 메시지 요청 실례의 확장 클래스입니다.
      (1).GetRequestContext 메서드:HTTP 요청 메시지 내용 가져오기
 public static HttpRequestContext GetRequestContext(this HttpRequestMessage request)
    {
      if (request == null)
        throw Error.ArgumentNull("request");
      return HttpRequestMessageExtensions.GetProperty<HttpRequestContext>(request, HttpPropertyKeys.RequestContextKey);
    }

들어오는 HTTP 요청에 따라 GetProperty() 방법을 호출하여 속성을 가져옵니다. GetProperty() 방법을 자세히 살펴보겠습니다.
 private static T GetProperty<T>(this HttpRequestMessage request, string key)
    {
      T obj;
      DictionaryExtensions.TryGetValue<T>(request.Properties, key, out obj);
      return obj;
    }

이 메서드는 요청 객체를 가져오고 KEY 값에 따라 TryGetValue () 메서드를 호출하여 속성을 가져옵니다.
   (2).CreateResponse(): 요청 정보에 대한 응답을 생성합니다.
    /// <summary>
    ///        HttpRequestMessage   HttpResponseMessage
    /// </summary>
    /// <returns>
    ///      HttpRequestMessage        HttpResponseMessage
    /// </returns>
    /// <param name="request">         HTTP     。</param>
<param name="statusCode">
HTTP 。</param>
<param name="value">
HTTP 。</param>
<param name="configuration">
HTTP 。</param>
<typeparam name="T">
HTTP 。</typeparam> public static HttpResponseMessage CreateResponse<T>(this HttpRequestMessage request, HttpStatusCode statusCode, T value, HttpConfiguration configuration) { if (request == null) throw Error.ArgumentNull("request"); configuration = configuration ?? HttpRequestMessageExtensions.GetConfiguration(request); if (configuration == null) throw Error.InvalidOperation(SRResources.HttpRequestMessageExtensions_NoConfiguration); IContentNegotiator contentNegotiator = ServicesExtensions.GetContentNegotiator(configuration.Services); if (contentNegotiator == null) throw Error.InvalidOperation(SRResources.HttpRequestMessageExtensions_NoContentNegotiator, (object) typeof (IContentNegotiator).FullName); IEnumerable<MediaTypeFormatter> formatters = (IEnumerable<MediaTypeFormatter>) configuration.Formatters; return NegotiatedContentResult<T>.Execute(statusCode, value, contentNegotiator, request, formatters); }

이 방법은 요청 메시지가 제공하는 관련 정보에 따라 요청 메시지를 처리한 후 응답 메시지 내용을 만든다.
   2.Http ResponseMessageExtensions: HTTP 응답 메시지 실례의 확장 클래스입니다.
TryGetContentValue(): 컨텐츠의 값을 가져옵니다.
    /// <summary>
    ///     HttpResponseMessageExtensions      。
    /// </summary>
    /// <returns>
    ////// </returns>
    /// <param name="response"></param>
         <param name="value">    。</param>
         <typeparam name="T">        。</typeparam>
    public static bool TryGetContentValue<T>(this HttpResponseMessage response, out T value)
    {
      if (response == null)
        throw Error.ArgumentNull("response");
      ObjectContent objectContent = response.Content as ObjectContent;
      if (objectContent != null && objectContent.Value is T)
      {
        value = (T) objectContent.Value;
        return true;
      }
      value = default (T);
      return false;
    }

들어오는 응답 메시지 대상에 따라 응답 메시지의 내용을 가져옵니다.
넷.WebApi 핵심 객체 HttpClient:
위에서 서버 측의 HTTP 요청을 수신하고 응답하는 조작 방법을 소개했고, 이어서 한 클라이언트가 HTTP 요청을 생성하여 서버에서 돌아오는 소식을 요청하고 가져오는 새로운 버전의NET에서는 클라이언트에서 HTTP 요청을 생성하고 가져오는 데 사용되는 클래스 HTTPClient 클래스를 제공합니다.
    1.등록 정보 요약:
BaseAddress: 요청을 보낼 때 사용하는 인터넷 자원에 대한 통일된 자원 식별자(URI)의 기본 주소를 가져오거나 설정합니다.
DefaultRequestHeaders: 각 요청에 따라 보낼 헤더를 가져옵니다.
MaxResponseContent BufferSize: 응답 내용을 읽거나 설정할 때 최대 바이트 수를 가져오거나 설정할 때 버퍼링합니다.
Timeout: 밀리초 수를 가져오거나 설정하기 전에 시간이 초과되기 전에 기다립니다.
   2.메서드 개요:
CancelPendingRequests: 이 인스턴스의 모든 미결 요청을 취소합니다.
DeleteAsync(String): DELETE 요청을 비동기식으로 지정된 URI로 보냅니다.
GetAsync(String): 지정된 URI에 GET 요청을 비동기식으로 보냅니다.
GetStreamAsync(String): GET 요청을 지정된 URI로 보내고 응답 바디를 비동기 작업 흐름으로 반환합니다.
PostAsync(String, HttpContent): POST 요청을 지정된 URI로 비동기식으로 보냅니다.
SendAsync(Http RequestMessage): 비동기식 작업으로 HTTP 요청을 보냅니다.
   3.메서드 및 속성 해석:
     (1).BaseAddress: 요청을 보낼 때 사용하는 인터넷 자원에 대한 통일된 자원 식별자(URI)의 기본 주소를 가져오거나 설정합니다.
    /// <summary>
    ///               Internet            (URI)    。
    /// </summary>
    /// <returns>
    ///    <see cref="T:System.Uri"/>。         Internet            (URI)    。
    /// </returns>
    [__DynamicallyInvokable]
    public Uri BaseAddress
    {
      [__DynamicallyInvokable] get
      {
        return this.baseAddress;
      }
      [__DynamicallyInvokable] set
      {
        HttpClient.CheckBaseAddress(value, "value");
        this.CheckDisposedOrStarted();
        if (Logging.On)
          Logging.PrintInfo(Logging.Http, (object) this, "BaseAddress: '" + (object) this.baseAddress + "'");
        this.baseAddress = value;
      }
    }

     (2).GetContentAsync: 지정된 ui에서 비동기적으로 컨텐트를 가져옵니다.
private Task<T> GetContentAsync<T>(Uri requestUri, HttpCompletionOption completionOption, T defaultValue, Func<HttpContent, Task<T>> readAs)
    {
      TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
      HttpUtilities.ContinueWithStandard<HttpResponseMessage>(this.GetAsync(requestUri, completionOption), (Action<Task<HttpResponseMessage>>) (requestTask =>
      {
        if (HttpClient.HandleRequestFaultsAndCancelation<T>(requestTask, tcs))
          return;
        HttpResponseMessage result = requestTask.Result;
        if (result.Content == null)
        {
          tcs.TrySetResult(defaultValue);
        }
        else
        {
          try
          {
            HttpUtilities.ContinueWithStandard<T>(readAs(result.Content), (Action<Task<T>>) (contentTask =>
            {
              if (HttpUtilities.HandleFaultsAndCancelation<T>((Task) contentTask, tcs))
                return;
              tcs.TrySetResult(contentTask.Result);
            }));
          }
          catch (Exception ex)
          {
            tcs.TrySetException(ex);
          }
        }
      }));
      return tcs.Task;
    }

이 방법은 get,post 요청을 생성한 후 대응하는 내용을 가져오는 비동기적인 방법입니다.TrySetResult() 메서드는 기본 System입니다.Threading.Tasks.Task`1이 RanToCompletion 상태로 변환됩니다.
     (3).SendAsync(): 비동기식으로 HTTP 요청을 보냅니다.
    /// <summary>
    ///         HTTP   。
    /// </summary>
    /// <returns>
    ///    <see cref="T:System.Threading.Tasks.Task`1"/>。           。
    /// </returns>
    /// <param name="request">     HTTP     。</param>
<param name="completionOption">
( )。</param>
<param name="cancellationToken">
</param>
<exception cref="T:System.ArgumentNullException">
<paramref name="request"/>
null。</exception>
<exception cref="T:System.InvalidOperationException">
<see cref="T:System.Net.Http.HttpClient"/></exception> [__DynamicallyInvokable] public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken) { if (request == null) throw new ArgumentNullException("request"); this.CheckDisposed(); HttpClient.CheckRequestMessage(request); this.SetOperationStarted(); this.PrepareRequestMessage(request); CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, this.pendingRequestsCts.Token); this.SetTimeout(linkedCts); TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>(); HttpUtilities.ContinueWithStandard<HttpResponseMessage>(base.SendAsync(request, linkedCts.Token), (Action<Task<HttpResponseMessage>>) (task => { try { this.DisposeRequestContent(request); if (task.IsFaulted) this.SetTaskFaulted(request, linkedCts, tcs, task.Exception.GetBaseException()); else if (task.IsCanceled) { this.SetTaskCanceled(request, linkedCts, tcs); } else { HttpResponseMessage result = task.Result; if (result == null) this.SetTaskFaulted(request, linkedCts, tcs, (Exception) new InvalidOperationException(SR.net_http_handler_noresponse)); else if (result.Content == null || completionOption == HttpCompletionOption.ResponseHeadersRead) this.SetTaskCompleted(request, linkedCts, tcs, result); else this.StartContentBuffering(request, linkedCts, tcs, result); } } catch (Exception ex) { if (Logging.On) Logging.Exception(Logging.Http, (object) this, "SendAsync", ex); tcs.TrySetException(ex); } })); return tcs.Task; }

이 방법은 비동기적으로 HTTP 요청을 보내는 방법으로 이 방법의 세 가지 매개 변수 중 Http Request Message는 http 요청 대상을 표시하고 Http Completion Option은 조작 완성 항목을 표시하며 CancellationToken은 영패를 취소한다고 표시한다.HTTP 요청을 보내기 전에 CheckRequestMessage 메서드를 호출하여 메시지를 확인합니다.비동기적인 방법을 사용할 때 조작의 취소 등 외부 요소가 방법에 미치는 영향을 고려해야 한다.
HttpClient 대상을 소개하면 HttpClient의 실제 조작에 대해 소개하지 않는다. HttpClient 대상의 사용은 매우 간단하지만 이런 종류의 밑바닥 실현은 비교적 복잡하다.   
오.요약:
본문은 상하 두 편으로 나뉘는데, 간단하게 Asp.를 소개한다.Net WebApi의 핵심 객체 및 Asp. 소개Net WebApi 라우팅 메커니즘, 처리 구조, 위탁 관리 방식 등은 부족한 점과 잘못된 점이 있으면 많이 지적해 주십시오.(내게는 드디어 다 썼으니 전편을 쓰면 하편을 써야 하니 정말 고통스럽다)

좋은 웹페이지 즐겨찾기