You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is because the property is not listed in the required array for the type, however I think this behaviour is undesirable, as a non-bullable type should be required by definition.
I have made a filter which resolves this for me. See attached code below. I was wondering if you agree that the default behaviour should be that non-nullable types are in the reqired list required by definition?
Usage:
services.AddSwaggerGen(options =>{options.SupportNonNullableReferenceTypes();// Insufficientoptions.SchemaFilter<FixNullableAndRequiredInSchemaFilter>();// My 'fix'
usingSystem.Reflection;usingMicrosoft.OpenApi.Models;usingSwashbuckle.AspNetCore.SwaggerGen;namespaceSwagger;publicsealedclassFixNullableAndRequiredInSchemaFilter:ISchemaFilter{publicvoidApply(OpenApiSchemaschema,SchemaFilterContextcontext){Typetype=context.Type;if(type.ShouldExcludeAsPrimitive()){return;}schema.Required.Clear();varproperties=type.GetProperties(BindingFlags.Public|BindingFlags.Instance);foreach(varpropertyinproperties){stringschemaName=property.ToSchemaName();// Some types have a variety of reasons to be excluded from serialisation,// e.g. [JsonExtensionData] so only change them if they are in the collection.if(schema.Properties.ContainsKey(schemaName)){boolhasNullableAttribute=type.HasNullableAttribute(property);schema.Properties[schemaName].Nullable=hasNullableAttribute;if(!hasNullableAttribute){schema.Required.Add(schemaName);}}}}}
Helpers
usingSystem.Reflection;usingSystem.Text.Json;usingSystem.Text.Json.Serialization;namespaceSwagger;publicstaticclassSwaggerHelperExtensions{// Note: these are compiler internal types.privateconststringNullableContextAttributeName="NullableContextAttribute";privateconststringNullableAttributeName="NullableAttribute";privateenumNullabilityMode{Unknown,NullableByDefault,NonNullableByDefault}publicstaticboolShouldExcludeAsPrimitive(thisTypetype){if(type==typeof(string)||type.IsPrimitive){returntrue;}else{varunderlying=Nullable.GetUnderlyingType(type);if(underlying!=null&&(underlying==typeof(string)||underlying.IsPrimitive)){returntrue;}}returnfalse;}publicstaticstringToSchemaName(thisPropertyInfoproperty){varname=property.GetCustomAttribute<JsonPropertyNameAttribute>()?.Name??property.Name;returnToSchemaName(name);}privatestaticstringToSchemaName(stringname){varjsonPropertyName=JsonNamingPolicy.CamelCase.ConvertName(name);returnjsonPropertyName;}publicstaticboolHasNullableAttribute(thisTypetype,PropertyInfopropertyInfo){if(propertyInfo.PropertyType.IsValueType){returnNullable.GetUnderlyingType(propertyInfo.PropertyType)!=null;}varattributes=propertyInfo.GetCustomAttributesData();boolhasNullableAttribute=attributes.Any(x =>x.AttributeType.Name==NullableAttributeName);varmode=type.EstablishNullabilityMode();returnmodeswitch{NullabilityMode.Unknown=>hasNullableAttribute,NullabilityMode.NullableByDefault=>hasNullableAttribute,NullabilityMode.NonNullableByDefault=>!hasNullableAttribute,
_ =>thrownewInvalidOperationException($"Unknown {nameof(NullabilityMode)} mode {mode}")};}// Gnarly. I can't find a better way..privatestaticNullabilityModeEstablishNullabilityMode(thisTypetype){varnullableContextAttribute=type.GetCustomAttributesData().FirstOrDefault(x =>x.AttributeType.Name==NullableContextAttributeName);if(nullableContextAttribute!=null&&nullableContextAttribute.ConstructorArguments.Count==1){object?value=nullableContextAttribute.ConstructorArguments[0].Value;if(valueisbyteb){if(b==1){// If the NullableContextAttribute is 1, the type is considered nullable by default.returnNullabilityMode.NullableByDefault;}elseif(b==2){// If the NullableContextAttribute is 2, the type is| considered non-nullable by default.returnNullabilityMode.NonNullableByDefault;}else{thrownewUnknownNullabilityModeException($"Unknown nullability mode for type {type.Name}");}}}returnNullabilityMode.Unknown;}privatesealedclassUnknownNullabilityModeException:Exception{publicUnknownNullabilityModeException(stringmessage):base(message){}}}
The text was updated successfully, but these errors were encountered:
JonnyWideFoot
changed the title
Required unpopulated on nullable record properties (dotnet7)
'Required' remains unpopulated for nullable record properties (dotnet7)
Mar 27, 2023
To make issue tracking a bit less overwhelming for the new maintainers (see #2778), I've created a new tracking issue to roll-up various nullability issues here: #2793.
We'll refer back to this issue from there and include it as part of resolving that issue, but I'm going to close this one to help prune the backlog.
Problem Statment
I have the following response type in a C# dotnet 7.0 project, with enable in the csproj:
By default, swagger is generating this type as:
Which is interpreted by my openAPI generator as:
This is not what I want, as nullability does not match the C# type.
If I enable 'SupportNonNullableReferenceTypes':
Then the nullability is corrected in the swagger json file:
However this generates with "id?", not "id":
This is because the property is not listed in the required array for the type, however I think this behaviour is undesirable, as a non-bullable type should be required by definition.
I have made a filter which resolves this for me. See attached code below. I was wondering if you agree that the default behaviour should be that non-nullable types are in the reqired list required by definition?
Usage:
Results in:
And generates a client thus:
Bug or intended behaviour?
Sample Code
Filter
Helpers
Tests
The text was updated successfully, but these errors were encountered: