domaindrivendev / Swashbuckle.WebApi

Seamlessly adds a swagger to WebApi projects!
BSD 3-Clause "New" or "Revised" License
3.07k stars 678 forks source link

Swagger JSON including null values which is breaking the UI #219

Closed domaindrivendev closed 9 years ago

domaindrivendev commented 9 years ago

Moving the problem described by @replaysMike in issue #184 here as it's a different problem.

For some reason, he is seeing the returned Swagger JSON include null values. This should not happen and is causing the swagger-ui to break. Looking at the following snippet ...

private HttpContent ContentFor(HttpRequestMessage request, SwaggerDocument swaggerDoc)
{
    var negotiator = request.GetConfiguration().Services.GetContentNegotiator();
    var result = negotiator.Negotiate(typeof(SwaggerDocument), request, GetSupportedSwaggerFormatters());

    return new ObjectContent(typeof(SwaggerDocument), swaggerDoc, result.Formatter, result.MediaType);
}

private IEnumerable<MediaTypeFormatter> GetSupportedSwaggerFormatters()
{
    var jsonFormatter = new JsonMediaTypeFormatter
    {
        SerializerSettings = new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Ignore,
            Converters = new[] { new VendorExtensionsConverter() }
        }
    };
    // NOTE: The custom converter would not be neccessary in Newtonsoft.Json >= 5.0.5 as JsonExtensionData
    // provides similar functionality. But, need to stick with older version for WebApi 5.0.0 compatibility 
    return new[] { jsonFormatter };
}

It's clear that the Swagger JSON should be created with a formatter that explicitly sets NullValueHandling.Ignore. Up until this issue, I've never seen this fail so it must be a very specific WebApi configuration that causes the problem.

@replaysMike - I wonder if by any chance you're using a custom IContentNegotiator?

replaysMike commented 9 years ago

I am indeed ;) I use a JsonContentNegotiator to improve performance of json serialization (caches the media type formatter, as outlined here link)

I'll remove that and test again.

domaindrivendev commented 9 years ago

Bingo!

It's an interesting one this. On the one hand the JsonContentNegotiator breaking the semantics of the negotiator interface. When a consumer (e.g. SB) asks to negotiate for a request based on a supplied set of supported formats it doesn't do that. Hence the issue you've uncovered.

Then on the other hand the use of the IContentNegotiator in SB is overkill here - I could easily achieve the same result without it and reduce the dependency on specific app configurations.

I'm leaning toward the latter but would be interested to hear your thoughts?

Thanks

replaysMike commented 9 years ago

Yup! This was the problem. Removing the content negotiator completely resolves the problem. I would agree, it's probably overkill. However it's also not the norm to be using an IContentNegotiator in the manner I did, since the performance increase is probably negligible. Reducing the dependency would be a smart move unless there is a compelling reason for using it, I'm afraid I'm not familiar enough with the pipeline yet to know why. Less brittle is better :)

Thanks dude.

domaindrivendev commented 9 years ago

I'm going to leave the current code in place for now ...

As a side note, the next major version of SB (targeted to AspNet 6.0 and currently in beta) will address this issue fully.