Open Closed

Cannot Use ExtraProperties with Interface Type in PaymentRequestProductCreateDto Across Microservices #9511


User avatar
0
socsricardo created

We are building a microservice-based solution using abp.io and the ABP Payment module. In our payment workflow, we use PaymentRequestProductCreateDto, which has an ExtraProperties property of type Dictionary<string, IPaymentRequestProductExtraParameterConfiguration>. We need to pass custom gateway configuration data (e.g., ZendaPaymentRequestProductExtraParameterConfiguration) through this property.

    public class ZendaPaymentRequestProductExtraParameterConfiguration : IPaymentRequestProductExtraParameterConfiguration
    {
        public string RegisterNo { get; set; }
    }

However, when sending this DTO between services (e.g., via HTTP), we encounter the following error during deserialization

Deserialization of interface or abstract types is not supported. Type 'Volo.Payment.IPaymentRequestProductExtraParameterConfiguration'. Path: $.products[0].extraProperties.Zenda | LineNumber: 0 | BytePositionInLine: 165.

Expected behaviour: We would like to be able to pass custom configuration objects in ExtraProperties across microservice boundaries without serialization issues, or have guidance on the recommended ABP approach for this scenario.

Question: What is the recommended way to use ExtraProperties for gateway-specific configuration in a microservice environment, given the interface-based dictionary and serialization limitations?

Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

5 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you share full error logs and exceptions?

    Also what is the code of ZendaPaymentRequestProductExtraParameterConfiguration class.

    liming.ma@volosoft.com

    Thanks

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Can you add a new JsonConverter to your caller project?

    services.Configure<AbpSystemTextJsonSerializerOptions>(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new PaymentRequestProductExtraParameterConfigurationJsonConverter());
    });
    
    using System;
    using System.Text.Json;
    using System.Text.Json.Serialization;
    using Volo.Payment;
    
    public class PaymentRequestProductExtraParameterConfigurationJsonConverter : JsonConverter<IPaymentRequestProductExtraParameterConfiguration>
    {
        private const string TypeDiscriminator = "$type";
    
        public override IPaymentRequestProductExtraParameterConfiguration Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            using var jsonDoc = JsonDocument.ParseValue(ref reader);
            var root = jsonDoc.RootElement;
    
            if (!root.TryGetProperty(TypeDiscriminator, out var typeProp))
            {
                throw new JsonException($"Missing discriminator field '{TypeDiscriminator}'.");
            }
    
            var typeName = typeProp.GetString();
            if (typeName.IsNullOrWhiteSpace())
            {
                throw new JsonException($"Missing type name in discriminator field '{TypeDiscriminator}'.");
            }
    
            var actualType = Type.GetType(typeName);
            if (actualType == null)
            {
                throw new JsonException($"Unable to find type: {typeName}");
            }
    
            var json = root.GetRawText();
            return (IPaymentRequestProductExtraParameterConfiguration)JsonSerializer.Deserialize(json, actualType, options);
        }
    
        public override void Write(Utf8JsonWriter writer, IPaymentRequestProductExtraParameterConfiguration value, JsonSerializerOptions options)
        {
            var type = value.GetType();
            var json = JsonSerializer.SerializeToElement(value, type, options);
    
            writer.WriteStartObject();
            writer.WriteString(TypeDiscriminator, type.AssemblyQualifiedName);
            foreach (var prop in json.EnumerateObject())
            {
                prop.WriteTo(writer);
            }
            writer.WriteEndObject();
        }
    }
    
    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    socsricardo created

    This did not resolve my issue, I am still experiencing the same error. I added the new JsonConverter to my web project.

    The API is still throwing the following exception: Deserialization of interface or abstract types is not supported. Type 'Volo.Payment.IPaymentRequestProductExtraParameterConfiguration'. Path: $.products[0].extraProperties.ZendaPaymentRequestProductExtraParameterConfiguration | LineNumber: 0 | BytePositionInLine: 213

    StackTrace:

    at System.Text.Json.ThrowHelper.ThrowNotSupportedException(ReadStack& state, Utf8JsonReader& reader, Exception innerException)
       at System.Text.Json.ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(JsonTypeInfo typeInfo, Utf8JsonReader& reader, ReadStack& state)
       at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
       at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
       at System.Text.Json.Serialization.JsonDictionaryConverter`3.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TDictionary& value)
       at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
       at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
       at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
       at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
       at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
       at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
       at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
       at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
       at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
       at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, T& value, JsonSerializerOptions options, ReadStack& state)
       at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.ContinueDeserialize(ReadBufferState& bufferState, JsonReaderState& jsonReaderState, ReadStack& readStack, T& value)
       at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsync(Stream utf8Json, CancellationToken cancellationToken)
       at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsObjectAsync(Stream utf8Json, CancellationToken cancellationToken)
       at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
       at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
       at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
       at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value, Object container)
       at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
    --- End of stack trace from previous location ---
       at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
       at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
    

    I also add the same JsonConverter to the API project where the exception is being thrown.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    socsricardo created

    Have managed to get this working.

    In the API project this registration would not trigger the read. This is still the registration on the web project.

    services.Configure<AbpSystemTextJsonSerializerOptions>(options => c
    {
        options.JsonSerializerOptions.Converters.Add(new PaymentRequestProductExtraParameterConfigurationJsonConverter());
    });
    

    Adding the JsonConverter in the API project against the JsonOptions instead of AbpSystemTextJsonSerializerOptions resolved the issue and the read now trigger.

    Configure<JsonOptions>(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new PaymentRequestProductExtraParameterConfigurationJsonConverter());
    });
    
    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Great 👍

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on September 16, 2026, 14:50
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.