Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: domaindrivendev/Swashbuckle.AspNetCore
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v6.1.3
Choose a base ref
...
head repository: domaindrivendev/Swashbuckle.AspNetCore
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v6.1.4
Choose a head ref
  • 3 commits
  • 5 files changed
  • 2 contributors

Commits on Apr 28, 2021

  1. Support requestBody examples via XML comments

    rmorris committed Apr 28, 2021

    Verified

    This commit was signed with the committer’s verified signature.
    leohemsted Leo Hemsted
    Copy the full SHA
    d128d29 View commit details
  2. Merge pull request #2112 from domaindrivendev/xml-examples-for-reques…

    …t-bodies
    
    Support requestBody examples via XML comments
    domaindrivendev authored Apr 28, 2021

    Verified

    This commit was signed with the committer’s verified signature.
    csmarchbanks Chris Marchbanks
    Copy the full SHA
    be4103d View commit details
  3. Prep for 6.1.4 release

    rmorris committed Apr 28, 2021
    Copy the full SHA
    539f96b View commit details
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ Once you have an API that can describe itself in Swagger, you've opened the trea
|Swashbuckle Version|ASP.NET Core|Swagger / OpenAPI Spec.|swagger-ui|ReDoc UI|
|----------|----------|----------|----------|----------|
|[master](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/tree/master/README.md)|>= 2.0.0|2.0, 3.0|3.47.1|2.0.0-rc.40|
|[6.1.3](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/tree/v6.1.3)|>= 2.0.0|2.0, 3.0|3.47.1|2.0.0-rc.40|
|[6.1.4](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/tree/v6.1.4)|>= 2.0.0|2.0, 3.0|3.47.1|2.0.0-rc.40|
|[5.6.3](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/tree/v5.6.3)|>= 2.0.0|2.0, 3.0|3.32.5|2.0.0-rc.40|
|[4.0.0](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/tree/v4.0.0)|>= 2.0.0, < 3.0.0|2.0|3.19.5|1.22.2|
|[3.0.0](https://github.com/domaindrivendev/Swashbuckle.AspNetCore/tree/v3.0.0)|>= 1.0.4, < 3.0.0|2.0|3.17.1|1.20.0|
@@ -33,8 +33,8 @@ Once you have an API that can describe itself in Swagger, you've opened the trea
1. Install the standard Nuget package into your ASP.NET Core application.

```
Package Manager : Install-Package Swashbuckle.AspNetCore -Version 6.1.3
CLI : dotnet add package --version 6.1.3 Swashbuckle.AspNetCore
Package Manager : Install-Package Swashbuckle.AspNetCore -Version 6.1.4
CLI : dotnet add package --version 6.1.4 Swashbuckle.AspNetCore
```
2. In the `ConfigureServices` method of `Startup.cs`, register the Swagger generator, defining one or more Swagger documents.
@@ -98,8 +98,8 @@ If you're using **System.Text.Json (STJ)**, then the setup described above will
If you're using **Newtonsoft**, then you'll need to install a separate package and explicitly opt-in to ensure that *Newtonsoft* settings/attributes are automatically honored by the Swagger generator:
```
Package Manager : Install-Package Swashbuckle.AspNetCore.Newtonsoft -Version 6.1.3
CLI : dotnet add package --version 6.1.3 Swashbuckle.AspNetCore.Newtonsoft
Package Manager : Install-Package Swashbuckle.AspNetCore.Newtonsoft -Version 6.1.4
CLI : dotnet add package --version 6.1.4 Swashbuckle.AspNetCore.Newtonsoft
```
```csharp
@@ -1495,7 +1495,7 @@ It's packaged as a [.NET Core Tool](https://docs.microsoft.com/en-us/dotnet/core
1. Install as a [global tool](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools#install-a-global-tool)
```
dotnet tool install -g --version 6.1.3 Swashbuckle.AspNetCore.Cli
dotnet tool install -g --version 6.1.4 Swashbuckle.AspNetCore.Cli
```

2. Verify that the tool was installed correctly
@@ -1526,7 +1526,7 @@ It's packaged as a [.NET Core Tool](https://docs.microsoft.com/en-us/dotnet/core
2. Install as a [local tool](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools#install-a-local-tool)
```
dotnet tool install --version 6.1.3 Swashbuckle.AspNetCore.Cli
dotnet tool install --version 6.1.4 Swashbuckle.AspNetCore.Cli
```

3. Verify that the tool was installed correctly
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<LicenseUrl>https://licenses.nuget.org/MIT</LicenseUrl>
<VersionPrefix>6.1.3</VersionPrefix>
<VersionPrefix>6.1.4</VersionPrefix>
</PropertyGroup>

<ItemGroup>
Original file line number Diff line number Diff line change
@@ -40,14 +40,13 @@ private void ApplyPropertyTags(OpenApiParameter parameter, ParameterFilterContex
}

var exampleNode = propertyNode.SelectSingleNode("example");
if (exampleNode != null)
{
var exampleAsJson = (parameter.Schema?.ResolveType(context.SchemaRepository) == "string")
? $"\"{exampleNode.InnerXml}\""
: exampleNode.InnerXml;
if (exampleNode == null) return;

parameter.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson);
}
var exampleAsJson = (parameter.Schema?.ResolveType(context.SchemaRepository) == "string")
? $"\"{exampleNode.InnerXml}\""
: exampleNode.InnerXml;

parameter.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson);
}

private void ApplyParamTags(OpenApiParameter parameter, ParameterFilterContext context)
@@ -70,14 +69,13 @@ private void ApplyParamTags(OpenApiParameter parameter, ParameterFilterContext c
parameter.Description = XmlCommentsTextHelper.Humanize(paramNode.InnerXml);

var example = paramNode.GetAttribute("example", "");
if (!string.IsNullOrEmpty(example))
{
var exampleAsJson = (parameter.Schema?.ResolveType(context.SchemaRepository) == "string")
? $"\"{example}\""
: example;

parameter.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson);
}
if (string.IsNullOrEmpty(example)) return;

var exampleAsJson = (parameter.Schema?.ResolveType(context.SchemaRepository) == "string")
? $"\"{example}\""
: example;

parameter.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson);
}
}
}
Original file line number Diff line number Diff line change
@@ -22,28 +22,43 @@ public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext conte
var propertyInfo = bodyParameterDescription.PropertyInfo();
if (propertyInfo != null)
{
ApplyPropertyTags(requestBody, propertyInfo);
ApplyPropertyTags(requestBody, context, propertyInfo);
return;
}

var parameterInfo = bodyParameterDescription.ParameterInfo();
if (parameterInfo != null)
{
ApplyParamTags(requestBody, parameterInfo);
ApplyParamTags(requestBody, context, parameterInfo);
return;
}
}

private void ApplyPropertyTags(OpenApiRequestBody requestBody, PropertyInfo propertyInfo)
private void ApplyPropertyTags(OpenApiRequestBody requestBody, RequestBodyFilterContext context, PropertyInfo propertyInfo)
{
var propertyMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(propertyInfo);
var propertySummaryNode = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{propertyMemberName}']/summary");
var propertyNode = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{propertyMemberName}']");

if (propertySummaryNode != null)
requestBody.Description = XmlCommentsTextHelper.Humanize(propertySummaryNode.InnerXml);
if (propertyNode == null) return;

var summaryNode = propertyNode.SelectSingleNode("summary");
if (summaryNode != null)
requestBody.Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml);

var exampleNode = propertyNode.SelectSingleNode("example");
if (exampleNode == null) return;

foreach (var mediaType in requestBody.Content.Values)
{
var exampleAsJson = (mediaType.Schema?.ResolveType(context.SchemaRepository) == "string")
? $"\"{exampleNode.InnerXml}\""
: exampleNode.InnerXml;

mediaType.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson);
}
}

private void ApplyParamTags(OpenApiRequestBody requestBody, ParameterInfo parameterInfo)
private void ApplyParamTags(OpenApiRequestBody requestBody, RequestBodyFilterContext context, ParameterInfo parameterInfo)
{
if (!(parameterInfo.Member is MethodInfo methodInfo)) return;

@@ -61,6 +76,18 @@ private void ApplyParamTags(OpenApiRequestBody requestBody, ParameterInfo parame
if (paramNode != null)
{
requestBody.Description = XmlCommentsTextHelper.Humanize(paramNode.InnerXml);

var example = paramNode.GetAttribute("example", "");
if (string.IsNullOrEmpty(example)) return;

foreach (var mediaType in requestBody.Content.Values)
{
var exampleAsJson = (mediaType.Schema?.ResolveType(context.SchemaRepository) == "string")
? $"\"{example}\""
: example;

mediaType.Example = OpenApiAnyFactory.CreateFromJson(exampleAsJson);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -5,15 +5,22 @@
using Microsoft.OpenApi.Models;
using Xunit;
using Swashbuckle.AspNetCore.TestSupport;
using System.Collections.Generic;

namespace Swashbuckle.AspNetCore.SwaggerGen.Test
{
public class XmlCommentsRequestBodyFilterTests
{
[Fact]
public void Apply_SetsDescription_FromActionParamTag()
public void Apply_SetsDescriptionAndExample_FromActionParamTag()
{
var requestbody = new OpenApiRequestBody();
var requestBody = new OpenApiRequestBody
{
Content = new Dictionary<string, OpenApiMediaType>
{
["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Type = "string" } }
}
};
var parameterInfo = typeof(FakeControllerWithXmlComments)
.GetMethod(nameof(FakeControllerWithXmlComments.ActionWithParamTags))
.GetParameters()[0];
@@ -23,15 +30,23 @@ public void Apply_SetsDescription_FromActionParamTag()
};
var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null);

Subject().Apply(requestbody, filterContext);
Subject().Apply(requestBody, filterContext);

Assert.Equal("Description for param1", requestbody.Description);
Assert.Equal("Description for param1", requestBody.Description);
Assert.NotNull(requestBody.Content["application/json"].Example);
Assert.Equal("\"Example for param1\"", requestBody.Content["application/json"].Example.ToJson());
}

[Fact]
public void Apply_SetsDescription_FromUnderlyingGenericTypeActionParamTag()
public void Apply_SetsDescriptionAndExample_FromUnderlyingGenericTypeActionParamTag()
{
var requestbody = new OpenApiRequestBody();
var requestBody = new OpenApiRequestBody
{
Content = new Dictionary<string, OpenApiMediaType>
{
["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Type = "string" } }
}
};
var parameterInfo = typeof(FakeConstructedControllerWithXmlComments)
.GetMethod(nameof(FakeConstructedControllerWithXmlComments.ActionWithParamTags))
.GetParameters()[0];
@@ -41,15 +56,23 @@ public void Apply_SetsDescription_FromUnderlyingGenericTypeActionParamTag()
};
var filterContext = new RequestBodyFilterContext(bodyParameterDescription, null, null, null);

Subject().Apply(requestbody, filterContext);
Subject().Apply(requestBody, filterContext);

Assert.Equal("Description for param1", requestbody.Description);
Assert.Equal("Description for param1", requestBody.Description);
Assert.NotNull(requestBody.Content["application/json"].Example);
Assert.Equal("\"Example for param1\"", requestBody.Content["application/json"].Example.ToJson());
}

[Fact]
public void Apply_SetsDescription_FromPropertySummaryTag()
public void Apply_SetsDescriptionAndExample_FromPropertySummaryAndExampleTags()
{
var requestBody = new OpenApiRequestBody();
var requestBody = new OpenApiRequestBody
{
Content = new Dictionary<string, OpenApiMediaType>
{
["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Type = "string" } }
}
};
var bodyParameterDescription = new ApiParameterDescription
{
ModelMetadata = ModelMetadataFactory.CreateForProperty(typeof(XmlAnnotatedType), nameof(XmlAnnotatedType.StringProperty))
@@ -59,6 +82,8 @@ public void Apply_SetsDescription_FromPropertySummaryTag()
Subject().Apply(requestBody, filterContext);

Assert.Equal("Summary for StringProperty", requestBody.Description);
Assert.NotNull(requestBody.Content["application/json"].Example);
Assert.Equal("\"Example for StringProperty\"", requestBody.Content["application/json"].Example.ToJson());
}

private XmlCommentsRequestBodyFilter Subject()