NSwag icon indicating copy to clipboard operation
NSwag copied to clipboard

The ignore condition 'JsonIgnoreCondition.WhenWritingNull' is not valid on value-type member

Open Mosie1 opened this issue 2 years ago • 13 comments

Hello,

Since version 13.16.0 of Nswag, the following attribute is added to all properties of the generated models when generating the C# clients. [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)]

This causes the following errors on value type properties. The ignore condition 'JsonIgnoreCondition.WhenWritingNull' is not valid on value-type member 'LanguageId' on type 'User'. Consider using 'JsonIgnoreCondition.WhenWritingDefault'.

Is there a way to disable the generation of this attribute?

Kind regards, Jorsi

Mosie1 avatar May 19 '22 09:05 Mosie1

I had to use v13.15.0... same bug.

bool/int/guid/datetime ..... --> WhenWritingDefault bool?...Nullable<T> --> WhenWritingNull

shuaqq2004 avatar May 20 '22 03:05 shuaqq2004

Hello,

I am experiencing the same issue (as above).

I am using v10.7.0 of the NJsonSchema and NJsonSchema.CodeGeneration.CSharp NuGet packages when generating classes from a JSON schema using the CSharpGenerator c;lass with:

settings.JsonLibrary = CSharpJsonLibrary.SystemTextJson;

It generates the following property (simple bool):

[System.Text.Json.Serialization.JsonPropertyName("unavailable")] [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] public bool Unavailable { get; set; }

When I generated the classes via https://apimundo.com/tools?tab=jsonschema-to-csharp it produced the following:

[System.Text.Json.Serialization.JsonPropertyName("unavailable")] public bool Unavailable { get; set; }

The addition of the "System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull" conditions causes System.Text.Json serialization to fail with: "The ignore condition 'JsonIgnoreCondition.WhenWritingNull' is not valid on value-type member 'Unavailable'".

I don't know if this is related to: https://github.com/RicoSuter/NJsonSchema/blob/master/src/NJsonSchema.CodeGeneration.CSharp/Models/PropertyModel.cs

Line 72

/// <summary>Returns the System.Text.Json.Serialization.JsonIgnoreCondition value to be applied to the property.</summary> public string JsonIgnoreCondition => _property switch { { IsRequired: false } => "System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull", { IsRequired: true } when _settings.RequiredPropertiesMustBeDefined => "System.Text.Json.Serialization.JsonIgnoreCondition.Never", _ => null };

Many thanks,

Chris.

ChrisWCurry avatar May 20 '22 16:05 ChrisWCurry

It looks like rolling back to 13.15.10 resolves this issue for the time being.

Alundra828 avatar May 24 '22 01:05 Alundra828

It looks like rolling back to 13.15.10 resolves this issue for the time being.

In my case, moving back to NJsonSchema and NJsonSchema.CodeGeneration.CSharp 10.6.10 resolved my issue.

I did try the 10.7.1 version (which came out on Wednesday), but the issue is still the same in that release.

ChrisWCurry avatar May 24 '22 08:05 ChrisWCurry

Experiencing the same issue, this seems like quite a serious bug since we cannot use non-nullable value types in our models. Cannot rollback as we also need #1512 Hoping the pull request gets merged soon.

binginsin avatar May 26 '22 14:05 binginsin

Same here.

timmkrause avatar Jun 02 '22 14:06 timmkrause

Also experiencing this issue

agilenut avatar Jun 04 '22 00:06 agilenut

Ping @RicoSuter

bdovaz avatar Jun 04 '22 07:06 bdovaz

Having issues with this also. Will revert to previous version in the meantime.

mtbayley avatar Jun 10 '22 17:06 mtbayley

we are also experiencing this issue, however rolling back to 13.15.10 has resolved it for now.

gavin2n avatar Jun 13 '22 08:06 gavin2n

Same here.

awp-sirius avatar Jun 13 '22 14:06 awp-sirius

Same with v13.16.1. Following solution resolved the issue :

It looks like rolling back to 13.15.10 resolves this issue for the time being.

Keviento avatar Jun 22 '22 15:06 Keviento

Any update on this? The latest package version has had a show stopping issue for almost 3 months now.

agilenut avatar Aug 05 '22 18:08 agilenut

Same problem here!

frabe1579 avatar Aug 31 '22 10:08 frabe1579

@RicoSuter - Thanks for the fix!! I just hit this issue with NSwag.MSBuild. Could we get an updated version of that package published to Nuget?

lukewis avatar Sep 02 '22 20:09 lukewis

Same problem here!

bdovaz avatar Sep 03 '22 10:09 bdovaz

How can i opt-out of this bevaviour or force my values?

Before these changes there was no attribute what so ever (so the default behaviour of STJ i assume). Then it was briefly System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull. And now its different again. This is kinda breaking...

This breaks alot of my connectors, assumptions and tests. Often a called backend service is not that easily to change.

From my current understanding of the code base its now either "WhenWritingDefault" or "Never" depending of the property if "required" or not. And nothing else?

The broken stuff is also subtle. Took me some time to find out the an INT 0 was not send because the whole property was disregarded because it was not required.

ThomasTosik avatar Nov 21 '22 08:11 ThomasTosik

I agree with @ThomasTosik, there should be a way to opt-out of the JsonIgnore attribute altogether. For the time being, I removed it this way:

public class EmbeddedTemplateFactory : DefaultTemplateFactory
{
    public EmbeddedTemplateFactory(CSharpClientGeneratorSettings settings)
        : base(settings.CSharpGeneratorSettings, new[] { settings.GetType().Assembly, settings.CSharpGeneratorSettings.GetType().Assembly })
    {
    }

    protected override string GetEmbeddedLiquidTemplate(string language, string template)
    {
        var result = base.GetEmbeddedLiquidTemplate(language, template);

        // Do not include JsonIgnore attributes.
        // https://github.com/RicoSuter/NJsonSchema/blob/e045ae82b55d4e8ae9f6690a27d907c699e3c9ee/src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid#L56
        // https://github.com/RicoSuter/NJsonSchema/blob/e045ae82b55d4e8ae9f6690a27d907c699e3c9ee/src/NJsonSchema.CodeGeneration.CSharp/Models/PropertyModel.cs#L72
        result = result.Replace("property.HasJsonIgnoreCondition", "false");

        return result;
    }
}
var json = await client.GetStringAsync(url);
var document = await OpenApiDocument.FromJsonAsync(json);
var settings = new CSharpClientGeneratorSettings
{
    // ...
};
settings.CSharpGeneratorSettings.TemplateFactory = new EmbeddedTemplateFactory(settings);
var generator = new RefitGenerator(document, settings);
var proxy = generator.GenerateFile();

gabrielmaldi avatar Nov 21 '22 15:11 gabrielmaldi

Just another +1 for this issue. We are consuming an API outside of our control, that has valid enum values of 0, that aren't marked as required, but we still want to send them, but aren't being serialized and sent.

rebecca-work avatar Feb 01 '23 16:02 rebecca-work

It would be nice to control this behaviour in a better way as there is no default that will suit everyone (except for never ignoring, but that sends unnecessary data over the network).

For people who need desperately need this changed, look into custom templates. At my work I have created a nuget package that contains multiple templates which completely change the generated code (to fit our use which was very non standard). The templates could definitely be used to modify this behaviour and should be quicker to do than change to a different generator. Once I have time i will look at updating / writing a guide on using templates with MsBuild/OpenApiReference tags.

binginsin avatar May 23 '23 16:05 binginsin

@rebecca-work @binginsin, you can use the workaround I described in https://github.com/RicoSuter/NSwag/issues/4012#issuecomment-1322279858

gabrielmaldi avatar May 23 '23 16:05 gabrielmaldi

I couldn't figure out how to use that workaround - we just use NSwag on the command line (dotnet tool), so I'm not sure how custom templates fit in to that toolchain.

(Also I commented on this earlier but then realised there's another open issue tracking this, so moved my comment there instead: https://github.com/RicoSuter/NJsonSchema/issues/1564)

mooski avatar May 23 '23 16:05 mooski

I used this code to circumvent the problem at runtime.

internal partial class UserClient // NSwag generated client
{
    partial void UpdateJsonSerializerSettings(System.Text.Json.JsonSerializerOptions settings)
    {
        settings.TypeInfoResolver = new DefaultJsonTypeInfoResolver
        {
            Modifiers = { JsonHelper.AlwaysSerializeValueTypeProperties }
        };
    }
}

file sealed class JsonHelper
{
    private static readonly Func<object, object?, bool> AlwaysSerialize = (_, __) => true;

    /// <summary>
    /// NSwag generates JsonIgnoreCondition.WhenWritingDefault for value type properties (enum, int, bool, etc.) which is wrong.
    /// </summary>
    public static void AlwaysSerializeValueTypeProperties(JsonTypeInfo ti)
    {
        // https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/custom-contracts

        foreach (var prop in ti.Properties)
        {
            if (prop.PropertyType.IsValueType && prop.AttributeProvider is not null)
            {
                prop.ShouldSerialize = AlwaysSerialize;
            }
        }
    }
}

espenrl avatar Aug 09 '23 14:08 espenrl