Custom System.Text.Json Converter string not working

476 views Asked by At

I wrote a string custom System.Text.Json converter

public class TranslatableJsonConverter : JsonConverter<string>
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public TranslatableJsonConverter(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
    {
        var request = _httpContextAccessor.HttpContext?.Request;
        if (request is null)
        {
            writer.WriteStringValue(value);
            return;
        }
        var acceptLanguage = request.GetUserLanguage();
        writer.WriteStringValue($"KPI_FAMILY_{value}".Translate(acceptLanguage));
    }
}

Here, I injected the IHttpContextAccessor because I have to retrieve an header field to process a string property of a record dto. Then I registered the custom converter in the following way:

public class ConfigureJsonOptions : IConfigureOptions<JsonOptions>
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public ConfigureJsonOptions(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    public void Configure(JsonOptions options)
    {
        options.JsonSerializerOptions.Converters.Add(new TranslatableJsonConverter(_httpContextAccessor));
    }
}

// Startup.cs
services.AddHttpContextAccessor();
services.ConfigureOptions<ConfigureJsonOptions>();

So, I decorated the property that I'd like to process:

public record DriverBehaviourFamilyCountersDto
{
    [JsonConverter(typeof(TranslatableJsonConverter))]
    public string Name { get; set; }
    
    public IEnumerable<BehaviourCounterDto> Behaviours { get; set; }
}

The problem is that I get the following exception, when serialization happens

System.InvalidOperationException: The converter specified on 'Video.Analytics.DriverBehavior.Coaching.BFF.Api.Dto.Output.DriverBehaviourFamilyCountersDto.Name' does not derive from JsonConverter or have a public parameterless constructor.\r\n at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializationConverterOnAttributeInvalid(Type classType, MemberInfo memberInfo)\r\n at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetConverterFromAttribute(JsonConverterAttribute converterAttribute, Type typeToConvert, MemberInfo memberInfo, JsonSerializerOptions options)\r\n at System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver.GetCustomConverterForMember(Type typeToConvert, MemberInfo memberInfo, JsonSerializerOptions options)\r\n at System.Text.Json.Serialization.Metadata.ReflectionJsonTypeInfo1.CreateProperty(Type typeToConvert, MemberInfo memberInfo, JsonSerializerOptions options, Boolean shouldCheckForRequiredKeyword)\r\n at System.Text.Json.Serialization.Metadata.ReflectionJsonTypeInfo1.LateAddProperties()\r\n at System.Text.Json.Serialization.Metadata.JsonTypeInfo.InitializePropertyCache()\r\n at System.Text.Json.Serialization.Metadata.JsonTypeInfo.Configure()\r\n
at System.Text.Json.Serialization.Metadata.JsonTypeInfo.g__ConfigureLocked|143_0()\r\n at System.Text.Json.Serialization.Metadata.JsonTypeInfo.EnsureConfigured()\r\n at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Boolean resolveIfMutable)\r\n at System.Text.Json.Serialization.Metadata.JsonTypeInfo.get_ElementTypeInfo()\r\n at System.Text.Json.Serialization.JsonCollectionConverter2.OnTryWrite(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, WriteStack& state)\r\n at System.Text.Json.Serialization.JsonConverter1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)\r\n at System.Text.Json.Serialization.Metadata.JsonPropertyInfo1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)\r\n at System.Text.Json.Serialization.Converters.ObjectDefaultConverter1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)\r\n at System.Text.Json.Serialization.JsonConverter1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)\r\n at System.Text.Json.Serialization.JsonConverter1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)\r\n at System.Text.Json.Serialization.JsonConverter`1.WriteCoreAsObject(Utf8JsonWriter writer, Object value, JsonSerializerOptions options, WriteStack& state)\r\n at System.Text.Json.JsonSerializer.WriteCore[TValue](Utf8JsonWriter writer, TValue& value, JsonTypeInfo jsonTypeInfo, WriteStack& state)\r\n at System.Text.Json.JsonSerializer.WriteStreamAsync[TValue](Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)\r\n at System.Text.Json.JsonSerializer.WriteStreamAsync[TValue](Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)\r\n at System.Text.Json.JsonSerializer.WriteStreamAsync[TValue](Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)\r\n at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()\r\n--- End of stack trace from previous location ---\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)\r\n at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)\r\n at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)\r\n at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)\r\n at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)\r\n at Serilog.AspNetCore.RequestLoggingMiddleware.Invoke(HttpContext httpContext)\r\n at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)"

Could you help me please?

0

There are 0 answers