Skip to main content

Command Palette

Search for a command to run...

JsonIgnore not hiding class property

With NSwag.AspNetCore

Updated
2 min read
JsonIgnore not hiding class property
J

I am a developer in Seattle with interests in Security (cyber and IRL), machine learning, and distributed systems.

Was helping a co-worker determine why a class property was being rendered even though the JsonIgnore attribute was added to that data member.

The request model inherits from a base class which has the properties we want to ignore defined:

public class BaseRequest 
{
    public virtual string? FirstName { get; set; }
}

In the derived class:

public class SomeRequest
{
    [JsonIgnore]
    public override string? FirstName {get; set;}

    [JsonIgnore]
    public string? LastName {get; set;}  // Added for testing.
}

When we view the Swagger UI:

{
    "firstName": "string"
}

The LastName property is ignored, but not the one defined in the base class. This is similar behavior to this Swashbuckle issue, but we're using NSwag.

Steps Attempted:
1. Ensure that System.Text.Json.Serialization.JsonIgnore was used and not Newtonsoft since that was what we’re using as the Serializer.
2. Tried other ignore attributes OpenApiIgnore, NeverBind, even the obsolete SwaggerIgnore.
4. Look into custom filter/provider for schema processing.
5. Bang head.
6. Google some more.
7. Repeat steps 4-7.

The workaround/resolution was reading up on the ApiDocumentGeneratorSettings, SystemTextJsonSchemaGeneratorSettings and DocumentProcessors

Then writing our own `SchemaProcessor:

public class HideInternalProperties : ISchemaProcessor
{
    public void Process(SchemaProcessorContext context)
    {
        foreach (ContextualPropertyInfo property in context.ContextualType.Properties)
        {
            if (!property.PropertyInfo.GetMethod?.IsPublic ?? false)
            {
                string propertyName = context.Settings.ReflectionService.GetPropertyName(property, context.Settings);
                context.Schema.Properties.Remove(propertyName);
            }
        }
    }
}

Update our derived class:

public class SomeRequest
{
    [JsonIgnore]
    internal new string? FirstName {get; set;}

    [JsonIgnore]
    public string? LastName {get; set;}  // Added for testing.
}

Update our service configuration in Program.cs adding: document.SchemaSettings.SchemaProcessors.Add(new HideInternalProperties());

    services.AddEndpointsApiExplorer()
            .AddOpenApiDocument(
                document =>
                {
                    document.Title = "Some API";
                    document.Version = "v1";
                    document.DocumentName = "v\1";
                    document.OperationProcessors.Add(new CorrelationIdHeader());
                    document.SchemaSettings.FlattenInheritanceHierarchy = true;
                    document.AddSecurity(
                        "Bearer",
                        new OpenApiSecurityScheme
                        {
                            Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                            Type = OpenApiSecuritySchemeType.Http,
                            Scheme = JwtBearerDefaults.AuthenticationScheme,
                            BearerFormat = "JWT",
                        }
                    );
                    document.SchemaSettings.SchemaProcessors.Add(new HideInternalProperties());
                    document.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor(JwtBearerDefaults.AuthenticationScheme));
                }
            )

References: