1

我正在使用HttpClient(又名 Web API 客户端)来使用 RESTfull 服务。服务需要在每次操作时建立(通过登录)然后销毁(通过注销)会话。所以调用服务 A 看起来像这样(伪代码)

// setup
create auth dictionary authDict
create authenticationContent using FormUrlEndodeContent(authDict)
create cookieContainer
create HttpClientHandler...
create HttpClient

// login
await httpClient.PostAsync(LoginUrl, authenticationContent);
do error checking

// perform Operation A
await httpClient.....post...or...get...
extract data, process it, tranform it, get a cup of coffee, etc, etc
populate OperationAResult

// logout
await httpClient.GetAsync(LogoutUrl);

// return result
return OperationAResult

我的问题是,我怎样才能轻松地为不同的操作重用设置、登录和注销?我是否应该创建一些将采用 Action<> 的方法,如果是这样,我如何确保操作按顺序发生?

4

2 回答 2

1

可能最简单的方法就是编写一个包装类。

public class MyHttpClient
{
  private HttpClient _client = new HttpClient();
  private MyHttpClientSetup _setup;

  public MyHttpClient(MyHttpClientSetup setup)
  {
    this._setup = setup;
  }

  private void HttpLogin() 
  { 
    // .. custom login stuff that uses this._setup
  }     

  private void HttpLogout() 
  { 
    // .. custom logout stuff that uses this._setup
  }     

  public void Reset()
  {
    this._client = new HttpClient();
  }

  // Wrapped Properties from the private HttpClient (1 example)
  public Uri BaseAddress 
  { 
    get{ return this._client.BaseAddress;} 
    set{ this._client.BaseAddress = value;} 
  }

  // Wrapped HttpMethods (1 example)
  // Extremely poorly written, should be delegated properly
  // This is just a bad example not using Task properly
  public Task<HttpResponseMessage> DeleteAsync(string requestUri)
  {
    this.HttpLogin();
    Task<HttpResponseMessage> result = this._client.DeleteAsync(requestUri);
    this.HttpLogout();
    return result;
  }


  public class MyHttpClientSetup
  {
    // Properties required for setup;
  }
}
于 2012-10-24T01:32:28.203 回答
1

您也许可以创建一个新的 MessageHandler 来透明地为您处理这些东西。

public class ConnectionHandler : DelegatingHandler {

        public HttpClient HttpClient {get;set;}

        public TestHandler(HttpMessageHandler handler) {
            this.InnerHandler = handler;
        }
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            // Do your login stuff here
            return base.SendAsync(request, cancellationToken)  // Make your actual request
              .ContinueWith(t => {
                            // Do your logout stuff here
                            } 
        }
    }

然后,您可以只使用 HttpClient 的单个实例来执行所有请求。要将处理程序添加到请求/响应管道,您只需创建一个常规 HttpClientHandler,将其分配给 DelegatingHandler 的 InnerHandler 属性,然后将新处理程序传递给 HttpClient 的构造函数。从那时起,所有通过 HttpClient 发出的请求都将通过您的 ConnnectionHandler 进行路由。

  var connectionHandler = new ConnectionHandler(new HttpClientHandler());
  var client = new HttpClient(connectionHandler);
  connectionHandler.HttpClient = client;

  var response = client.GetAsync("http://example.org/request").Result;

使用单个 HttpClient 实例的优点是您不必不断重新指定 DefaultRequestHeaders。此外,处理 HttpClient 将终止 TCP 连接,因此下一个请求将不得不重新打开它。

于 2012-10-24T01:46:50.680 回答