HttpClient with asp.net WebApi in unit testing sce

2019-03-13 09:01发布

问题:

I have an integration test which I wanted to use as the basis of testing my WebAPI controllers with.

Initially I thought I would have to set-up WebAPI in self-host mode and carry-out end-to-end tests over local Http.

However I realised later by looking at the tests in the WebApiContrib project that its possible to set up an HttpClient with an HttpServer set-up with the correct service route to the WebAPI controller. I seems I can unit test the controllers without setting up WebApi in self-host mode. I can put in any domain name in the request on the client and HttpClient seems to auto-magically bind to the correct controller.

Is there any Http transport happening here, using some local interprocess comms or purely 'seeing' that the server is in the same app domain and thus using reflection? What is happening under the hood for this to happen?

code:

[Test]
public void Test_WebApi_Controller()
{
    Assembly.Load("myproj.Web");

    var prodServiceMock = new Mock<IProductService>();
    ObjectFactory.Initialize(x => x.For<IProductService>().Use(prodServiceMock.Object));                      

    var config = new HttpConfiguration();
    config.Routes.MapHttpRoute("default", "webapi/{controller}/{id}", new { id = RouteParameter.Optional });
    config.ServiceResolver.SetResolver(new WebApiDependencyResolver());

    var server = new HttpServer(config);
    var client = new HttpClient(server);

    var response = client.GetAsync("http://anything.com/webapi/product").Result;

}

回答1:

HttpClient has a pluggable pipeline model. Normally when you new up a HttpClient you get a HttpClientHandler instance as the default request processor. That HttpClientHandler is the one actually does the HttpWebRequest. HttpClientHandler derives from HttpMessageHandler.

By no concidence HttpServer also derives from HttpMessageHandler. So in this example the HttpServer is being passed to the HttpClient instance to provide it's request processing. By passing a HttpMessageHandler to the constructor of HttpClient you are telling HttpClient to use the provided handler instead of the default one. If you look at WebRequestHandler in System.Net.Http.WebRequest you will see this is derived from HttpClientHandler and adds some extra functionality that is specific to the Windows Desktop OS.

This means when you make a request to the HTTPClient it is delivered directly to the HttpServer message handler and then processed as it normally would be on the server.