I'd like to add caching of the swagger.json, and in the previous version (https://github.com/domaindrivendev/Swashbuckle/blob/master/Swashbuckle.Dummy.Core/App_Start/CachingSwaggerProvider.cs), you added a customprovider to achive this.
Is there a way in the AspNetCore version to do this?
Have you taken a look at the Response Caching middleware (https://docs.microsoft.com/en-us/aspnet/core/performance/caching/middleware) that ships with AspNet Core?
I'm more than happy to add the custom provider functionality back if necessary but would favor leveraging the framework for cross-cutting concerns like caching if it fits. Take a look and let me know. Thanks
Thanks, the middleware works nicely!
@ErlendSB do you know of any examples on how to enable this for Swashbuckle please?
@domaindrivendev the middle ware caching is client side cache headers i believe? how would we be able to do caching on server side?
any help would be much appreciated.
@ErlendSB, could you post a snippet?
The caching is helping a bit, but I believe the number of DOM elements are the biggest performance issue.
I hope/think swagger-ui 3.x will do this differently.
public void ConfigureServices(IServiceCollection services)
{
services.AddResponseCaching();
...
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseResponseCaching();
...
}
@ErlendSB I was under the impression that the caching middleware enables client side caching (caching in the user's browser, proxies, etc)? I'd like to cache the generated swagger doc on server side so it doesn't have to be generated for each user.
This was extremely simple by using a custom ISwaggerProvider. But now all that stuff is internalized :(
@domaindrivendev Do you have any suggestions on my requirement? I also tried creating a decorator for the ISwaggerProvider using SimpleInjector but it doesn't seem possible with the separation of configuring services and app builder. (container cross wiring would need to be done before re-registering the new swagger provider decorator with the service collection).
For posterity here is a way to achieve the CachedProvider functionality in Swashbuckle.AspNetCore:
In Startup.cs
services.AddSwaggerGen(); // Keep empty and always call before line below
services.AddCachedSwaggerGen(options =>
{ /*... your normal config ...*/ });
Provide the new extension method, to overwrite the previously registered ISwaggerProvider in the DI
public static class CachedSwaggerProviderExtensions
{
public static IServiceCollection AddCachedSwaggerGen(
this IServiceCollection services,
Action<SwaggerGenOptions> setupAction = null)
{
// Overwrite the built in swagger generator with our cached one
services.Replace(ServiceDescriptor.Transient<ISwaggerProvider, CachedSwaggerProvider>());
if (setupAction != null)
{
services.ConfigureSwaggerGen(setupAction);
}
return services;
}
}
Finally the specialized version of the SwaggerGenerator that caches the swagger.json document
public class CachedSwaggerProvider : SwaggerGenerator, ISwaggerProvider
{
private static readonly ConcurrentDictionary<string, OpenApiDocument> Cache = new ConcurrentDictionary<string, OpenApiDocument>();
public CachedSwaggerProvider(
IApiDescriptionGroupCollectionProvider apiDescriptionsProvider,
ISchemaGenerator schemaGenerator,
IOptions<SwaggerGeneratorOptions> optionsAccessor)
: base(apiDescriptionsProvider, schemaGenerator, optionsAccessor)
{
}
/// <inheritdoc />
public new OpenApiDocument GetSwagger(string documentName, string host = null, string basePath = null)
{
// Generate a unique key for the API documentation created.
var cacheKey = $"{documentName}_{host}_{basePath}";
// Check to see if the entry has already been created, only re-create it if not found
return Cache.GetOrAdd(cacheKey, key => base.GetSwagger(documentName, host, basePath));
}
}
That's it, now your swagger.json document will be cached after the first call.
@ErlendSB @ckarcz I would need to look into it further, but it's my current understanding that the caching middleware does support server-side caching. Like I said, I'm not over familiar with that middleware but the docs certainly seems to indicate that to be the case:
The middleware determines when responses are cacheable, stores responses, and serves responses from cache
thanks for the updated implementation @sverrirs.
@domaindrivendev the thing is for an API, you want granular control of caching. i.e. turn it server level response caching only for the swagger docs/ui site. the swagger docs/ui can be cached indefinitely. the API data itself needs custom rules/etc. if i find a way to do this in the framework i will update this thread.
Most helpful comment
For posterity here is a way to achieve the CachedProvider functionality in Swashbuckle.AspNetCore:
In Startup.cs
Provide the new extension method, to overwrite the previously registered ISwaggerProvider in the DI
Finally the specialized version of the SwaggerGenerator that caches the swagger.json document
That's it, now your swagger.json document will be cached after the first call.