Skip to content

Commit

Permalink
Add IncludeXmlCommentsWithRemarks option to add xml comments from s…
Browse files Browse the repository at this point in the history
…ummary and remarks into the swagger documentation;

Update nuget-dependencies.
  • Loading branch information
unchase committed Oct 11, 2020
1 parent 970a850 commit 736e7a7
Show file tree
Hide file tree
Showing 27 changed files with 899 additions and 96 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@

These are the changes to each version that has been released on the [nuget](https://www.nuget.org/packages/Unchase.Swashbuckle.AspNetCore.Extensions/).

## v2.4.0 `2020-10-11`

- [x] Add `IncludeXmlCommentsWithRemarks` option to add xml comments from summary and remarks into the swagger documentation
- [x] Update nuget-dependencies

## v2.3.13 `2020-10-07`

- [x] Add `IncludeXEnumRemarks` option to include remarks for descriptions from xml-comments
Expand Down
121 changes: 112 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,7 @@

For old versions see [README_OLD.md](README_OLD.md).

* Since [v2.3.0](https://github.com/unchase/Unchase.Swashbuckle.AspNetCore.Extensions/releases/tag/v2.3.0) there are [**breaking changes**](#breaking-changes-2.3.0) in `Startup.cs`:

```csharp

```

* Since [v2.3.0](https://github.com/unchase/Unchase.Swashbuckle.AspNetCore.Extensions/releases/tag/v2.3.0) there are [**breaking changes**](#breaking-changes-2.3.0) in `Startup.cs`

### Compatibility

Expand All @@ -46,7 +41,7 @@ dotnet add package Unchase.Swashbuckle.AspNetCore.Extensions --version {version}
```

> Where {version} is the version of the package you want to install.
> For example, `dotnet add package Unchase.Swashbuckle.AspNetCore.Extensions --version 2.0.0`
> For example, `dotnet add package Unchase.Swashbuckle.AspNetCore.Extensions --version 2.4.0`
Then use whichever extensions (filters) you need.

Expand Down Expand Up @@ -106,9 +101,11 @@ public void ConfigureServices(IServiceCollection services)
// use it if you want to hide Paths and Definitions from OpenApi documentation correctly
options.UseAllOfToExtendReferenceSchemas();

// if you want to add xml comments into the swagger documentation, first of all add:
// if you want to add xml comments (with remarks) into the swagger documentation, first of all add:
var xmlFilePath = Path.Combine(AppContext.BaseDirectory, "WebApi3.1-Swashbuckle.xml");
options.IncludeXmlComments(xmlFilePath);
options.IncludeXmlCommentsWithRemarks(xmlFilePath);
// or add without remarks
//options.IncludeXmlComments(xmlFilePath);
// Add filters to fix enums
// use by default:
Expand Down Expand Up @@ -322,6 +319,28 @@ public void ConfigureServices(IServiceCollection services)
}
```

6. **Add xml comments from summary and remarks into the swagger documentation**:

- Since [v2.4.0](https://github.com/unchase/Unchase.Swashbuckle.AspNetCore.Extensions/releases/tag/v2.4.0) in the _ConfigureServices_ method of _Startup.cs_, inside your `AddSwaggerGen` call, add `IncludeXmlCommentsWithRemarks` option instead of `IncludeXmlComments` option:

```csharp
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...

services.AddSwaggerGen(options =>
{
...

// add xml comments from summary and remarks into the swagger documentation
options.IncludeXmlCommentsWithRemarks("<xml_File_Full_Path>");

...
});
}
```

## Builds status

|Status|Value|
Expand Down Expand Up @@ -486,6 +505,90 @@ For example:

![Change responses](assets/changeResponsesByHttpStatusCode.png)

### Add xml comments from summary and remarks into the swagger documentation

![Add xml comments from summary and remarks](assets/addXmlCommentsFromSummaryAndRemarks.png)

For code:

```csharp
/// <summary>
/// Inner class
/// </summary>
/// <remarks>
/// Inner class remarks - class
/// </remarks>
public class InnerClass
{
/// <summary>
/// List of inner enums
/// </summary>
/// <remarks>
/// List of inner enums remarks - property
/// </remarks>
public List<InnerEnum> InnerEnum { get; set; }

/// <summary>
/// Second inner class
/// </summary>
/// <remarks>
/// Second inner class remarks - property
/// </remarks>
public SecondInnerClass<SecondInnerEnum> SecondInnerClass { get; set; }
}

/// <summary>
/// Inner enum
/// </summary>
/// <remarks>
/// Inner enum remarks - enum
/// </remarks>
public enum InnerEnum
{
/// <summary>
/// Inner enum value
/// </summary>
/// <remarks>
/// Inner enum value remarks
/// </remarks>
Value = 1
}

/// <summary>
/// Second inner class
/// </summary>
/// <remarks>
/// Second inner class remarks - class
/// </remarks>
public class SecondInnerClass<T> where T : Enum
{
/// <summary>
/// Second inner enum
/// </summary>
/// <remarks>
/// Second inner enum remarks - property
/// </remarks>
public T InnerEnum { get; set; }
}

/// <summary>
/// Second inner enum
/// </summary>
/// <remarks>
/// Second inner enum remarks - enum
/// </remarks>
public enum SecondInnerEnum
{
/// <summary>
/// Second inner enum value
/// </summary>
/// <remarks>
/// Second inner enum value remarks
/// </remarks>
Value = 0
}
```

## HowTos

- [ ] Add HowTos in a future
Expand Down
3 changes: 3 additions & 0 deletions Unchase.Swashbuckle.AspNetCore.Extensions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{145A03BF-E60E-41F6-BD89-457F940F6C9B}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
assets\addXmlCommentsFromSummaryAndRemarks.png = assets\addXmlCommentsFromSummaryAndRemarks.png
assets\appendActionCountIntoSwaggerTag.png = assets\appendActionCountIntoSwaggerTag.png
appveyor.yml = appveyor.yml
Build.ps1 = Build.ps1
assets\buymeacoffe.png = assets\buymeacoffe.png
CHANGELOG.md = CHANGELOG.md
assets\changeResponsesByHttpStatusCode.png = assets\changeResponsesByHttpStatusCode.png
assets\enumDescriptionInSchemaDefinitions.png = assets\enumDescriptionInSchemaDefinitions.png
assets\enumDescriptionInSchemaParameters.png = assets\enumDescriptionInSchemaParameters.png
assets\enumDescriptionInSwaggerUI.png = assets\enumDescriptionInSwaggerUI.png
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 2.3.{build}
version: 2.4.{build}
pull_requests:
do_not_increment_build_number: true
skip_tags: true
Expand Down
Binary file added assets/addXmlCommentsFromSummaryAndRemarks.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public enum DescriptionSources

internal static class EnumTypeExtensions
{
#region Methods

private static string GetDescriptionFromEnumOption(Type enumOptionType, object enumOption)
{
return enumOptionType.GetFieldAttributeDescription(enumOption, 0);
Expand Down Expand Up @@ -196,5 +198,7 @@ internal static string AddEnumValuesDescription(this OpenApiSchema schema, bool
}
return sb.ToString();
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace Unchase.Swashbuckle.AspNetCore.Extensions.Extensions
/// </summary>
public static class OpenApiDocumentExtensions
{
#region Extension methods

/// <summary>
/// Remove Paths and Components from OpenApi documentation for specific controller action without accepted roles.
/// </summary>
Expand All @@ -23,7 +25,9 @@ public static class OpenApiDocumentExtensions
/// <returns>
/// Returns <see cref="OpenApiDocument"/>.
/// </returns>
public static OpenApiDocument RemovePathsAndComponentsWithoutAcceptedRolesFor<TController>(this OpenApiDocument openApiDoc, Func<TController, string> actionNameSelector,
public static OpenApiDocument RemovePathsAndComponentsWithoutAcceptedRolesFor<TController>(
this OpenApiDocument openApiDoc,
Func<TController, string> actionNameSelector,
IReadOnlyList<string> acceptedRoles) where TController : class, new()
{
var actionDescriptor = ApiDescriptionFactory.Create(actionNameSelector, typeof(TController).GetCustomAttribute<RouteAttribute>().Template)?.ActionDescriptor;
Expand All @@ -49,7 +53,9 @@ public static OpenApiDocument RemovePathsAndComponentsWithoutAcceptedRolesFor<TC
/// <returns>
/// Returns <see cref="OpenApiDocument"/>.
/// </returns>
public static OpenApiDocument RemovePathsAndComponentsWithoutAcceptedRolesFor<TController>(this OpenApiDocument openApiDoc, string actionName,
public static OpenApiDocument RemovePathsAndComponentsWithoutAcceptedRolesFor<TController>(
this OpenApiDocument openApiDoc,
string actionName,
IReadOnlyList<string> acceptedRoles) where TController : class
{
var actionDescriptor = ApiDescriptionFactory.Create(typeof(TController), actionName, typeof(TController).GetCustomAttribute<RouteAttribute>().Template)?.ActionDescriptor;
Expand All @@ -74,7 +80,8 @@ public static OpenApiDocument RemovePathsAndComponentsWithoutAcceptedRolesFor<TC
/// <returns>
/// Returns <see cref="OpenApiDocument"/>.
/// </returns>
public static OpenApiDocument RemovePathsAndComponentsWithoutAcceptedRolesForController<TController>(this OpenApiDocument openApiDoc,
public static OpenApiDocument RemovePathsAndComponentsWithoutAcceptedRolesForController<TController>(
this OpenApiDocument openApiDoc,
IReadOnlyList<string> acceptedRoles) where TController : class
{
var paths = new Dictionary<(MethodInfo, Type), string>();
Expand All @@ -90,5 +97,7 @@ public static OpenApiDocument RemovePathsAndComponentsWithoutAcceptedRolesForCon

return openApiDoc;
}

#endregion
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Net;
using System.Xml.XPath;
using Microsoft.Extensions.DependencyInjection;
using Swashbuckle.AspNetCore.SwaggerGen;
using Unchase.Swashbuckle.AspNetCore.Extensions.Filters;
Expand All @@ -12,7 +13,7 @@ namespace Unchase.Swashbuckle.AspNetCore.Extensions.Extensions
/// </summary>
public static class SwaggerGenOptionsExtensions
{
#region Extensions
#region Extension methods

/// <summary>
/// Change all responses by specific http status codes in OpenApi document.
Expand Down Expand Up @@ -66,7 +67,10 @@ public static SwaggerGenOptions ChangeAllResponsesByHttpStatusCode<T>(
/// <param name="services"><see cref="IServiceCollection"/>.</param>
/// <param name="configureOptions">An <see cref="Action{FixEnumsOptions}"/> to configure options for filters.</param>
/// <returns></returns>
public static SwaggerGenOptions AddEnumsWithValuesFixFilters(this SwaggerGenOptions swaggerGenOptions, IServiceCollection services = null, Action<FixEnumsOptions> configureOptions = null)
public static SwaggerGenOptions AddEnumsWithValuesFixFilters(
this SwaggerGenOptions swaggerGenOptions,
IServiceCollection services = null,
Action<FixEnumsOptions> configureOptions = null)
{
// local function
void EmptyAction(FixEnumsOptions x) { }
Expand All @@ -82,6 +86,50 @@ void EmptyAction(FixEnumsOptions x) { }
return swaggerGenOptions;
}

/// <summary>
/// Inject human-friendly descriptions for Operations, Parameters and Schemas based on XML Comment files (from summary and remarks).
/// </summary>
/// <param name="swaggerGenOptions"><see cref="SwaggerGenOptions"/>.</param>
/// <param name="xmlDocFactory">A factory method that returns XML Comments as an XPathDocument.</param>
/// <param name="includeControllerXmlComments">
/// Flag to indicate if controller XML comments (i.e. summary) should be used to assign Tag descriptions.
/// Don't set this flag if you're customizing the default tag for operations via TagActionsBy.
/// </param>
public static SwaggerGenOptions IncludeXmlCommentsWithRemarks(
this SwaggerGenOptions swaggerGenOptions,
Func<XPathDocument> xmlDocFactory,
bool includeControllerXmlComments = false)
{
swaggerGenOptions.IncludeXmlComments(xmlDocFactory, includeControllerXmlComments);

var xmlDoc = xmlDocFactory();
swaggerGenOptions.ParameterFilter<XmlCommentsWithRemarksParameterFilter>(xmlDoc);
swaggerGenOptions.RequestBodyFilter<XmlCommentsWithRemarksRequestBodyFilter>(xmlDoc);
swaggerGenOptions.SchemaFilter<XmlCommentsWithRemarksSchemaFilter>(xmlDoc);

if (includeControllerXmlComments)
swaggerGenOptions.DocumentFilter<XmlCommentsWithRemarksDocumentFilter>(xmlDoc);

return swaggerGenOptions;
}

/// <summary>
/// Inject human-friendly descriptions for Operations, Parameters and Schemas based on XML Comment files (from summary and remarks).
/// </summary>
/// <param name="swaggerGenOptions"><see cref="SwaggerGenOptions"/>.</param>
/// <param name="filePath">An absolute path to the file that contains XML Comments.</param>
/// <param name="includeControllerXmlComments">
/// Flag to indicate if controller XML comments (i.e. summary) should be used to assign Tag descriptions.
/// Don't set this flag if you're customizing the default tag for operations via TagActionsBy.
/// </param>
public static SwaggerGenOptions IncludeXmlCommentsWithRemarks(
this SwaggerGenOptions swaggerGenOptions,
string filePath,
bool includeControllerXmlComments = false)
{
return swaggerGenOptions.IncludeXmlCommentsWithRemarks(() => new XPathDocument(filePath), includeControllerXmlComments);
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ namespace Unchase.Swashbuckle.AspNetCore.Extensions.Factories
/// </summary>
internal static class ApiDescriptionFactory
{
#region Methods

/// <summary>
/// Create <see cref="ApiDescription"/>.
/// </summary>
Expand Down Expand Up @@ -262,5 +264,7 @@ private static ParameterDescriptor CreateParameterDescriptor(ParameterInfo param
ParameterType = parameterInfo.ParameterType,
};
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,41 @@

namespace Unchase.Swashbuckle.AspNetCore.Extensions.Factories
{
/// <summary>
/// <see cref="ModelMetadata"/> factory.
/// </summary>
public static class ModelMetadataFactory
{
#region Methods

/// <summary>
/// Create <see cref="ModelMetadata"/> for type.
/// </summary>
/// <param name="type">Type of method.</param>
public static ModelMetadata CreateForType(Type type)
{
return new EmptyModelMetadataProvider().GetMetadataForType(type);
}

/// <summary>
/// Create <see cref="ModelMetadata"/> for property.
/// </summary>
/// <param name="containingType">Type of property method.</param>
/// <param name="propertyName">Name of property.</param>
public static ModelMetadata CreateForProperty(Type containingType, string propertyName)
{
return new EmptyModelMetadataProvider().GetMetadataForProperty(containingType, propertyName);
}

/// <summary>
/// Create <see cref="ModelMetadata"/> for parameter.
/// </summary>
/// <param name="parameter"><see cref="ParameterInfo"/></param>
public static ModelMetadata CreateForParameter(ParameterInfo parameter)
{
return new EmptyModelMetadataProvider().GetMetadataForParameter(parameter);
}

#endregion
}
}
}
Loading

0 comments on commit 736e7a7

Please sign in to comment.