Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Ingredients for Well-Designed OWIN Middleware Components (Part 3)

DZone's Guide to

Ingredients for Well-Designed OWIN Middleware Components (Part 3)

Now that you've learned about decoupling the pipeline, learn more about testing with OWIN middleware.

· Integration Zone
Free Resource

Learn how API management supports better integration in Achieving Enterprise Agility with Microservices and API Management, brought to you in partnership with 3scale

In my last post, I talked about decoupling the construction of the OWIN pipeline from the definition of the OWIN middleware component. In this post, I'm going to talk about the next ingredient, the testing story.

Ingredient 4: Testing your entire HTTP pipeline

In most projects that are building ASP.NET MVC or WebAPI controllers, I've observed two testing strategies:

  1. Test the controller class directly by passing in strongly typed message objects and analyzing the resulting objects.
  2. Keep the controller code as thin as possible and test the underlying service code.

There used to be a WebAPI self-host that you could use from inside your unit test, but it still requires an actual network port. Although slow, it can work, provided that you don't run your unit tests in parallel (the default for XUnit 2).

The beauty of OWIN is that it doesn't have a direct dependency on an actual network stack. It just defines an abstraction based on simple types like dictionaries, tasks and funcs. It's Microsoft's Katana that provides an IIS host, a console host and even a Windows Service host. So ideally, your unit test could cover the entire OWIN pipeline without the need of real network ports, nor has any restrictions when they run in parallel with other unit tests. If you use OWIN, I wrote a unit test that asserts that Piercer returns its own assemblies when run from inside the unit test runner AppDomain like this.

 [Fact]
public async Task When_specifying_an_explicit_route_it_should_be_reachable_through_that_route()
{
    var appBuilder = new AppBuilder();
    appBuilder.UsePiercer(new PiercerSettings().AtRoute("/myroute"));
    AppFunc app = appBuilder.Build();

    var httpClient = new HttpClient(new OwinHttpMessageHandler(appFunc));

    var result = await httpClient
      .GetStringAsync("http://localhost/myroute/piercer/assemblies");

    result.Should().Contain("Piercer.Middleware");
}

Using an independent AppBuilder allows you to build an in-memory OWIN pipeline accessible through an AppFunc. To send actual HTTP requests into that pipeline from a typical HttpClient object, you can use a nifty little library created by Damian Hickey, the OwinHttpMessageHandler. It will convert the HttpRequestMessage objects that the HttpClient client sends into the dictionary that the AppFunc expects, all without ever touching a network stack. You can check out its implementation here.

So imagine you're writing a middleware component that needs to communicate with the outside world. I assume you would probably add a property or method to your middleware's settings class (like PiercerSettings) taking the URL to communicate with. Well, don't do that. Instead, either take an HttpClient or a Uri and an optional HttpMessageHandler instance. If you take that optional HttpMessageHandler, callers can either pass in the actual URL to connect to or the aforementioned OwinHttpMessageHandler like this:

 appBuilder.UsePiercer(new PiercerSettings()
.ConnectingTo(new Uri("http://localhost"));

Or within unit tests:

appBuilder.UsePiercer(new PiercerSettings()
.ConnectingTo(new Uri("http://localhost", new OwinHttpMessageHandler(appFunc))
);

The definition of the ConnectingTo method might look like this:

public PiercerSettings ConnectingTo(Uri uri, HttpMessageHandler handler = null)
{
httpClient = new HttpClient(handler ?? new HttpClientHandler())
{
BaseAddress = uri
};

return this;
}

Now assume that within your unit test, the component that you're connecting to should also be hosted on the same AppBuilder. You can't pass in the AppFunc until you've completed building the pipeline, so we're at a kind of stand-off here. You can fix that by relying on the delayed execution of lambda expressions. Just redefine the ConnectingTo method so that it takes a Func:

 public PiercerSettings ConnectingTo(Uri uri, Func handlerFunc = null) { }

Then, you can do this:

AppFunc appFunc = null;

appBuilder.UsePiercer(new PiercerSettings()
.ConnectingTo(() => new OwinHttpMessageHandler(appFunc));

appBuilder.UseOtherService();

appFunc = appBuilder.Build();

The only caveat is that your middleware component shouldn't try to access the other service until the OWIN pipeline has been fully build. If that doesn't happen until your component is receiving its first HTTP request, you'll be fine. But if your component is doing some kind of background processing, you'll have to delay that explicitly, something I'll discuss in the next ingredient.

Unleash the power of your APIs with future-proof API management - Create your account and start your free trial today, brought to you in partnership with 3scale.

Topics:
middleware ,owin ,testing ,integration ,.NET

Published at DZone with permission of Dennis Doomen, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}