Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

web-api & swagger documentation

I've written a asp web-api and I've added versioning to the api using this class.

My routes look like this:

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

config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config));

So I can access https://localhost:44301/v1/test

I'm now trying to add Swagger to produce some api documentation (actually I'm using the Swashbuckle Nuget package)

When I browse to /swagger the page loads but comes up with errors for all the controllers:

Unable to read api 'TestController' from path https://localhost:44301/swagger/api-docs/TestController (server returned undefined)

If I browse to https://localhost:44301/swagger/api-docs/TestController it comes up with a NullReferenceException with a stack trace of:

at Swashbuckle.Swagger.OperationGenerator.CreateParameter(ApiParameterDescription apiParamDesc, String apiPath)
   at Swashbuckle.Swagger.OperationGenerator.<>c__DisplayClass2.<ApiDescriptionToOperation>b__1(ApiParameterDescription paramDesc)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Swashbuckle.Swagger.OperationGenerator.ApiDescriptionToOperation(ApiDescription apiDescription)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Swashbuckle.Swagger.ApiExplorerAdapter.CreateApi(IGrouping`2 apiDescriptionGroup, OperationGenerator operationGenerator)
   at Swashbuckle.Swagger.ApiExplorerAdapter.<>c__DisplayClassb.<GetDeclaration>b__7(IGrouping`2 apiDescGrp)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Swashbuckle.Swagger.ApiExplorerAdapter.GetDeclaration(String basePath, String version, String resourceName)
   at Swashbuckle.Application.CachingSwaggerProvider.<>c__DisplayClass4.<GetDeclaration>b__3(String k)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Swashbuckle.Application.CachingSwaggerProvider.GetDeclaration(String basePath, String version, String resourceName)
   at Swashbuckle.Application.SwaggerSpecHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.HttpServer.<>n__FabricatedMethod9(HttpRequestMessage , CancellationToken )
   at System.Web.Http.HttpServer.<SendAsync>d__0.MoveNext()

If I change the route to this:

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

The Swagger pages then work, but the actual api doesn't!

So the question is, how can I make Swagger work with a versioned api?

like image 933
Paul Avatar asked Nov 22 '22 16:11

Paul


1 Answers

In the end I used SDammann.WebApi.Versioning nuget package and the following routes:

VersionedControllerSelector.VersionPrefix = "v";

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

My controllers are in a namespace called v1 or v2 etc.

like image 134
Paul Avatar answered Nov 25 '22 05:11

Paul