refit icon indicating copy to clipboard operation
refit copied to clipboard

[Bug]: BodySerializationMethod.UrlEncoded with Complex view model class

Open infofromca opened this issue 1 year ago • 0 comments

Describe the bug 🐞

I have a very complex class called CheckoutViewModel: using OrchardCore.Commerce.MoneyDataType; using System.Collections.Generic;

namespace OrchardCore.Commerce.Payment.ViewModels;

public class CheckoutViewModel : PaymentViewModel //, ICheckoutViewModel
{
    public string? ShoppingCartId { get; set; }

    public Amount GrossTotal { get; set; } = new();

    // [BindNever]
  //  public IEnumerable<OrchardCore.Commerce.Abstraction.ViewModels.Region> Regions { get; set; } = Array.Empty<OrchardCore.Commerce.Abstraction.ViewModels.Region>();

   // [BindNever]
    public IDictionary<string, IDictionary<string, string>> Provinces { get; set; } =
        new Dictionary<string, IDictionary<string, string>>();

    public string? UserEmail { get; set; }

    public bool IsInvalid { get; set; }

  //  public IEnumerable<IShape> CheckoutShapes { get; set; } = Array.Empty<IShape>();

    //public CheckoutViewModel(OrderPart orderPart, Amount singleCurrencyTotal, Amount netTotal)
    //    : base(orderPart, singleCurrencyTotal, netTotal) =>
    //    Metadata.Type = "Checkout";

    //public CheckoutViewModel()
    //    : base() =>
    //    Metadata.Type = "Checkout";
}
//using Microsoft.AspNetCore.Mvc.ModelBinding;
using OrchardCore.Commerce.Abstractions.Abstractions;
using OrchardCore.Commerce.Abstractions.Models;
using OrchardCore.Commerce.MoneyDataType;
using OrchardCore.Commerce.Payment.Abstractions;
//using OrchardCore.DisplayManagement.Views;
using System.Collections.Generic;
using System.Threading.Tasks;
using BlazingOrchard.DisplayManagement.Services;
using BlazingOrchard.DisplayManagement.Shapes;
using BlazingOrchard.DisplayManagement.Zones;
using System.Linq;

namespace OrchardCore.Commerce.Payment.ViewModels;

public class PaymentViewModel : IPaymentViewModel //ShapeViewModel ,
{
    public Amount SingleCurrencyTotal { get; set; } = new();

    public Amount NetTotal { get; set; } = new();

    public OrderPart OrderPart { get; set; } = new();

    //[BindNever]
    public IDictionary<string, object> PaymentProviderData { get; set; } = new Dictionary<string, object>();

    public PaymentViewModel(OrderPart orderPart, Amount singleCurrencyTotal, Amount netTotal)
    {
        OrderPart = orderPart;
        SingleCurrencyTotal = singleCurrencyTotal;
        NetTotal = netTotal;
    }
    public PaymentViewModel()
    {
      
    }
    //public async Task WithProviderDataAsync(IEnumerable<IPaymentProvider> paymentProviders)
    //{
    //    foreach (var provider in paymentProviders)
    //    {
    //        if (await provider.CreatePaymentProviderDataAsync(this) is { } data)
    //        {
    //            PaymentProviderData[provider.Name] = data;
    //        }
    //    }
    //}

    //private ShapeMetadata _metadata;
    //public ShapeMetadata Metadata
    //{
    //    get
    //    {
    //        return _metadata ??= new ShapeMetadata();
    //    }
    //    set
    //    {
    //        _metadata = value;
    //    }
    //}

    //public string Position
    //{
    //    get
    //    {
    //        return Metadata.Position;
    //    }

    //    set
    //    {
    //        Metadata.Position = value;
    //    }
    //}

    //public string Id { get; set; }
    //public string TagName { get; set; }

    //private List<string> _classes;
    //public IList<string> Classes
    //{
    //    get { return _classes ??= new List<string>(); }
    //    set { _classes = (List<string>)value; }
    //}

    //private Dictionary<string, string> _attributes;
    //public IDictionary<string, string> Attributes
    //{
    //    get { return _attributes ??= new Dictionary<string, string>(); }
    //    set { _attributes = (Dictionary<string, string>)value; }
    //}

    //private Dictionary<string, object> _properties;
    //public IDictionary<string, object> Properties
    //{
    //    get { return _properties ??= new Dictionary<string, object>(); }
    //    set { _properties = (Dictionary<string, object>)value; }
    //}

    //private bool _sorted = false;

    //private List<IPositioned> _items;
    //public IReadOnlyList<IPositioned> Items
    //{
    //    get
    //    {
    //        _items ??= new List<IPositioned>();

    //        if (!_sorted)
    //        {
    //            _items = _items.OrderBy(x => x, FlatPositionComparer.Instance).ToList();
    //            _sorted = true;
    //        }

    //        return _items;
    //    }
    //}
}

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OrchardCore.Commerce.Abstractions.Abstractions;
using OrchardCore.Commerce.Abstractions.Fields;
using OrchardCore.ContentFields.Fields;
using OrchardCore.ContentManagement;
using System.Collections.Generic;

namespace OrchardCore.Commerce.Abstractions.Models;

public class OrderPart : ContentPart
{
    public TextField OrderId { get; set; } = new();
    public TextField Status { get; set; } = new();

    /// <summary>
    /// Gets the order's line items.
    /// </summary>
    public IList<OrderLineItem> LineItems { get; set; } = new List<OrderLineItem>();

    /// <summary>
    /// Gets additional costs that don't belong to an <see cref="OrderLineItem"/>, such as taxes and shipping.
    /// </summary>
    public IList<OrderAdditionalCost> AdditionalCosts { get; set; } = new List<OrderAdditionalCost>();

    /// <summary>
    /// Gets the amounts charged for this order. Typically a single credit card charge.
    /// </summary>

    // This is a temporary solution, it needs to be reworked in the future!
#pragma warning disable CA2326 // Do not use TypeNameHandling values other than None
#pragma warning disable SCS0028 // TypeNameHandling is set to the other value than 'None'. It may lead to deserialization vulnerability.
    [JsonProperty(ItemTypeNameHandling = TypeNameHandling.Auto)]
#pragma warning restore SCS0028 // TypeNameHandling is set to the other value than 'None'. It may lead to deserialization vulnerability.
#pragma warning restore CA2326 // Do not use TypeNameHandling values other than None
    public IList<IPayment> Charges { get; set; } = new List<IPayment>();

    public TextField Email { get; set; } = new();
    public TextField Phone { get; set; } = new();
    public TextField VatNumber { get; set; } = new();

    public AddressField BillingAddress { get; set; } = new();
    public AddressField ShippingAddress { get; set; } = new();
    public BooleanField BillingAndShippingAddressesMatch { get; set; } = new();
    public BooleanField IsCorporation { get; set; } = new();

    public IDictionary<string, JToken> AdditionalData { get; set; } = new Dictionary<string, JToken>();
}

Step to reproduce

[Post("/api/checkout/confirm/{providerName}/{paymentIntentId}/{shoppingCartId}?middleUrl={middleUrl}")] Task<PaymentOperationStatusViewModelVM> ConfirmPaymentAsync( string providerName, string paymentIntentId, string shoppingCartId, string middleUrl, [Body(BodySerializationMethod.UrlEncoded)] CheckoutViewModel checkoutViewModel, CancellationToken cancellationToken = default); 2. Click on submit to have a http post aync calling to api server 3. Scroll down to it hit the api server which is ok . 4. See error but I got this 👍 POST /api/checkout/confirm/Stripe/pi_3PsrfnRpyWVeDn6H0MxBWbGo_secret_r7Q8wEngIEPH0JeVjLzfuCECs/4hap81e272txkszm6jrryh52xj?middleUrl=guangmauiauth HTTP/1.1 Host: localhost:62354 Content-Type: application/x-www-form-urlencoded Content-Length: 544

RegionList=System.Collections.Generic.List%601%5BOrchardCore.Commerce.Abstraction.ViewModels.Region%5D&ShoppingCartId=4hap81e272txkszm6jrryh52xj&GrossTotal=%240.00&Provinces=System.Collections.Generic.Dictionary%602%5BSystem.String%2CSystem.Collections.Generic.IDictionary%602%5BSystem.String%2CSystem.String%5D%5D&UserEmail=&IsInvalid=False&SingleCurrencyTotal=%243.00&NetTotal=%243.00&OrderPart=OrchardCore.Commerce.Abstractions.Models.OrderPart&PaymentProviderData=System.Collections.Generic.Dictionary%602%5BSystem.String%2CSystem.Object%5D

UserEmail=&IsInvalid=False&SingleCurrencyTotal=%243.00&NetTotal=%243.00 are ok, but OrderPart=OrchardCore.Commerce.Abstractions.Models.OrderPart&PaymentProviderData=System.Collections.Generic.Dictionary%602%5BSystem.String%2CSystem.Object%5D just gave out the name of the another class , not the data.

Reproduction repository

https://github.com/reactiveui/refit

Expected behavior

OrderPart=OrchardCore.Commerce.Abstractions.Models.OrderPart&PaymentProviderData=System.Collections.Generic.Dictionary%602%5BSystem.String%2CSystem.Object%5D should show the data like [email protected]&....

Screenshots 🖼️

No response

IDE

No response

Operating system

No response

Version

No response

Device

No response

Refit Version

No response

Additional information ℹ️

No response

infofromca avatar Aug 28 '24 20:08 infofromca