Swashbuckle - Add Model and Example Values to Swagger Ui from a Model from Another Project

Swashbuckle - Add Model and Example values to Swagger UI from a Model from another project

I have recently handled a similar scenario when I worked on a web API project which was hosted on IIS. I was required to enable xml documentations for all view models and models from two different projects.

Below is a summary of the main steps of the work:

  1. Enable XML documentation for related projects (refer to here)
  2. For each project, build it first and then include the xml file in the project. Set the property of the file "Copy to Output Directory" to be "Copy is newer" to ensure it is copied to the bin folder of the server.
  3. In the Swagger config, invoke IncludeXmlComments() to include the XML documentation files as suggested by Simon88.

The key point is to ensure all xml documentation files are copied to the bin folder of the host server and Swagger UI knows where they are :-).

By the way, there are few similar questions/answers for this kind of issue. One is here

Hope it helps.

Specify example requests for swagger's "Try it out"

In .Net5 you can add a SchemaFilter to Swagger in the Startup.cs

public override void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(c =>
{
c.SchemaFilter<ExampleSchemaFilter>();
});
}

In the ExampleSchemaFilter.cs you simply define an OpenApiObject for your specific class:

using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

public class ExampleSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type == typeof(User))
{
schema.Example = new OpenApiObject()
{
["firstName"] = new OpenApiString("John"),
["lastName"] = new OpenApiString("Doe"),
};
}
}
}

Using Swashbuckle for Asp.net core how can I add a model to the generated model list?

You could create an document filter and register it globally.

public class CustomModelDocumentFilter<T> : IDocumentFilter where T : class
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
context.SchemaRegistry.GetOrRegister(typeof(T));
}
}

and then register it in your Startup class.

services.AddSwaggerGen(options =>
{
...
options.DocumentFilter<CustomModelDocumentFilter<MyCustomModel>>();
options.DocumentFilter<CustomModelDocumentFilter<MyOtherModel>>();
...
}

For polymorphic class you could use these to filters (slightly improved versions of this answer).

public class PolymorphismDocumentFilter<T> : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
RegisterSubClasses(context.SchemaRegistry, typeof(T));
}

private static void RegisterSubClasses(ISchemaRegistry schemaRegistry, Type abstractType)
{
const string discriminatorName = "$type";

string friendlyId = abstractType.FriendlyId();
if (!schemaRegistry.Definitions.TryGetValue(friendlyId, out Schema parentSchema))
parentSchema = schemaRegistry.GetOrRegister(abstractType);

// set up a discriminator property (it must be required)
parentSchema.Discriminator = discriminatorName;
parentSchema.Required = new List<string> { discriminatorName };

if (parentSchema.Properties == null)
parentSchema.Properties = new Dictionary<string, Schema>();

if (!parentSchema.Properties.ContainsKey(discriminatorName))
parentSchema.Properties.Add(discriminatorName, new Schema { Type = "string", Default = abstractType.FullName });

// register all subclasses
var derivedTypes = abstractType.GetTypeInfo().Assembly.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));

foreach (var item in derivedTypes)
schemaRegistry.GetOrRegister(item);
}
}

public class PolymorphismSchemaFilter<T> : ISchemaFilter
{
private readonly Lazy<HashSet<Type>> derivedTypes = new Lazy<HashSet<Type>>(Init);

public void Apply(Schema schema, SchemaFilterContext context)
{
if (!derivedTypes.Value.Contains(context.SystemType)) return;

var type = context.SystemType;
var clonedSchema = new Schema
{
Properties = schema.Properties,
Type = schema.Type,
Required = schema.Required
};

// schemaRegistry.Definitions[typeof(T).Name]; does not work correctly in Swashbuckle.AspNetCore
var parentSchema = new Schema { Ref = "#/definitions/" + typeof(T).Name };

var assemblyName = Assembly.GetAssembly(type).GetName();
schema.Discriminator = "$type";
// This is required if you use Microsoft's AutoRest client to generate the JavaScript/TypeScript models
schema.Extensions.Add("x-ms-discriminator-value", $"{type.FullName}, {assemblyName.Name}");
schema.AllOf = new List<Schema> { parentSchema, clonedSchema };

// reset properties for they are included in allOf, should be null but code does not handle it
schema.Properties = new Dictionary<string, Schema>();
}

private static HashSet<Type> Init()
{
var abstractType = typeof(T);
var dTypes = abstractType.GetTypeInfo().Assembly
.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));

var result = new HashSet<Type>();

foreach (var item in dTypes)
result.Add(item);

return result;
}
}

Two filters are required. The first will add all of your delivered classes to the schema. It also adds properties that aren't existing int he base class to the derived type's schema.

The second filter adds some properties ($type for serialization when the model returns) and extensions (for Microsoft's AutoRest client / generator) as well as adding the allOf properties to the Swagger schema, which are required in order to create a inheritance schema when generated with swagger-gen or AutoRest.

Registration is similar, just that you need to register them in pairs (only registration of the base class is required)

// The following lines add polymorphism to the swagger.json schema, so that
// code generators can create properly inheritance hierarchies.
options.DocumentFilter<PolymorphismDocumentFilter<BaseClass>>();
options.SchemaFilter<PolymorphismSchemaFilter<BaseClass>gt;();
Update for ASP.NET Core 3 and Swashbuckle.AspNetCore 5.0
public class CustomModelDocumentFilter<T> : IDocumentFilter where T : class
{
public void Apply(OpenApiDocument openapiDoc, DocumentFilterContext context)
{
context.SchemaGenerator.GenerateSchema(typeof(T), context.SchemaRepository);
}
}

The PolymorphismDocumentFilter/PolymorphismSchemaFilter updated for Swashbuckle.AspNetCore 5.0

public class PolymorphismDocumentFilter<T> : IDocumentFilter
{
public void Apply(OpenApiDocument openApiDoc, DocumentFilterContext context)
{
RegisterSubClasses(context, typeof(T));
}

private static void RegisterSubClasses(DocumentFilterContext context, Type abstractType)
{
const string discriminatorName = "$type";
var schemaRepository = context.SchemaRepository.Schemas;
var schemaGenerator = context.SchemaGenerator;

if (!schemaRepository.TryGetValue(abstractType.Name, out OpenApiSchema parentSchema))
{
parentSchema = schemaGenerator.GenerateSchema(abstractType, context.SchemaRepository);
}

// set up a discriminator property (it must be required)
parentSchema.Discriminator = new OpenApiDiscriminator { PropertyName = discriminatorName };
parentSchema.Required.Add(discriminatorName);

if (!parentSchema.Properties.ContainsKey(discriminatorName))
parentSchema.Properties.Add(discriminatorName, new OpenApiSchema { Type = "string", Default = new OpenApiString(abstractType.FullName) });

// register all subclasses
var derivedTypes = abstractType.GetTypeInfo().Assembly.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));

foreach (var type in derivedTypes)
schemaGenerator.GenerateSchema(type, context.SchemaRepository);
}
}

and

public class PolymorphismSchemaFilter<T> : ISchemaFilter
{
private readonly Lazy<HashSet<Type>> derivedTypes = new Lazy<HashSet<Type>>(Init);

public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
var type = context.ApiModel.Type;
if (!derivedTypes.Value.Contains(type))
return;

var clonedSchema = new OpenApiSchema
{
Properties = schema.Properties,
Type = schema.Type,
Required = schema.Required
};

// schemaRegistry.Definitions[typeof(T).Name]; does not work correctly in SwashBuckle
if(context.SchemaRepository.Schemas.TryGetValue(typeof(T).Name, out OpenApiSchema _))
{
schema.AllOf = new List<OpenApiSchema> {
new OpenApiSchema { Reference = new OpenApiReference { Id = typeof(T).Name, Type = ReferenceType.Schema } },
clonedSchema
};
}

var assemblyName = Assembly.GetAssembly(type).GetName();
schema.Discriminator = new OpenApiDiscriminator { PropertyName = "$type" };
schema.AddExtension("x-ms-discriminator-value", new OpenApiString($"{type.FullName}, {assemblyName.Name}"));

// reset properties for they are included in allOf, should be null but code does not handle it
schema.Properties = new Dictionary<string, OpenApiSchema>();
}

private static HashSet<Type> Init()
{
var abstractType = typeof(T);
var dTypes = abstractType.GetTypeInfo().Assembly
.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));

var result = new HashSet<Type>();

foreach (var item in dTypes)
result.Add(item);

return result;
}
}

How to bring another project (get,post) api method to swagger api project?

I used service stack swagger instead of swashbuckle.

It's solve my problem.

here is the solution.

https://forums.servicestack.net/t/guidance-on-enabling-oauth-2-0-in-generated-swagger-docs/3995/18

Adding Model information to swagger output

You will need to enable XML documentation file creation in your project properties:
Project Properties > Build > Check the XML Documentation File box

Then you can uncomment or add the following line to your SwaggerConfig.cs file:
c.IncludeXmlComments(GetXmlCommentsPath());

How to configure Swashbuckle to ignore property on model

If you need to do this but without using JsonIgnore (maybe you still need to serialize/deserialize the property) then just create a custom attribute.

[AttributeUsage(AttributeTargets.Property)]
public class SwaggerExcludeAttribute : Attribute
{
}

Then a schema filter similar to Johng's

public class SwaggerExcludeFilter : ISchemaFilter
{
#region ISchemaFilter Members

public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
if (schema?.properties == null || type == null)
return;

var excludedProperties = type.GetProperties()
.Where(t =>
t.GetCustomAttribute<SwaggerExcludeAttribute>()
!= null);

foreach (var excludedProperty in excludedProperties)
{
if (schema.properties.ContainsKey(excludedProperty.Name))
schema.properties.Remove(excludedProperty.Name);
}
}

#endregion
}

Don't forget to register the filter

c.SchemaFilter<SwaggerExcludeFilter>();

Swashbuckle - Add Model and Example values to Swagger UI from a Model from another project

I have recently handled a similar scenario when I worked on a web API project which was hosted on IIS. I was required to enable xml documentations for all view models and models from two different projects.

Below is a summary of the main steps of the work:

  1. Enable XML documentation for related projects (refer to here)
  2. For each project, build it first and then include the xml file in the project. Set the property of the file "Copy to Output Directory" to be "Copy is newer" to ensure it is copied to the bin folder of the server.
  3. In the Swagger config, invoke IncludeXmlComments() to include the XML documentation files as suggested by Simon88.

The key point is to ensure all xml documentation files are copied to the bin folder of the host server and Swagger UI knows where they are :-).

By the way, there are few similar questions/answers for this kind of issue. One is here

Hope it helps.



Related Topics



Leave a reply



Submit