Невозможно заменить распознаватель контракта JSON по умолчанию в ASP .Core 3 - PullRequest
0 голосов
/ 27 января 2020

После создания базового c проекта Web API на основе. NET Core 3.0 framework все ответы API приходили в случае верблюда. Я установил SwashBuckle Swagger + встроенный JSON сериализатор из System.Text. Json, в частности, чтобы отображать перечисления в виде строк, все работало как раньше. Затем я решил переключиться на NSwag + NewtonSoft Json из-за некоторых ограничений встроенного сериализатора с динамическими c и объектами расширения. Теперь все ответы API отображаются в PascalCase, и я не могу изменить ни политику именования, ни даже создать собственный обработчик контрактов.

Пример

https://forums.asp.net/t/2138758.aspx?Configure+SerializerSettings+ContractResolver

Вопрос

Я подозреваю, что может быть, какой-то пакет переопределяет решатель контрактов за сценой Как убедиться, что служба API использует ТОЛЬКО настраиваемый обработчик контрактов, который я назначаю при запуске, и игнорирует все другие подобные настройки?

Пользовательский JSON распознаватель контрактов

public class CustomContractResolver : IContractResolver
{
  private readonly IHttpContextAccessor _context;
  private readonly IContractResolver _contract;
  private readonly IContractResolver _camelCaseContract;

  public CustomContractResolver(IHttpContextAccessor context)
  {
    _context = context;
    _contract = new DefaultContractResolver();
    _camelCaseContract = new CamelCasePropertyNamesContractResolver();
  }

  // When API endpoint is hit, this method is NOT triggered

  public JsonContract ResolveContract(Type value)
  {
    return _camelCaseContract.ResolveContract(value);
  }
}

Контроллер

[ApiController]
public class RecordsController : ControllerBase
{
  [HttpGet]
  [Route("services/records")]
  [ProducesResponseType(typeof(ResponseModel<RecordEntity>), 200)]
  public async Task<IActionResult> Records([FromQuery] QueryModel queryModel)
  {
    var response = new ResponseModel<RecordEntity>();

    return Content(JsonConvert.SerializeObject(response), "application/json"); // NewtonSoft serializer
  }
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
  services
    .AddCors(o => o.AddDefaultPolicy(builder => builder
      .AllowAnyOrigin()
      .AllowAnyHeader()
      .AllowAnyMethod()));

  services
    .AddControllers(o => o.RespectBrowserAcceptHeader = true)
    /*
    .AddJsonOptions(o =>
    {
      o.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
      o.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
      o.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    })
    */
    .AddNewtonsoftJson(o =>
    {
      o.UseCamelCasing(true);
      o.SerializerSettings.Converters.Add(new StringEnumConverter());
      //o.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver { NamingStrategy = new CamelCaseNamingStrategy() };
      o.SerializerSettings.ContractResolver = new CustomContractResolver(new HttpContextAccessor());
    });

  services.AddOpenApiDocument(o =>   // NSwag
  {
    o.PostProcess = document =>
    {
      document.Info.Version = "v1";
      document.Info.Title = "Demo API";
    };
  });

  DataConnection.DefaultSettings = new ConnectionManager(DatabaseOptionManager.Instance); // LINQ to DB
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  if (env.IsDevelopment())
  {
    app.UseDeveloperExceptionPage();
  }

  app.UseCors(o => o.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
  app.UseRouting();
  app.UseAuthorization();
  app.UseEndpoints(o => o.MapControllers());

  app.UseOpenApi();                                // NSwag
  app.UseSwaggerUi3(o => o.Path = "/v2/docs");
  app.UseReDoc(o => o.Path = "/v1/docs");
}

1 Ответ

0 голосов
/ 28 января 2020

До сих пор не понимаю, почему пользовательский обработчик контрактов не запускается конечной точкой API, но нашел комбинацию, которая помогает мне переключить API на случай верблюда. Не стесняйтесь объяснить, почему это так работает.

services.AddControllers(o => o.RespectBrowserAcceptHeader = true)

  // Options for System.Text.Json don't affect anything, can be uncommented or removed

  //.AddJsonOptions(o =>
  //{
  //  o.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
  //  o.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
  //  o.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
  //})

  .AddNewtonsoftJson(o =>
  {
    o.UseCamelCasing(true);
    o.SerializerSettings.Converters.Add(new StringEnumConverter());

    // This option below breaks global settings, so had to comment it

    //o.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver 
    //{
    //  NamingStrategy = new CamelCaseNamingStrategy()
    //};
  });

JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
  ContractResolver = new CamelCasePropertyNamesContractResolver()
};

Идея была взята из этой статьи .

NewtonSoft позволяет установить глобальные параметры сериализации без учета MVC, веб-API и другие рамки.

...