2
votes

I am using Microsoft.Owin.Hosting in my one of integration test project to self-host the Web API in order to test end to end functionality.

[TestMethod]
public void GetLoanApplications()
{
    using (WebApp.Start<Startup>(url: url))
    {
        using (var client = new HttpClient())
        {
            // Create httpclient and send request-and-response-metadata-in-aspnet-web-api
        }
    }
}

I am able to self-host the web API and able to invoke the controller action. Owin requires some Startup class configuration, which is as follows:

[assembly: OwinStartup(typeof(MyService.App_Start.Startup))]
namespace MyService.App_Start
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
            app.UseWebApi(config);
        }
    }
}

Here is my Web API Config method looks like:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
    }
}

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );            
    }
}

Problem

  • When I run my main application (not the test project) both the Owin startup and web API config methods are getting called.
  • Let's say if I have some services or filters to be configured, it will get invoked twice.
  • What I thought is IF I am running test project it should only invoke owin startup file (which it is doing right now) and when I am debugging my main app it should only call web API config register method.

Any idea on is this the way it should work or I am doing something wrong?

2
that is by design. move the code from Application_Start into owin start up. - Nkosi
Is the production code intended to be self-hosted or IIS? What is the role of OWIN in the intended system? - Nkosi
@Nkosi I have used OWIN for the integration testing only. Its allowing us to self host Web Api through which we can write and test end to end integration testing. In production we would be using IIS for hosting. - Shaggy
Provided a suggestion based on how I've dealt with a similar situation in the past. - Nkosi

2 Answers

4
votes

First the system would need a way to differentiate between the environments.

<appSettings>
    <add key="APP_ENVIRONMENT" value="Development" />
    <!-- ... -->
</appSettings>

Since when run in production both the Owin startup and web api config methods are getting called then OWIN is already configured as a first class citizen in the project.

I suggest moving the code from Application_Start into owin start up

public class WebApiApplication : System.Web.HttpApplication {
    protected void Application_Start() {
        //REMOVE THIS AND LET OWIN STARTUP HANDLE SETUP
        //GlobalConfiguration.Configure(WebApiConfig.Register);
    }
}

so that it is only invoked once depending on the configured environment.

[assembly: OwinStartup(typeof(MyService.App_Start.Startup))]
namespace MyService.App_Start {
    public class Startup {
        const string EnvironmentKey = "APP_ENVIRONMENT";
        const string PRODUCTION = "Production";
        const string TEST = "Test";

        public void Configuration(IAppBuilder app) {
            string ENVIRONMENT = ConfigurationManager.AppSettings[EnvironmentKey] 
                                    ?? Production;
            if(ENVIRONMENT == TEST) {
                var config = new HttpConfiguration();
                WebApiConfig.Register(config);
                app.UseWebApi(config);
            } else {
                GlobalConfiguration.Configure(WebApiConfig.Register);
            }
        }
    }
}

Note the reuse of the WebApiConfig.Register to avoid repeated code. The same configuration will be applied for either environment and all in the same place if additional configurations were to be implemented (ie Development, Testing, Staging, Procustion...etc)

The test project app.config would include the current environment's setting

<appSettings>
    <add key="APP_ENVIRONMENT" value="Test" />
    <!-- ... -->
</appSettings>

and invoke the start up configuration for self-hosting otherwise it will default back to production settings, but would have also been configured in the web.config

<appSettings>
    <add key="APP_ENVIRONMENT" value="Production" />
    <!-- ... -->
</appSettings>
1
votes

You need to chose between init your web api from the OWIN pipeline or with the old method in the Application_Start, see the application lifecycle.

If you keep Application_Start and OwinSartup then your web api is initialized twice