Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

294
Visualizações
JsonConverter not working in integration tests

I've enabled my API to serialize/deserialize enum using string values. To do that I've added JsonStringEnumConverter to the list of supported JsonConverters in my API's Startup class:

.AddJsonOptions(opts =>
{
    var enumConverter = new JsonStringEnumConverter();
    opts.JsonSerializerOptions.Converters.Add(enumConverter);
});

It works fine- my API succeessfully serialize and deserialize enums as a string.

Now- I'm trying to build integration test for my API and having some issue. I'm using HttpContentJsonExtensions.ReadFromJsonAsync to deserialize the API response but an exception is thrown over an enum property.

The problem is obvious- HttpContentJsonExtensions.ReadFromJsonAsync is not aware to the list of converters used by the API (since, as I mentioned earlier, I've added the JsonStringEnumConverter to the list of supported converters and it works fine).

If I do this in my test function:

var options = new System.Text.Json.JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverter());
SomeClass result= await response.Content.ReadFromJsonAsync<SomeClass>(options);

Then the enum property is deserialized and no exception is thrown. However now, ReadFromJsonAsync is only aware of JsonStringEnumConverter and not to other JSON converters that are used by the API (like Guid converter)

How can I make sure that HttpContentJsonExtensions.ReadFromJsonAsync will be able to use all JSON converters that are used by the API?

Thanks!

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

There is, unfortunately, no way to achieve this out of the box. The reason is that the "designers" of the System.Text.Json APIs decided, in an unbelievably baffling move, to make said APIs static - probably to mimic the well-know Newtonsoft.Json - but static APIs, of course, cannot carry state along with them. For more context I refer you to the feature request to fix this poor design.

I actually came up with a solution in that FR, which I've tweaked a little since I concocted it:

public interface IJsonSerializer
{
    JsonSerializerOptions Options { get; }

    Task<T> DeserializeAsync<T>(Stream utf8Json, CancellationToken cancellationToken);

    // other methods elided for brevity
}

public class DefaultJsonSerializer : IJsonSerializer
{
    private JsonSerializerOptions _options;
    public JsonSerializerOptions Options
        => new JsonSerializerOptions(_options); // copy constructor so that callers cannot mutate the options

    public DefaultJsonSerializer(IOptions<JsonSerializerOptions> options)
        => _options = options.Value;

    public async Task<T> DeserializeAsync<T>(Stream utf8Json, CancellationToken cancellationToken = default)
        => await JsonSerializer.DeserializeAsync<T>(utf8Json, Options, cancellationToken);

    // other methods elided for brevity
}

Essentially you define a wrapper interface with method signatures identical to the static ones of JsonSerializer (minus the JsonSerializerOptions parameter as you want to use the ones defined on the class), then a default implementation of said interface that delegates to the static JsonSerializer methods. Map the interface to the implementation in Startup.ConfigureServices and instead of calling the static JsonSerializer methods in the classes that need to handle JSON, you inject your JSON interface into those classes and use it.

Given that you're using HttpContentJsonExtensions, you will additionally need to define your own wrapper version of that extension class that duplicates its method signatures but replaces their JsonSerializerOptions parameters with instances of your JSON serialization interface, then passes said interface's options through to the underlying HttpContentJsonExtensions implementation:

public static class IJsonSerializerHttpContentJsonExtensions
{
    public static Task<object?> ReadFromJsonAsync(this HttpContent content, Type type, IJsonSerializer serializer, CancellationToken cancellationToken = default)
        => HttpContentJsonExtensions.ReadFromJsonAsync(content, type, serializer.Options, cancellationToken);

    // other methods elided for brevity
}

Is it painful? Yes. Is it unnecessary? Also yes. Is it stupid? A third time, yes. But such is Microsoft.

over 4 years ago · Santiago Trujillo Relatório

0

I had the same exact issue as described by the OP and my code looked very much the same except I had and Enum and DateOnly converter. I was using the System.Text.Json classes. For me, the problem was that I needed to change another property on the serialization options. I previously just had this:

// Setup custom serializers
var serializerOptions = new JsonSerializerOptions
{
   Converters = { new Data.DateOnlyConverter(), new Data.EnumStatusConverter() }
};

I needed to add the following to the serializerOptions object:

serializerOptions.PropertyNameCaseInsensitive = true;

and then my tests could deserialize the values from my PostAsAsync functions.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda