Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JsonProperty(ItemConverterType = typeof(StringEnumConverter)) not recognized without DescribeAllEnumsAsStrings() #1349

Closed
artfulsage opened this issue Oct 30, 2019 · 11 comments

Comments

@artfulsage
Copy link

Hi. In Swashbuckle.AspNetCore 5.0.0-rc4 method SwaggerGenOptions.DescribeAllEnumsAsStrings() marked as Obsolete. But without it attribute [Newtonsoft.Json.JsonProperty(ItemConverterType = typeof(Newtonsoft.Json.Converters.StringEnumConverter))] is not working properly. See example below.

public class Program
{
	public static void Main(string[] args)
		=> Host.CreateDefaultBuilder(args)
			.ConfigureWebHostDefaults(b => b.UseStartup<Startup>())
			.Build()
			.Run();
}

public class Startup
{
	public void ConfigureServices(IServiceCollection services)
		=> services
			.AddSwaggerGen(c => c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v1" }))
			.AddControllers();

	public void Configure(IApplicationBuilder app)
		=> app
			.UseSwagger()
			.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "v1"))
			.UseRouting()
			.UseEndpoints(endpoints => endpoints.MapControllers());
}

[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter), true)]
public enum OkEnum
{
	Freezing, Bracing, Chilly, Cool
}

public enum BadEnum
{
	Freezing, Bracing, Chilly, Cool
}

public class WeatherForecast
{
	public DateTime Date { get; set; }
	public OkEnum OkValue { get; set; }
	[Newtonsoft.Json.JsonProperty(ItemConverterType = typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
	public List<BadEnum> BadValues { get; set; }
}

[ApiController]
[Route("weather")]
public class WeatherForecastController : ControllerBase
{
	[HttpGet]
	public IEnumerable<WeatherForecast> Get()
		=> Enumerable.Range(1, 5).Select(index => new WeatherForecast
		{
			Date = DateTime.Now.AddDays(index),
			OkValue = OkEnum.Cool,
			BadValues = new List<BadEnum> { BadEnum.Cool }
		});
}

sw

With SwaggerGenOptions.DescribeAllEnumsAsStrings()

sw3

@Mds92
Copy link

Mds92 commented Dec 24, 2019

I have the same problem

@domaindrivendev
Copy link
Owner

@artfulsage can you elaborate a little more on your usecase? I do understand the issue you're reporting but I guess I'm not understanding why you wouldn't just use the JsonConverterAttribute on the enum definition itself (as opposed to the property that uses it) - i.e. as you've demonstrated with OkEnum above.

The only reason I can think of to NOT do this is if you wanted to serialize the enum as a string in some cases (e.g. when part of a certain property) and as an integer in others. However, the DescribeAllEnumsAsStrings is a global setting applied to all enums and therefore wouldn't support this scenario anyway.

@ddeisadzevp
Copy link

I have the same problem (using 5.0.0 RC-5). I have tried adding a global JsonConvert (StringEnumConverter) to json serializer settings along with DescribeAllEnumsAsStrings, just DescribeAllEnumsAsStrings , StringEnumConverter on the enum itself. None of these options seem to work, the enums still return as integers. I am not sure what other information to display for this issue, but let me know.

@jcoutch
Copy link

jcoutch commented Jan 6, 2020

@artfulsage - You're using Newtonsoft attributes, but Swashbuckle.AspNetCore 5.x uses System.Text.Json by default.

To fix this, either:

  • Use [JsonConverter(typeof(JsonStringEnumConverter))] from the System.Text.Json.Serialization namespace on your enum declarations

  • Or to convert all enums to strings, in your ConfigureServices method, add the following after AddControllers():

.AddJsonOptions(options => {
    options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
});
  • If you need to use Newtonsoft for serialization, add the Swashbuckle.AspNetCore.Newtonsoft Nuget package and call services.AddSwaggerGenNewtonsoftSupport() in Startup.cs -> ConfigureServices

@artfulsage
Copy link
Author

@domaindrivendev, @jcoutch thanks for your feedback!

  • My enum is located in separated database project. And that's why I don't want to put any code for serialization there (JsonConverterAttribute).

  • Addition of services.AddSwaggerGenNewtonsoftSupport() seems not working in my real project.

  • But this works fine!

.AddJsonOptions(options => {
    options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
});

@ddeisadzevp
Copy link

@domaindrivendev it might be helpful to add that to the docs/WIKI (FAQ) : services.AddSwaggerGenNewtonsoftSupport() for future reference, seems like it is a commonly asked question

@jcoutch
Copy link

jcoutch commented Jan 9, 2020

@tobyartisan
Copy link

@artfulsage, when you use services.AddSwaggerGenNewtonsoftSupport(), then ensure that you add it after you add services.AddSwaggerGen(...); otherwise, it won't work.

@artfulsage
Copy link
Author

@domaindrivendev @jcoutch @tobyartisan perhaps I do something wrong but this code still does not work

netcoreapp3.1
Newtonsoft.Json 12.0.3
Swashbuckle.AspNetCore 5.2.1
Swashbuckle.AspNetCore.Newtonsoft 5.2.1

public class Program
{
  public static void Main(string[] args)
    => Host.CreateDefaultBuilder(args)
      .ConfigureWebHostDefaults(b => b.UseStartup<Startup>())
      .Build()
      .Run();
}

public class Startup
{
  public void ConfigureServices(IServiceCollection services)
  {
    services
      .AddMvc()
      .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
      .AddNewtonsoftJson();

    services
      .AddSwaggerGen(c => c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v1" }))
      .AddSwaggerGenNewtonsoftSupport();
  }

  public void Configure(IApplicationBuilder app)
    => app
      .UseSwagger()
      .UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "v1"))
      .UseRouting()
      .UseEndpoints(endpoints => endpoints.MapControllers());
}

public enum BadEnum
{
  Freezing, Bracing, Chilly, Cool
}

public class WeatherForecast
{
  public DateTime Date { get; set; }
  [Newtonsoft.Json.JsonProperty(ItemConverterType = typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
  public List<BadEnum> BadValues { get; set; }
}

[ApiController]
[Route("weather")]
public class WeatherForecastController : ControllerBase
{
  [HttpGet]
  public IEnumerable<WeatherForecast> Get()
    => Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
      Date = DateTime.Now.AddDays(index),
      BadValues = new List<BadEnum> { BadEnum.Cool }
    });
}

Screenshot_2020-03-24 Swagger UI

Screenshot_2020-03-24 Screenshot

@simonvane
Copy link

@artfulsage Do you need to do this bit?

.AddJsonOptions(options => {
    options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
});

@domaindrivendev
Copy link
Owner

@artfulsage - unfortunately ItemConverterType isn't currently supported. As mentioned above, if you decorate your enum class directly as follows - the enum will be described correctly.

[JsonConverter(typeof(StringEnumConverter))]
public enum BadEnum
{
    Freezing, Bracing, Chilly, Cool
}

However, it seems this may not be feasible for you. As many of the comments in this issue have deviated from the original, I think it would be best to create a new issue that specifically addresses the lack of support for enum serialization behavior that's configured via ItemConverterType

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants