Skip to content

Commit

Permalink
Added Swashbuckle.AspNetCore.Annotations.SwaggerIgnoreAttribute (#2610)
Browse files Browse the repository at this point in the history
Application of the SwaggerIgnoreAttribute suppresses the annotated
property during schema generation, without altering the serialization
behavior as with JsonIgnoreAttribute.
  • Loading branch information
jcracknell committed Apr 18, 2024
1 parent f26510d commit 1c29b4b
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

// ReSharper disable once CheckNamespace
namespace Swashbuckle.AspNetCore.Annotations
{
/// <summary>
/// Causes the annotated member to be ignored during schema generation.
/// Does not alter serialization behavior.
/// </summary>
/// <remarks>
/// Can be used in combination with <see cref="System.Text.Json.Serialization.JsonExtensionDataAttribute"/>
/// to capture and invalidate unsupported properties.
/// </remarks>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property)]
public sealed class SwaggerIgnoreAttribute : Attribute { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using Swashbuckle.AspNetCore.Annotations;

namespace Swashbuckle.AspNetCore.SwaggerGen
{
Expand Down Expand Up @@ -166,6 +167,7 @@ private IEnumerable<DataProperty> GetDataPropertiesFor(Type objectType, out Type
(property.IsPubliclyReadable() || property.IsPubliclyWritable()) &&
!(property.GetIndexParameters().Any()) &&
!(property.HasAttribute<JsonIgnoreAttribute>() && isIgnoredViaNet5Attribute) &&
!(property.HasAttribute<SwaggerIgnoreAttribute>()) &&
!(_serializerOptions.IgnoreReadOnlyProperties && !property.IsPubliclyWritable());
})
.OrderBy(property => property.DeclaringType.GetInheritanceChain().Length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Annotations;
using Swashbuckle.AspNetCore.Swagger;
#if NET7_0_OR_GREATER
using Microsoft.AspNetCore.Http.Metadata;
Expand Down Expand Up @@ -86,6 +87,7 @@ public OpenApiDocument GetSwagger(string documentName, string host = null, strin
var applicableApiDescriptions = _apiDescriptionsProvider.ApiDescriptionGroups.Items
.SelectMany(group => group.Items)
.Where(apiDesc => !(_options.IgnoreObsoleteActions && apiDesc.CustomAttributes().OfType<ObsoleteAttribute>().Any()))
.Where(apiDesc => !apiDesc.CustomAttributes().OfType<SwaggerIgnoreAttribute>().Any())
.Where(apiDesc => _options.DocInclusionPredicate(documentName, apiDesc));

var schemaRepository = new SchemaRepository(documentName);
Expand Down Expand Up @@ -319,6 +321,7 @@ private IList<OpenApiParameter> GenerateParameters(ApiDescription apiDescription
{
return (!apiParam.IsFromBody() && !apiParam.IsFromForm())
&& (!apiParam.CustomAttributes().OfType<BindNeverAttribute>().Any())
&& (!apiParam.CustomAttributes().OfType<SwaggerIgnoreAttribute>().Any())
&& (apiParam.ModelMetadata == null || apiParam.ModelMetadata.IsBindingAllowed);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Swashbuckle.AspNetCore.Annotations;

namespace Swashbuckle.AspNetCore.SwaggerGen.Test
{
Expand Down Expand Up @@ -49,6 +50,9 @@ public void ActionWithIntParameterWithDefaultValueAttribute([DefaultValue(3)]int
public void ActionWithIntParameterWithRequiredAttribute([Required]int param)
{ }

public void ActionWithIntParameterWithSwaggerIgnoreAttribute([SwaggerIgnore] int param)
{ }

public void ActionWithObjectParameter(XmlAnnotatedType param)
{ }

Expand Down Expand Up @@ -76,5 +80,9 @@ public int ActionWithProducesAttribute()
{
throw new NotImplementedException();
}

[SwaggerIgnore]
public void ActionWithSwaggerIgnoreAttribute()
{ }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using Swashbuckle.AspNetCore.Annotations;

namespace Swashbuckle.AspNetCore.SwaggerGen.Test.Fixtures
{
public class SwaggerIngoreAnnotatedType
{
public string NotIgnoredString { get; set; }

[SwaggerIgnore]
public string IgnoredString { get; set; }

[SwaggerIgnore]
[JsonExtensionData]
public IDictionary<string, JsonElement> IgnoredExtensionData { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.TestSupport;
using Swashbuckle.AspNetCore.SwaggerGen.Test.Fixtures;
using Xunit;

namespace Swashbuckle.AspNetCore.SwaggerGen.Test
Expand Down Expand Up @@ -824,6 +825,22 @@ public void GenerateSchema_HonorsSerializerAttribute_JsonExtensionData()
Assert.Null(schema.AdditionalProperties.Type);
}

[Fact]
public void GenerateSchema_HonorsAttribute_SwaggerIgnore()
{
var schemaRepository = new SchemaRepository();

var referenceSchema = Subject().GenerateSchema(typeof(SwaggerIngoreAnnotatedType), schemaRepository);

var schema = schemaRepository.Schemas[referenceSchema.Reference.Id];

Assert.True(schema.Properties.ContainsKey(nameof(SwaggerIngoreAnnotatedType.NotIgnoredString)));
Assert.False(schema.Properties.ContainsKey(nameof(SwaggerIngoreAnnotatedType.IgnoredString)));
Assert.False(schema.Properties.ContainsKey(nameof(SwaggerIngoreAnnotatedType.IgnoredExtensionData)));
Assert.False(schema.AdditionalPropertiesAllowed);
Assert.Null(schema.AdditionalProperties);
}

[Theory]
[InlineData(typeof(object))]
[InlineData(typeof(JsonDocument))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,27 @@ public void GetSwagger_SetsDeprecated_IfActionHasObsoleteAttribute()
Assert.Equal(expectedParameterLocation, parameter.In);
}

[Fact]
public void GetSwagger_IgnoresOperations_IfOperationHasSwaggerIgnoreAttribute()
{
var subject = Subject(
apiDescriptions: new[]
{
ApiDescriptionFactory.Create<FakeController>(
c => nameof(c.ActionWithSwaggerIgnoreAttribute),
groupName: "v1",
httpMethod: "POST",
relativePath: "ignored",
parameterDescriptions: Array.Empty<ApiParameterDescription>()
)
}
);

var document = subject.GetSwagger("v1");

Assert.Empty(document.Paths);
}

[Fact]
public void GetSwagger_IgnoresParameters_IfActionParameterHasBindNeverAttribute()
{
Expand Down Expand Up @@ -452,6 +473,35 @@ public void GetSwagger_IgnoresParameters_IfActionParameterHasBindNeverAttribute(
Assert.Empty(operation.Parameters);
}

[Fact]
public void GetSwagger_IgnoresParameters_IfActionParameterHasSwaggerIgnoreAttribute()
{
var subject = Subject(
new[]
{
ApiDescriptionFactory.Create<FakeController>(
c => nameof(c.ActionWithIntParameterWithSwaggerIgnoreAttribute),
groupName: "v1",
httpMethod: "POST",
relativePath: "resource",
parameterDescriptions: new[]
{
new ApiParameterDescription
{
Name = "param",
Source = BindingSource.Query
}
}
)
}
);

var document = subject.GetSwagger("v1");

var operation = document.Paths["/resource"].Operations[OperationType.Post];
Assert.Empty(operation.Parameters);
}

[Fact]
public void GetSwagger_SetsParameterRequired_IfApiParameterIsBoundToPath()
{
Expand Down

0 comments on commit 1c29b4b

Please sign in to comment.