Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #1661 - Make IDocumentFilter async compatible #2635

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ public void Configure(SwaggerGeneratorOptions options)
_swaggerGenOptions.DocumentFilterDescriptors.ForEach(
filterDescriptor => options.DocumentFilters.Add(CreateFilter<IDocumentFilter>(filterDescriptor)));

_swaggerGenOptions.DocumentAsyncFilterDescriptors.ForEach(
filterDescriptor => options.DocumentAsyncFilters.Add(CreateFilter<IDocumentAsyncFilter>(filterDescriptor)));

if (!options.SwaggerDocs.Any())
{
options.SwaggerDocs.Add("v1", new OpenApiInfo { Title = _hostingEnv.ApplicationName, Version = "1.0" });
Expand All @@ -69,6 +72,7 @@ public void DeepCopy(SwaggerGeneratorOptions source, SwaggerGeneratorOptions tar
target.ParameterFilters = new List<IParameterFilter>(source.ParameterFilters);
target.OperationFilters = new List<IOperationFilter>(source.OperationFilters);
target.DocumentFilters = new List<IDocumentFilter>(source.DocumentFilters);
target.DocumentAsyncFilters = new List<IDocumentAsyncFilter>(source.DocumentAsyncFilters);
}

private TFilter CreateFilter<TFilter>(FilterDescriptor filterDescriptor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public class SwaggerGenOptions

public List<FilterDescriptor> DocumentFilterDescriptors { get; set; } = new List<FilterDescriptor>();

public List<FilterDescriptor> DocumentAsyncFilterDescriptors { get; set; } = new List<FilterDescriptor>();

public List<FilterDescriptor> SchemaFilterDescriptors { get; set; } = new List<FilterDescriptor>();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,24 @@ public static void SupportNonNullableReferenceTypes(this SwaggerGenOptions swagg
});
}

/// <summary>
/// Extend the Swagger Generator with async "filters" that can modify SwaggerDocuments after they're initially generated
/// </summary>
/// <typeparam name="TFilter">A type that derives from IDocumentAsyncFilter</typeparam>
/// <param name="swaggerGenOptions"></param>
/// <param name="arguments">Optionally inject parameters through filter constructors</param>
public static void DocumentAsyncFilter<TFilter>(
this SwaggerGenOptions swaggerGenOptions,
params object[] arguments)
where TFilter : IDocumentAsyncFilter
{
swaggerGenOptions.DocumentFilterDescriptors.Add(new FilterDescriptor
{
Type = typeof(TFilter),
Arguments = arguments
});
}

/// <summary>
/// Inject human-friendly descriptions for Operations, Parameters and Schemas based on XML Comment files
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.OpenApi.Models;

namespace Swashbuckle.AspNetCore.SwaggerGen
{

public interface IDocumentFilter
{
void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context);
}

public interface IDocumentAsyncFilter
{
Task Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context);
}

public class DocumentFilterContext
{
public DocumentFilterContext(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public async Task<OpenApiDocument> GetSwaggerAsync(string documentName, string h
filter.Apply(swaggerDoc, filterContext);
}

foreach (var filter in _options.DocumentAsyncFilters)
{
await filter.Apply(swaggerDoc, filterContext);
}

swaggerDoc.Components.Schemas = new SortedDictionary<string, OpenApiSchema>(swaggerDoc.Components.Schemas, _options.SchemaComparer);

return swaggerDoc;
Expand All @@ -70,8 +75,15 @@ public OpenApiDocument GetSwagger(string documentName, string host = null, strin
filter.Apply(swaggerDoc, filterContext);
}

swaggerDoc.Components.Schemas = new SortedDictionary<string, OpenApiSchema>(swaggerDoc.Components.Schemas, _options.SchemaComparer);
if (_options.DocumentAsyncFilters?.Any() ?? false)
{
throw new SwaggerGeneratorException("DocumentAsyncFilters are configured but not using GetSwaggerAsync(). " +
"Use GetSwaggerAsync() instead of GetSwagger()");
}


swaggerDoc.Components.Schemas = new SortedDictionary<string, OpenApiSchema>(swaggerDoc.Components.Schemas, _options.SchemaComparer);

return swaggerDoc;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public SwaggerGeneratorOptions()
RequestBodyFilters = new List<IRequestBodyFilter>();
OperationFilters = new List<IOperationFilter>();
DocumentFilters = new List<IDocumentFilter>();
DocumentAsyncFilters = new List<IDocumentAsyncFilter>();
}

public IDictionary<string, OpenApiInfo> SwaggerDocs { get; set; }
Expand Down Expand Up @@ -67,6 +68,9 @@ public SwaggerGeneratorOptions()

public IList<IDocumentFilter> DocumentFilters { get; set; }

public IList<IDocumentAsyncFilter> DocumentAsyncFilters { get; set; }


private bool DefaultDocInclusionPredicate(string documentName, ApiDescription apiDescription)
{
return apiDescription.GroupName == null || apiDescription.GroupName == documentName;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.TestSupport;
using System.Threading.Tasks;

namespace Swashbuckle.AspNetCore.SwaggerGen.Test
{
public class TestDocumentAsyncFilter : IDocumentAsyncFilter
{
public Task Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
swaggerDoc.Extensions.Add("X-foo", new OpenApiString("bar"));
swaggerDoc.Extensions.Add("X-docName", new OpenApiString(context.DocumentName));
context.SchemaGenerator.GenerateSchema(typeof(ComplexType), context.SchemaRepository);

return Task.CompletedTask;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,32 @@ public void GetSwagger_SupportsOption_DocumentFilters()
Assert.Contains("ComplexType", document.Components.Schemas.Keys);
}

[Fact]
public async Task GetSwagger_SupportsOption_AsyncDocumentFilters()
{
var subject = Subject(
apiDescriptions: new ApiDescription[] { },
options: new SwaggerGeneratorOptions
{
SwaggerDocs = new Dictionary<string, OpenApiInfo>
{
["v1"] = new OpenApiInfo { Version = "V1", Title = "Test API" }
},
DocumentAsyncFilters = new List<IDocumentAsyncFilter>
{
new TestDocumentAsyncFilter()
}
}
);

var document = await subject.GetSwaggerAsync("v1");

Assert.Equal(2, document.Extensions.Count);
Assert.Equal("bar", ((OpenApiString)document.Extensions["X-foo"]).Value);
Assert.Equal("v1", ((OpenApiString)document.Extensions["X-docName"]).Value);
Assert.Contains("ComplexType", document.Components.Schemas.Keys);
}

private SwaggerGenerator Subject(
IEnumerable<ApiDescription> apiDescriptions,
SwaggerGeneratorOptions options = null,
Expand Down