Deserialize Json into objects and pass them as arguments to methods

henryvuong

Member
Joined
Sep 8, 2023
Messages
15
Programming Experience
3-5
I am trying to make API calls to Amazon from my C# SDK. In this program, I deserialize a JSON string into C# objects and pass them as arguments into some methods to make API calls. The issue I have is the objects are not the same type with the arguments in the method signature. Below is my code. Pay attention to the "error" comments I make in the Main() method:


C#:
/*
 * Selling Partner API for Listings Items
 *
 * The Selling Partner API for Listings Items (Listings Items API) provides programmatic access to selling partner listings on Amazon. Use this API in collaboration with the Selling Partner API for Product Type Definitions, which you use to retrieve the information about Amazon product types needed to use the Listings Items API.  For more information, see the [Listings Items API Use Case Guide](doc:listings-items-api-v2021-08-01-use-case-guide).
 *
 * OpenAPI spec version: 2021-08-01
 *
 * Generated by: https://github.com/swagger-api/swagger-codegen.git
 */

using System;
using System.IO;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using RestSharp;
using NUnit.Framework;
using SellingPartnerAPI.ListingsItemsAPI.Client;
using SellingPartnerAPI.ListingsItemsAPI.Api;
using SellingPartnerAPI.ListingsItemsAPI.Model;
using Amazon.SellingPartnerAPIAA;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using static SellingPartnerAPI.ListingsItemsAPI.Test.ListingsApiTests;

namespace SellingPartnerAPI.ListingsItemsAPI.Test
{
    /// <summary>
    ///  Class for testing ListingsApi
    /// </summary>
    /// <remarks>
    /// This file is automatically generated by Swagger Codegen.
    /// Please update the test case below to test the API endpoint.
    /// </remarks>
    [TestFixture]
    public class ListingsApiTests
    {
        private ListingsApi instance;

        /// <summary>
        /// Setup before each unit test
        /// </summary>
        [SetUp]
        public void Init()
        {
            // TODO uncomment below to initialize instance for testing
            //instance = new ListingsApi();
        }

        /// <summary>
        /// Clean up after each unit test
        /// </summary>
        [TearDown]
        public void Cleanup()
        {

        }

        /// <summary>
        /// Test an instance of ListingsApi
        /// </summary>
        [Test]
        public void InstanceTest()
        {
            // TODO uncomment below to test 'IsInstanceOfType' ListingsApi
            //Assert.IsInstanceOfType(typeof(ListingsApi), instance, "instance is a ListingsApi");
        }

        
        /// <summary>
        /// Test DeleteListingsItem
        /// </summary>
        [Test]
        public void DeleteListingsItemTest()
        {
            // TODO uncomment below to test the method and replace null with proper value
            //string sellerId = null;
            //string sku = null;
            //List<string> marketplaceIds = null;
            //string issueLocale = null;
            //var response = instance.DeleteListingsItem(sellerId, sku, marketplaceIds, issueLocale);
            //Assert.IsInstanceOf<ListingsItemSubmissionResponse> (response, "response is ListingsItemSubmissionResponse");
        }
        
        /// <summary>
        /// Test GetListingsItem
        /// </summary>
        [Test]
        public void GetListingsItemTest()
        {
            // TODO uncomment below to test the method and replace null with proper value
            //string sellerId = null;
            //string sku = null;
            //List<string> marketplaceIds = null;
            //string issueLocale = null;
            //List<string> includedData = null;
            //var response = instance.GetListingsItem(sellerId, sku, marketplaceIds, issueLocale, includedData);
            //Assert.IsInstanceOf<Item> (response, "response is Item");
        }
        
        /// <summary>
        /// Test PatchListingsItem
        /// </summary>
        [Test]
        public void PatchListingsItemTest()
        {
            // TODO uncomment below to test the method and replace null with proper value
            //string sellerId = null;
            //string sku = null;
            //List<string> marketplaceIds = null;
            //ListingsItemPatchRequest body = null;
            //string issueLocale = null;
            //var response = instance.PatchListingsItem(sellerId, sku, marketplaceIds, body, issueLocale);
            //Assert.IsInstanceOf<ListingsItemSubmissionResponse> (response, "response is ListingsItemSubmissionResponse");
        }
        
        /// <summary>
        /// Test PutListingsItem
        /// </summary>
        [Test]
        public void PutListingsItemTest()
        {
            // TODO uncomment below to test the method and replace null with proper value
            //string sellerId = null;
            //string sku = null;
            //List<string> marketplaceIds = null;
            //ListingsItemPutRequest body = null;
            //string issueLocale = null;
            //var response = instance.PutListingsItem(sellerId, sku, marketplaceIds, body, issueLocale);
            //Assert.IsInstanceOf<ListingsItemSubmissionResponse> (response, "response is ListingsItemSubmissionResponse");
        }

        //**************** Classes for Listing Item Request body *****************
        public class Root
        {
            public string productType { get; set; }
            public List<Patch> patches { get; set; }
        }
        public class Patch
        {
            public string op { get; set; }
            public string operation_type { get; set; }
            public string path { get; set; }
            public List<Value> value { get; set; }
        }
        public class Value
        {
            public string fulfillment_channel_code { get; set; }
            public int quantity { get; set; }
        }

        //Reference: https://developer-docs.amazon.com/sp-api-blog/docs/automate-your-sp-api-calls-using-the-c-sdk
        public static void Main()
        {
            try
            {
                LWAAuthorizationCredentials lwaAuthorizationCredentials = new LWAAuthorizationCredentials
                {
                    ClientId = "XXXXXXXXXX",
                    ClientSecret = "XXXXXXXXXX",
                    RefreshToken = "XXXXXXXXXX",
                    Endpoint = new Uri("https://api.amazon.com/auth/o2/token")
                };

                ListingsApi listingsApi = new ListingsApi.Builder()
                    .SetLWAAuthorizationCredentials(lwaAuthorizationCredentials)
                    .Build();

                string sellerId = "XXXXXXXXXX";
                List<string> marketplaceIds = new List<string>();
                marketplaceIds.Add("ATVPDKIKX0DER");
                string sku = "XXX-YYY-ZZZ";
                
                //Update qty of a single product
                //Source: https://github.com/amzn/selling-partner-api-docs/issues/2068

                string json = @"
                    {
                        'productType': 'CELLULAR_PHONE',
                        'patches': [
                            {
                                'op': 'replace',
                                'operation_type': 'PARTIAL_UPDATE',
                                'path': '/attributes/fulfillment_availability',
                                'value': [
                                    {
                                        'fulfillment_channel_code': 'DEFAULT',
                                        'quantity': 1
                                    }
                                ]
                            }
                        ]
                    }";

                var patchListing = JsonConvert.DeserializeObject<Root>(json);

                PatchOperation.OpEnum op = (PatchOperation.OpEnum)patchListing.patches[0].op; //Error CS0030: Cannot convert type 'string' to 'PatchOperation.OpEnum'
                string path = patchListing.patches[0].path;
                List<Value> value = patchListing.patches[0].value; //this value is not accepted as an argument in PatchOperation

                PatchOperation patchOperations = new PatchOperation(op, path, value); //Error CS1503 Argument 3: cannot convert from 'Value>' to 'List<object>'
                ListingsItemPatchRequest listingsItemPatchRequest = new ListingsItemPatchRequest(patchListing.productType, patchOperations); //Error CS1503 Argument 2: cannot convert from 'PatchOperation' to 'List<PatchOperation>'
                ListingsItemSubmissionResponse result = listingsApi.PatchListingsItem(sellerId, sku, marketplaceIds, listingsItemPatchRequest);
                Console.WriteLine(result.ToJson());
                Console.ReadLine();
            }
            catch (LWAException e)
            {
                Console.WriteLine("LWA Exception when calling SellersApi#getMarketplaceParticipations");
                Console.WriteLine(e.getErrorCode());
                Console.WriteLine(e.getErrorMessage());
                Console.WriteLine(e.Message);
            }
            catch (ApiException e)
            {
                Console.WriteLine("Exception when calling SellersApi#getMarketplaceParticipations");
                Console.WriteLine(e.Message);
            }
        }
    }
}

Here're the errors (I put these comments in my code above):
Error CS0030: Cannot convert type 'string' to 'PatchOperation.OpEnum'
Error CS1503 Argument 3: cannot convert from 'Value>' to 'List<object>'
Error CS1503 Argument 2: cannot convert from 'PatchOperation' to 'List<PatchOperation>'

The classes I use in the above code can be viewed here:
ListingApi.cs: ListingApi.cs — Codefile
ListingsItemPatchRequest.cs: ListingsItemPatchRequest.cs — Codefile
PatchOperation.cs: PatchOperation.cs — Codefile

So the problem I have is the arguments I pass into the method are not the same type with the method's signature. How can I fixed them?
 
For the parts where C# is complaining that you can't cast a string to a enum, that is because it really can't. It just like trying to convert a letter that you get from a Nigerian prince promising you millions into real cash at the bank. Notice how in your classes you declare those fields to be strings. So of course you can't just cast them to enums. You could try using Enum.Parse() to convert the string to an enum value, or you could follow the approach described in the blog post below so that JSON.NET will do the conversion at parsing time:

 
For the last error you are getting, the class is expecting to get a list of PatchOperation but you are passing a single object. Just like there is a difference between a carton of eggs that contains a single egg, and a single egg, there is a difference between list of PatchOperation and a single PatchOperation. Pass in a list of PatchOperation because that is what the class wants as a parameter.
 
For the second error, you can't just treat a List<Value> as a List<object>. They are different types much like a list of clowns is different from a list of politicians. (Although some people may same they are the same. :) ) C# cannot automatically convert between those two types. You will have to copy over the items from your List<Value> to a new List<object>, or use LINQ to do it for you.
 
Last edited:
Overall, all the errors above show a common theme about lack of understanding about data types. C# is a strongly typed language. Out of curiosity, what book or tutorial did you use to learn C#. It feels like they missed out on a major C# programming concept.
 
I am a self-taught programmer. I write program for my own use. I have been able to write some small programs to manage my own business and as you can guess, it's not professional., but it's good enough for me. This is one of the programs I have to write to make API call to Amazon for my Amazon store.

Can you give me some suggestion how my code should be re-written? Thanks
 
For the first error, I can simply fix that by using:
PatchOperation.OpEnum op = PatchOperation.OpEnum.Replace;
since I know it's a replace operation.

For the second error, I did not quote it correctly. It is actually this:
Error CS1503 Argument 3: cannot convert from 'System.Collections.Generic.List<Value>' to 'System.Collections.Generic.List<object>'
The third argument of PatchOperation requires a List<object> . I don't know why it does not accept my List<Value>.
You can see the entire class of PatchOperation in this file:
PatchOperation.cs: PatchOperation.cs — Codefile

For the third error, I resvised the code as such:
C#:
List<PatchOperation> patches = new List<PatchOperation>();
patches.Add(new PatchOperation() { Op = op, Path = path, Value = value });
ListingsItemPatchRequest listingsItemPatchRequest = new ListingsItemPatchRequest(patchListing.productType, patches);
So I am now down to one error as mentioned above
 
Last edited:
For the second error, you can't just treat a List<Value> as a List<object>. They are different types much like a list of clowns is different from a list of politicians. (Although some people may same they are the same. :) ) C# cannot automatically convert between those two types. You will have to copy over the items from your List<Value> to a new List<object>, or use LINQ to do it for you.


Can you show me some example how to copy over items from a list to a new List<object>? I tried to create a new object list, like this:
C#:
List<object> objList = new List<object>();
but not sure how to copy the items from List<Value> to it.
 
Pseudo-code:
foreach(object value in valueList)
    objList.Add(value)
 
Or take a look at the LINQ Cast<T> extension method.
 
I replace the third argument of PatchOperation by "objList" , like so:
C#:
List<PatchOperation> patches = new List<PatchOperation>();
patches.Add(new PatchOperation() { Op = op, Path = path, Value = objList });

But when I debug I got this error:
$exception {"path is a required property for PatchOperation and cannot be null"}
I even replaced "path" by the literal string "/attributes/fulfillment_availability" for testing but still got the same error. And it looks like Op = 0, Value = null at run time too. These are the default settings of PatchOperation method as you can see in this file:
PatchOperation.cs: PatchOperation.cs — Codefile
 
Post your updated code. I have a feeling that you are passing a different object than the one you initialized in post #12.
 
Last edited:
I got the answer from another forum post:
Even though your answer does not lead to the final solution, it does help me understand more of the subject. Thanks for your help anyway.
 
Back
Top Bottom