Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not able to deserialize Push Transactions with Custom Parameters #50

Open
timvandenhof opened this issue Jul 26, 2021 · 2 comments
Open

Comments

@timvandenhof
Copy link

Description

For processing in a back office system, we create transactions with a custom property containing an identifier. For example I create a 'mycustomprop' in the Buckaroo Plaza and provide a value for it when creating a transaction. This transaction also contains the push url.

When the push is received in the API, it successfully passes the hmac validation. The next step is actually deserializing the message which seems to fail when Custom Properties are used:
Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'BuckarooSdk.DataTypes.CustomParameters' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.

Cause

The actual JSON message has a 'CustomParameters' property which is a list of Name-Value pairs. The models used in the project however expect a 'List' property which is a list containing the Name-Value pairs. So the data model contains an additional layer which is not there in the JSON message. Therefore the deserialisation from JSON to the model failes.

Potential solutions

  1. Change the object model structure in the SDK, so that it matches the actual JSON structure. This might cause side effects else where in the SDK Client I might not be aware of yet.
  2. Create some kind of custom deserialisation logic on top of NewtonSoft JSON.

Relevant documentation

Technical implementation

  • NET 5.0 utilizing ASP.net WebApi
  • Buckaroo SDK 1.4.0 via NuGet (latest)
  • NewtonsNewtonsoft.Jsonoft.Json 13.0.1 via NuGet (latest)
var pushHandler = new PushHandler(_buckarooOptions.ApiKey);
var pushMessage = pushHandler.DeserializePush(requestBody, requestUrlWithoutSchema, authHeader);

Could also have used the SdkClient, which also has a PushHandler.

Example Push

{
    "Transaction": {
        "Key": "F30D335AF97E45D6A97A25F89DFED232",
        "Invoice": "956bb897-0dc1-4347-bf15-ce09be8b5566",
        "ServiceCode": "ideal",
        "Status": {
            "Code": {
                "Code": 490,
                "Description": "Failed"
            },
            "SubCode": {
                "Code": "S996",
                "Description": "An error occurred while processing the transaction: "
            },
            "DateTime": "2021-07-22T12:14:39"
        },
        "IsTest": true,
        "Order": null,
        "Currency": "EUR",
        "AmountDebit": 1.49,
        "TransactionType": "C021",
        "Services": [{
                "Name": "ideal",
                "Action": null,
                "Parameters": [{
                        "Name": "consumerIssuer",
                        "Value": "ASN Bank"
                    }, {
                        "Name": "transactionId",
                        "Value": "0000000000000001"
                    }
                ],
                "VersionAsProperty": 2
            }
        ],
        "CustomParameters": [{
                "Name": "mycustomprop",
                "Value": "84da798a-13d0-4845-95d5-d0f30f2ee0de"
            }
        ],
        "AdditionalParameters": null,
        "MutationType": 1,
        "RelatedTransactions": null,
        "IsCancelable": false,
        "IssuingCountry": null,
        "StartRecurrent": false,
        "Recurring": false,
        "CustomerName": null,
        "PayerHash": null,
        "PaymentKey": "9C78C466896E4596B2C8C6A7607DCB6C",
        "Description": null
    }
}

Stack trace

Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'BuckarooSdk.DataTypes.CustomParameters' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path 'CustomParameters', line 1, position 581.
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureArrayContract(JsonReader reader, Type objectType, JsonContract contract)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value)
   at PaymentApi.Controllers.DebugPushHandler.DeserializeTransaction(String jsonString) in C:\Repos\PaymentApi\Controllers\DebugPushHandler.cs:line 72
   at PaymentApi.Controllers.DebugPushHandler.DeserializePush(String jsonString) in C:\Repos\PaymentApi\Controllers\DebugPushHandler.cs:line 55
   at PaymentApi.Controllers.DebugPushHandler.DeserializePush(Byte[] body, String requestUri, String authorizationHeader) in C:\Repos\PaymentApi\Controllers\DebugPushHandler.cs:line 39
   at PaymentApi.Controllers.Internal.BuckarooController.PostTransaction() in C:\Repos\PaymentApi\Controllers\BuckarooController.cs:line 94
   at lambda_method631(Closure , Object )
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at PaymentApi.Middleware.RequestBufferingMiddleware.Invoke(HttpContext context) in C:\Repos\PaymentApi\Middleware\RequestBufferingMiddleware.cs:line 39
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Note: Stacktrace is made on an exact copy of PushHandler, but added as source 'DebugPushHandler' to allow debugging. The result is the same.

@timvandenhof
Copy link
Author

Related ticket IT by Buckaroo Service desk: BCK-7351

@timvandenhof
Copy link
Author

Should be resolved with: #51

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant