Can't get ASP.NET Web API 2 Help pages working when using Owin
Asked Answered
F

2

19

I've installed the correct package for Web Api 2

Install-Package Microsoft.AspNet.WebApi.HelpPage -Pre 

But the help area is not being mapped and is returning 404 (Web Api working fine). I'm using Microsoft.Owin.Host.SystemWeb as the host. Below is my Startup code.

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            //Required for MVC areas new HttpConfiguration() doesn't work with MVC
            var config = GlobalConfiguration.Configuration;

            AreaRegistration.RegisterAllAreas();

            WepApiStartup.Configure(config);

            app.UseWebApi(config);

        }
    }
Farfetched answered 20/9, 2013 at 16:8 Comment(0)
F
16

Found the solution after a lot of digging/trial and error. The issue is well described here: http://aspnetwebstack.codeplex.com/discussions/453068

UseWebApi and UseHttpMessageHandler don't call Next OWIN's middleware other than for 404. This means if you use UseWebApi that's it, Next is never called therefore you can't use it with any other middleware (Nancy or Web Api Help pages for example).

Thanks to @aliostad patch: https://github.com/aliostad/CacheCow/blob/master/samples/UsingCacheCowWithNancyAndOwin/HttpMessageHandlerAdapterModified.cs#L43

You can get it working as expected. I hope the team merge the pull request for this as UseWebApi breaks the Owin design goals IMO.

Update 13 Feb 2014

I've written an Owin extension to workaround this:

internal static void UseWebApiAndHelp(this IAppBuilder app, HttpConfiguration config)
{
    WepApiStartup.Configure(config);

    app.UseHandlerAsync((request, response, next) =>
    {
        if (request.Path == "/") //app.Map using a regex exclude list would be better here so it doesn't fire for every request
        {
            response.StatusCode = 301;
            response.SetHeader("Location", "/Help");
            return Task.FromResult(0);
        }

        return next();
    });

    // Map the help path and force next to be invoked
    app.Map("/help", appbuilder => appbuilder.UseHandlerAsync((request, response, next) => next()));

    app.UseWebApi(config);    
}

Update 01 July 2015

You can also host the help pages using WebApi instead of MVC, which is great for self host http://blogs.msdn.com/b/yaohuang1/archive/2012/12/20/making-asp-net-web-api-help-page-work-on-self-hosted-services.aspx

Update 10 September 2015

For Web Api I tried @hongye-sun answer and it works too, follow what @gspatel says by changing HelpPageAreaRegistration.RegisterArea and the HelpController's constructor. My workaround works as well so pick whatever one works best for your situation.

However I'm still getting the issue when using UseWebApi with other middleware and it not invoking Next() (seems to only happen when using IIS not self host). I've found my workaround of mapping the path and forcing next to be invoked is a valid workaround for all Owin middleware Nancy, Simple.Web etc.

Update 13 Jan 2016

I've developed Owin middleware to generate the ASP.NET Web API Help pages we know and love that completely solves this problem. My blog post explains the background to this issue in detail

Farfetched answered 27/9, 2013 at 18:14 Comment(3)
It appears this still hasn't been fixed. Any good work around ?Nabonidus
I couldn't find app.UseHandlerAsync, so I used app.Use((context, next) => ... instead.Sauerbraten
Sorry you need to: Install-Package Owin.ExtensionsFarfetched
O
32

GlobalConfiguration.Configuration is web host specific HttpConfiguraiton, which should only be used with web host scenario. Use it with OWIN host will cause unexpected issues.

Please use the following code instead:

public class Startup
{
    public static HttpConfiguration HttpConfiguration { get; private set; }

    public void Configuration(IAppBuilder app)
    {
        HttpConfiguration = new HttpConfiguration();

        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(HttpConfiguration);

        app.UseWebApi(HttpConfiguration);
    }
}

Replace all GlobalConfiguration.Configuration with Startup.HttpConfiguration in the project include help page files.

Oden answered 20/9, 2013 at 17:50 Comment(4)
This certainly works for something like this: cfg.Services.Replace(typeof(IHttpControllerActivator), new CompositionRoot()); Thank you very much!Morel
There are only two places needing to be replaced in Help: HelpPageAreaRegistration.RegisterArea and HelpController's constructor. Worked like a charm.Past
As @Past said this works if you pass it to HelpPageAreaRegistration.RegisterArea and expose your HttpConfiguration in a static property in your Startup class, so you can pass it to the HelpController's constructor too.Farfetched
@Hongye Sun Think you've just saved my dissertation project for my degree, had this issue and noone else had the solution. Cheers!Samualsamuel
F
16

Found the solution after a lot of digging/trial and error. The issue is well described here: http://aspnetwebstack.codeplex.com/discussions/453068

UseWebApi and UseHttpMessageHandler don't call Next OWIN's middleware other than for 404. This means if you use UseWebApi that's it, Next is never called therefore you can't use it with any other middleware (Nancy or Web Api Help pages for example).

Thanks to @aliostad patch: https://github.com/aliostad/CacheCow/blob/master/samples/UsingCacheCowWithNancyAndOwin/HttpMessageHandlerAdapterModified.cs#L43

You can get it working as expected. I hope the team merge the pull request for this as UseWebApi breaks the Owin design goals IMO.

Update 13 Feb 2014

I've written an Owin extension to workaround this:

internal static void UseWebApiAndHelp(this IAppBuilder app, HttpConfiguration config)
{
    WepApiStartup.Configure(config);

    app.UseHandlerAsync((request, response, next) =>
    {
        if (request.Path == "/") //app.Map using a regex exclude list would be better here so it doesn't fire for every request
        {
            response.StatusCode = 301;
            response.SetHeader("Location", "/Help");
            return Task.FromResult(0);
        }

        return next();
    });

    // Map the help path and force next to be invoked
    app.Map("/help", appbuilder => appbuilder.UseHandlerAsync((request, response, next) => next()));

    app.UseWebApi(config);    
}

Update 01 July 2015

You can also host the help pages using WebApi instead of MVC, which is great for self host http://blogs.msdn.com/b/yaohuang1/archive/2012/12/20/making-asp-net-web-api-help-page-work-on-self-hosted-services.aspx

Update 10 September 2015

For Web Api I tried @hongye-sun answer and it works too, follow what @gspatel says by changing HelpPageAreaRegistration.RegisterArea and the HelpController's constructor. My workaround works as well so pick whatever one works best for your situation.

However I'm still getting the issue when using UseWebApi with other middleware and it not invoking Next() (seems to only happen when using IIS not self host). I've found my workaround of mapping the path and forcing next to be invoked is a valid workaround for all Owin middleware Nancy, Simple.Web etc.

Update 13 Jan 2016

I've developed Owin middleware to generate the ASP.NET Web API Help pages we know and love that completely solves this problem. My blog post explains the background to this issue in detail

Farfetched answered 27/9, 2013 at 18:14 Comment(3)
It appears this still hasn't been fixed. Any good work around ?Nabonidus
I couldn't find app.UseHandlerAsync, so I used app.Use((context, next) => ... instead.Sauerbraten
Sorry you need to: Install-Package Owin.ExtensionsFarfetched

© 2022 - 2024 — McMap. All rights reserved.