5

I am trying to get NSwag setup on a new Web API project using OWIN with no luck. I am wondering if the docs aren't mentioning something or I've missed a step. I'm following the instructions from the Middlewares Wiki, but when I load the default swagger endpoint I just get a 404.

Is there something I need to do to generate the content that should be at that location? I've been assuming the middleware handles that.

Does NSwag require MVC to be a part of your project? Will it work in an app that is just Web API?

I've checked out the sample projects but neither of them use OWIN with ASP.NET Web API 2. There is only a global.asax example, and a .Net Core example.

You can easily reproduce my issue if you like. Simply create a new ASP.NET Web Application using the OWIN Web API Starter Template and then perform the setup from the Middlewares Wiki. (When you create a new project there's a link near the bottom of the Add New Project wizard: Click here to go online and find templates.. Click that and search for "OWIN Web API Starter Template".

Please let me know if I should provide more detail. Other than posting a bunch of code, that starter project should allow you to reproduce my issue in 5-10 minutes.

Thanks!

mikesigs
  • 10,491
  • 3
  • 33
  • 40
  • MVC is noz needed. I think IIS handles the .json url as static file and does not call the middleware... I think you need to disable the static file handler globally or for the swagger route... – Rico Suter Dec 14 '16 at 21:17

2 Answers2

3

Hope this helps, works for me:

  1. clone https://github.com/NSwag/Samples

  2. open solution, I used VS2015 update 3

  3. create a new Owin MVC project add new "ASP.Net web applation (.Net Framework)" project to solution; I called it: SampleOwinWebApiWithSwaggerUi ... use the default MVC project template (MVC checkbox is checked), also check the "Web API" checkbox. Change authentication, select no authentication, click OK. Right click the new project and select "Set as Startup Project"

  4. add nuget package ... right click the new SampleOwinWebApiWithSwaggerUi project, click Manage NuGet packages. Add this package: Microsoft.AspNet.WebApi.Owin (adds other dependencies including Owin + Microsoft.Owin + Microsoft.AspNet.WebApi.Owin for you too)

  5. add a web api controller ... I re-used the PersonController.cs and it's associated model Persons.cs from the SampleWebApiWithSwaggerUi project, added controller to a new folder ./api under ./Controllers and just updated namespaces and using statements from 'SampleWebApiWithSwaggerUi' to 'SampleOwinWebApiWithSwaggerUi'

  6. Added an Owin startup.cs file, right-click SampleOwinWebApiWithSwaggerUi project, add new, enter 'owin' in the search box, select OWIN Startup class, change the default name from Startup1.cs to Startup.cs, click Add

  7. Add 'NSwag.AspNet.Owin' NuGet package ... again this adds other packages and updates, as required.

  8. Add 'Microsoft.Owin.Host.SystemWeb' NuGet package

  9. update Startup.cs, adding the following lines:

    // from https://github.com/NSwag/NSwag/wiki/Middlewares
    var config = new HttpConfiguration(); app.UseSwaggerUi(typeof(Startup).Assembly, new SwaggerUiOwinSettings()); app.UseWebApi(config); config.MapHttpAttributeRoutes(); config.EnsureInitialized();

as you add these, you will need to add the following dependencies to usings:

using System.Web.Http;
using NSwag.AspNet.Owin;
  1. update web.config, section

I changed from

<system.webServer>
    <handlers>
        <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
        <remove name="OPTIONSVerbHandler" />
        <remove name="TRACEVerbHandler" />
        <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer>

to:

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true" />
    <handlers>
        <clear />
        <add name="Owin" verb="" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb" />
        <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
        <remove name="OPTIONSVerbHandler" />
        <remove name="TRACEVerbHandler" />
        <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
        <add name="SwaggerIndex" path="swagger/index.html" verb="*" type="NSwag.AspNet.Owin.SwaggerUiIndexMiddleware" />
        <add name="SwaggerGenerator" path="swagger/v1/swagger.json" verb="*" type="NSwag.AspNet.Owin.SwaggerMiddleware" />
        <add name="SwaggerRedirect" path="swagger" verb="*" type="NSwag.AspNet.Owin.RedirectMiddleware" />
    </handlers>
</system.webServer>

NOTE: I did not follow advice here https://github.com/NSwag/NSwag/wiki/OwinGlobalAsax as this failed for me:

<appSettings>
    <add key="owin:AutomaticAppStartup" value="false" />
</appSettings>

since we do want the Owin startup.cs to load.

  1. At this point you should be able to use /swagger, web api data ok, however static files such as bootstrap.css are not served for MVC pages. To fix this I followed advice here: https://stackoverflow.com/a/36297940/445927 though I changed the physicalFileSystem root, as below. This additional code should be added to the end of startup.cs, after swagger additions noted above.

// to serve static files, see: https://stackoverflow.com/a/36297940/445927

string root = AppDomain.CurrentDomain.BaseDirectory;
//var physicalFileSystem = new PhysicalFileSystem(Path.Combine(root, "wwwroot"));
var physicalFileSystem = new PhysicalFileSystem(root));
var options = new FileServerOptions
{
    RequestPath = PathString.Empty,
    EnableDefaultFiles = true,
    FileSystem = physicalFileSystem
};
options.StaticFileOptions.FileSystem = physicalFileSystem;
options.StaticFileOptions.ServeUnknownFileTypes = false;
app.UseFileServer(options);

Finally you should have ASP.Net MVC (with static files), Web API and Swagger all working.

Update: Rico has now merged into main repo: https://github.com/NSwag/Samples

Community
  • 1
  • 1
2

The solution posted by @RobertDyball is needlessly complex. By default, the StaticFile handler is the last handler to be executed. This means that simply intercepting all NSwag requests is enough:

<add name="NSwag" path="swagger" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

This also used to be the recommended method by Swashbuckle, until it switched to extensionless URLs. You may notice that ASP.NET is able to handle extensionless URLs with the same type of handler in <add name="ExtensionlessUrlHandler-Integrated-4.0".

user247702
  • 23,641
  • 15
  • 110
  • 157