zyash
zyash

Reputation: 732

NSwag customizing JSON output

I have a class:

class Test {
  public IPAddress Ip {get; set; }
}

By default, Nswag (Nswag.AspNetCore package) at http://localhost:1234/swagger serializes it as so, in the preview "Example" output:

[    
  "Ip": {
     "AddressFamily": 0,
     "ScopeId": 0,
     "IsIPv6Multicast": true,
     "IsIPv6LinkLocal": true,
     "IsIPv6SiteLocal": true,
     "IsIPv6Teredo": true,
     "IsIPv4MappedToIPv6": true,
     "Address": 0
    }
]

I want to custimize it, so that it serializes just the Ip field as a string without all the other type properties of IPAddress.

To do that, I created my own JsonConverter:

public class IPAddressConverter : JsonConverter
{ 
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(IPAddress));
    }

    public override void WriteJson(JsonWriter writer, object value,   JsonSerializer serializer)
    {
        writer.WriteValue(value.ToString());
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    { 
        return IPAddress.Parse((string)reader.Value);
    }
}

And verified that it works with JSON.Net.

var settings = new JsonSerializerSettings() { Converters =  { new IPAddressConverter() } };
JsonConvert.SerializeObject(IPAddress.Parse("123.123.123.123"), settings);
JsonConvert.DeserializeObject<IPAddress>("123.123.123.123", settings);

Now I wanted to plug this into NSwag. I modified the NSwag settings like so inside ASP.Net's Startup.cs:

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc();

        var swaggerSettings = new SwaggerUi3Settings()
        { 
            ContractResolver = new CustomSwaggerContractResolver(),
            DefaultPropertyNameHandling = NJsonSchema.PropertyNameHandling.Default /* If this is not set to default it raises an exception when a ContractResolver is set and then swagger page does not load at all */
        };

        app.UseSwaggerUi3(typeof(Startup).Assembly, swaggerSettings);
 }

#

public class CustomSwaggerContractResolver : DefaultContractResolver
{   
    protected override JsonContract CreateContract(Type objectType)
    {  
        JsonContract contract = base.CreateContract(objectType);

        if (objectType == typeof(IPAddress))
        {
            contract.Converter = new IPAddressConverter();
        }  

        return contract;
    }
} 

Unfortunately when I browse to http://localhost:1234/swagger to see the Json "Example" output of my Test class, it is still including all the properties of IPAddress instead of Ip field being serialized as a simple string.

When I debug I can see that code inside CustomSwaggerContractResolver is called, and the converter is assigned, but the IPAddressConverter itself is never being called.

Is there anything that I am missing?

Thank you.

Upvotes: 4

Views: 10022

Answers (1)

Rico Suter
Rico Suter

Reputation: 11858

Because the transformation of a converter cannot be reflected (it is procedural) you need to add a type mapper

https://github.com/RSuter/NJsonSchema/wiki/Type-Mappers

and map the ipaddress type to a simple string schema

(NJsonSchema is the base of NSwag)

Upvotes: 5

Related Questions