HttpClient with asp.net WebApi in unit testing scenario - asp.net-web-api

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

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.

Related

'X-Appengine-Inbound-Appid' header is not set when using Spring RestTemplate

I have two services running on the Google App Engine (MS1 & MS2). MS1 is deployed in the Standard Environment and MS2 is deployed in the Flexible Environment. I am invoking an API from Standard Environment to the Flexible Environment. I want to make sure that MS2 only accepts requests originating from MS1. So, I decided to use this feature from App Engine. I am setting the X-Appengine-Inbound-Appid header and setInstanceFollowRedirects to false in MS1, but looks like App Engine is removing this header. I am not able to find this header in MS2.
HttpHeaders headers = new HttpHeaders();
headers.add("X-Appengine-Inbound-Appid", ApiProxy.getCurrentEnvironment().getAppId());
HttpEntity<MergePdfsResource> entity = new HttpEntity<MergePdfsResource>(mergePdfsResource, headers);
restTemplate.setRequestFactory(new SimpleClientHttpRequestFactory() {
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
super.prepareConnection(connection, httpMethod);
connection.setInstanceFollowRedirects(false);
}
});
ResponseEntity<SomeClass> response = restTemplate.postForEntity(apiUrl, entity, SomeClass.class);
Following is the answer I got from the Google Support:
The X-Appengine-Inbound-Appid header is set only if we are using the URLFetch service. In the java8 runtime environment, the default is native which uses the standard Java network classes. So, I had to set the URL stream handler to urlfetch in appengine-web.xml as below:
<url-stream-handler>urlfetch</url-stream-handler>

How to pass a web socket handler instance instead of class

I'm working with embedded Jetty websockets and what I see in the examples is passing the Class of the handler to the container instead of an instance. I would to know if it's possible to pass an instance instead of a class and how that works.
ServerContainer wscontainer = webSocketServerContainerInitializer.configureContext(context);
// Add WebSocket endpoint to javax.websocket layer
wscontainer.addEndpoint(EventSocket.class);
I would like to be able to do
wscontainer.addEndpoint(new EventSocket());
of course this method is not supported.
I see that on the client side you can provide an instance of a handler
Session session = container.connectToServer(new ClientSocket(), uri);
I'm curious why the api was designed to accept a class instead of an instance, which is unlike how servlets work.
Update:
The following solution works:
// contains ServerEndpoint annotation and onMessage, onOpen etc
final EventSocket eventSocket = new EventSocket();
ServerEndpointConfig config = ServerEndpointConfig.Builder.create(eventSocket.getClass(), eventSocket.getClass().getAnnotation(ServerEndpoint.class).value())
.configurator(new Configurator() {
#Override
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
return (T) eventSocket;
}
})
.build();
wscontainer.addEndpoint(config);
In servlets, you have 1 instance for all requests to the same servlet.
In a websocket server, you have long lived connections, and the normal technique is to have a new websocket endpoint instance per connection. In websocket clients, you don't have to worry about this. You are just 1 instance to start with. If you want multiple connections, you have multiple instances of that websocket endpoint that you created yourself.
ServerContainer is a javax.websocket.server.ServerContainer (aka JSR-356).
It has 2 addEndpoint() mechanisms:
addEndpoint(Class<?> endpointClass) assumes that the class either extends from Endpoint or is annotated with #ServerEndpoint (yes, you can have server that doesn't initialize via annotation scanning, but still uses annotations and this addEndpoint mechanism to programatically add endpoints). It assumes that the server will instantiate a new Endpoint on each incoming websocket upgrade request.
addEndpoint(ServerEndpointConfig serverConfig) takes a ServerEndpointConfig that declares how you want your endpoint to bound. It too assumes that the server will instantiate a new Endpoint on each incoming websocket upgrade request. However, there is way out using this technique. Define your own Configurator object that overrides the getEndpointInstance(Class<?> endpointClass) method, returning the same object over and over again. Just note that the instance you return must be of the class type that was passed into that method (otherwise its an error).
If you choose to use the jetty native websocket implementation, then you can also use the WebSocketCreator to handle the creation of websocket instances, even singletons.

How do I register a custom IHttpModule with HttpServer

I am using the HttpServer class to test my web api. In my application, I have a custom IHttpModule that handles some URL rewriting. I need this module to process the requests for my web api as well. Here is my code that I use to create the HttpServer object.
var config = new HttpSelfHostConfiguration(ServerUrl);
RouteConfig.RegisterRoutes(config.Routes);
FilterConfig.RegisterWebApiFilters(config.Filters);
var httpServer = new HttpServer(config);
Can someone tell me the obvious thing I am missing that I need to do to register my module with the server?
AFAIK you can't use HttpModules with a self hosted WebAPI server. I think what you need is a MessageHandler.
Http Message Handlers
DelegatingHandler (MSDN)

The request lifetime scope cannot be created because the HttpContext is not available

Having a hard time trying to setup AutoFac with some async non httprequest.
I have the following on App_Start
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<sfEntities>().As<IUnitOfWork>().InstancePerHttpRequest();
builder.RegisterGeneric(typeof(sfRepository<>)).As(typeof(IRepository<>)).InstancePerHttpRequest();
builder.RegisterGeneric(typeof(BaseServices<>)).As(typeof(IBaseServices<>)).InstancePerHttpRequest();
builder.RegisterType<EmailServices>().As<IEmailServices>().InstancePerHttpRequest();
builder.RegisterType<UserServices>().As<IUserServices>().InstancePerHttpRequest();
builder.RegisterType<ChatServices>().As<IChatServices>().InstancePerHttpRequest();
builder.RegisterType<DefaultFormsAuthentication>();
builder.RegisterType<WebSecurity>();
builder.RegisterType<Chat>();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
If I change to InstancePerLifetimeScope() I get problems with UnitofWork.SaveChanges(). Setup this way works fine except for async calls.
p.s.: UnitOfWork pass the EF DbContext between services to ensure that the same instance is used and to dispose properly. If I change to InstancePerLifetimeScope I was getting identity conflicts when calling .SaveChanges(), probably because there should be more than one instance of UnitOfWork.
The following code throws the following exception:
Timer timer = new Timer(new TimerCallback(OnTimer), null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
private static void OnTimer(object o)
{
using (var timerScope = AutofacDependencyResolver.Current.ApplicationContainer.BeginLifetimeScope())
{
var chatServices = timerScope.Resolve<IChatServices>();
chatServices.MarkInactiveUsers();
}
}
No scope with a Tag matching 'httpRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being reqested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
On SignalR, the following code throws the following exception:
SignalR.GlobalHost.DependencyResolver.Register(typeof(Chat), () => new Chat(DependencyResolver.Current.GetService<IUnitOfWork>(), DependencyResolver.Current.GetService<IChatServices>(), DependencyResolver.Current.GetService<IUserServices>()));
The request lifetime scope cannot be created because the HttpContext is not available
Thanks in advance!
Having a hard time trying to setup AutoFac with some async non httprequest.
For non-http requests, or more specifically, for non-ASP.NET pipeline requests (like WCF or ServiceStack), you should definitely change all InstancePerHttpRequest() code to InstancePerLifetimeScope(). You can and should do this because InstancePerLifetimeScope() will make it resolvable in both ASP.NET pipeline and non-ASP.NET pipeline contexts.
If I change to InstancePerLifetimeScope() I get problems with UnitofWork.SaveChanges(). Setup this way works fine except for async calls... If I change to InstancePerLifetimeScope I was getting identity conflicts when calling .SaveChanges(), probably because there should be more than one instance of UnitOfWork.
Yes, there should be more than one instance of UnitOfWork, but you can achieve that with a single registration that should be scoped to InstancePerLifetimeScope():
Example:
builder.RegisterType<NhUnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
The IChatServices service is registered as InstancePerHttpRequest and will therefore only be available within the http request lifetime scope. You are resolving from the application scope which have no "access" to the current request and therefore fail with the error you mention. So yes, to get the timer to work you must register the service in the application scope.
Basically, you can have request scoped services that access application scoped services, but not the other way around.
Question is: what is UnitOfWork.SaveChanges do and what "problems" do you get? Please elaborate.

JerseyClient using DefaultHttpClient

I need to access a JAX-WS webservice protected by SSL using Jersey Client. I have successfully got this working with limited configuration and just letting the Client use the default HTTPURLConnection API.
This approach wont work however for my overall solution because it does not allow me the flexibility to change the credentials used when making a request to the WS. I'm trying to use DefaultHTTPClient instead and then passing it to the Client object on intialization.
NTCredentials credentials = new NTCredentials("username", "password",
computerName, domainName);
DefaultHttpClient httpClienttemp = new DefaultHttpClient();
DefaultHttpClient httpClient = wrapClient(httpClienttemp);
httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, credentials );
ClientConfig config = new DefaultClientConfig();
The wrapClient method creates an X509TrustManager and overrides the necessary methods so that all certificates are accepted. It also creates a SchemeRegistry entry for https access on port 443. This configuration results in a Connection refused exception.
The strange thing is, if i add an additional entry in the SchemeRegistry for http and give it a port of 443 then the request does get sent however a Connection Reset exception then gets thrown.
The Url i use to create the WebResource object is https however the SOAPAction i declare in the header uses http. Any ideas where im going wrong?
This is a limitation of the default HTTP Client (com.sun.jersey.api.client.Client) documented in the Jersey docs. You will have to use Apache HTTP Client to achieve this functionality.
Looks like someone already recommended doing this in the answer to your previous question: Jersey Client API - authentication.
EDIT: Corrected reference to the default Jersey HTTP Client to avoid confusion.

Resources