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?
5 Answer(s)
-
0
hi
Can you share full error logs and exceptions?
Also what is the code of
ZendaPaymentRequestProductExtraParameterConfiguration
class.liming.ma@volosoft.com
Thanks
-
0
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(); } }
-
0
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. -
0
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 theJsonOptions
instead ofAbpSystemTextJsonSerializerOptions
resolved the issue and the read now trigger.Configure<JsonOptions>(options => { options.JsonSerializerOptions.Converters.Add(new PaymentRequestProductExtraParameterConfigurationJsonConverter()); });
-
0
Great 👍