Link to home
Start Free TrialLog in
Avatar of N M
N MFlag for Luxembourg

asked on

C# - JSON Serialization using model

I have a C# small console app that I need to run, it consumes an HTTP restful API. My problem is that using JSON I get a "Cannot implement type blahblah with a collection initializer because it does not implement 'System.Collections.IEnumerable' " and I'm lost. Coud you help me please? Posting the relevant part of the code..

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using System.Threading.Tasks;

namespace TESTMEname
{

    public class headers
    {
        public string Request_ID { get; set; } = "XX123456789";
        public string Correlation_ID { get; set; } = "12345678910";
        public string Token { get; set; } = "abcdefghijklmnopqrstuvwxyzetc";
        public string Content_Type { get; set; } = "application/x-www-form-urlencoded";
    }

    public class access
    {
        public string allPs { get; set; } = "allAccounts";
        public string availableAccounts { get; set; } = "allAccounts";
    }

    public class Body
    {
        public access access { get; set; }
        public bool combinedServiceIndicator { get; set; } = false;
        public int frequencyPerDay { get; set; } = 4;
        public bool recurringIndicator { get; set; } = false;
        public string validUntil { get; set; } = "2020-12-31";
    }

    [System.Serializable]
    public class Consent    //RootObject
    {
        public headers headers { get; set; }
        public Body body { get; set; }
    }

Open in new window


and my class is

class Program
    {
        static HttpClient client = new HttpClient();

        static void ShowConsent(Consent cust_consent)
        {
            Console.WriteLine(cust_consent.ToString());
        }

        static async Task<Uri> CreateConsentAsync(Consent cust_consent)
        {
            HttpResponseMessage response = await client.PostAsJsonAsync("http://myniceurl:8001/some/good/url/", cust_consent);

            ShowConsent(cust_consent);

            response.EnsureSuccessStatusCode();

            // return URI of the created resource.
            return response.Headers.Location;
        }

        static async Task<Consent> GetConsentAsync(string path)
        {
            Consent cust_consent = null;

            HttpResponseMessage response = await client.GetAsync(path);

            if (response.IsSuccessStatusCode)
            {
                cust_consent = await response.Content.ReadAsAsync<Consent>();
            }

            return cust_consent;
        }

Open in new window


When I try to populate I simple can't

        static void Main()
        {

            RunAsync().GetAwaiter().GetResult();
        }



        static async Task RunAsync()
        {
            // Update port # and url in the following line.
            client.BaseAddress = new Uri("http://myurl:8001/etc..../");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));

            try
            {
                // Create a new cust_consent  <------- fails!!!!!!!
                Consent cust_consent = new Consent
                {
                    cust_consent.headers.Request_ID  = "something",

                    cust_consent.body.access.allPs = "new_value",
                    cust_consent.body.access.availableAccounts = "new_value",
                    cust_consent.body.combinedServiceIndicator = false,
                    cust_consent.body.frequencyPerDay = 4,
                    cust_consent.body.recurringIndicator = false,
                    cust_consent.body.validUntil = "some_date_YYYYMMDD"
			...etc...
                };

                string json = JsonConvert.SerializeObject(cust_consent);
                Console.WriteLine(json);
                Console.WriteLine("----------------------------------------------------------");
                var url = await CreateConsentAsync(cust_consent);

                Console.WriteLine($"Created at {url}");

                ShowConsent(cust_consent);

            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            Console.ReadLine();

        }
    }
}

Open in new window

Avatar of N M
N M
Flag of Luxembourg image

ASKER

This is the JSON I am trying to POST to the url (hope is ok):

{
"headers":
	{
	"X-Request-ID":"something",
	"LH-Correlation-ID":"something",
	"LH-PSU-Token":"anicevaluehere",
	"Content-Type":"application/x-www-form-urlencoded"
	},
"body":
	{
	  "access": {
		"allPsd2": "allAccounts",
		"availableAccounts": "allAccounts"
				},
	  "combinedServiceIndicator": false,
	  "frequencyPerDay": 4,
	  "recurringIndicator": false,
	  "validUntil": "2022-12-31"
	}
}

Open in new window


Hope it helps..
Avatar of leakim971
"X-Request-ID" different to "Request_ID "
same for other fields, use :


    public class headers
    {
        [JsonProperty("X-Request-ID")]
        public string Request_ID { get; set; } = "XX123456789";
        [JsonProperty("LH-Correlation-ID")]
        public string Correlation_ID { get; set; } = "12345678910";
        [JsonProperty("LH-PSU-Token")]
        ...

Open in new window

Avatar of N M

ASKER

Thank you, did that already (adding JSON prooerties)

however, when I try to populate, I get the error..

Any suggestions?

Thank you very much
Any suggestions?

try simple object
and add new "property" one by one until it fail

so first try to post a simple like this one :
{"headers":{"a":"something"}}

of course update the class so it match everytime you add a new property
Avatar of N M

ASKER

Thank you
I tried, it partially works up to the point that I have the "access" with two nested properties.
Then, the JSON serialization fails..

With the above code, seems the only problem populating the properties is this error, hence I am trying to see what it means (I tried "by the book" example of Microsoft but did not work, and interestingly enough, I end up with same error..
Body class the B is uppercase, is it OK ?
Avatar of N M

ASKER

Yes, it works as well in lowercase.
here on the documentation : https://docs.microsoft.com/fr-fr/dotnet/standard/serialization/system-text-json-how-to

check the TemperatureRanges:

public Dictionary<string, HighLowTemps> TemperatureRanges { get; set; }

using this tools : https://app.quicktype.io/#l=cs&r=json2csharp

I get :

// <auto-generated />
//
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
//    using QuickType;
//
//    var welcome = Welcome.FromJson(jsonString);

namespace QuickType
{
    using System;
    using System.Collections.Generic;

    using System.Globalization;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;

    public partial class Welcome
    {
        [JsonProperty("headers")]
        public Headers Headers { get; set; }

        [JsonProperty("body")]
        public Body Body { get; set; }
    }

    public partial class Body
    {
        [JsonProperty("access")]
        public Access Access { get; set; }

        [JsonProperty("combinedServiceIndicator")]
        public bool CombinedServiceIndicator { get; set; }

        [JsonProperty("frequencyPerDay")]
        public long FrequencyPerDay { get; set; }

        [JsonProperty("recurringIndicator")]
        public bool RecurringIndicator { get; set; }

        [JsonProperty("validUntil")]
        public DateTimeOffset ValidUntil { get; set; }
    }

    public partial class Access
    {
        [JsonProperty("allPsd2")]
        public string AllPsd2 { get; set; }

        [JsonProperty("availableAccounts")]
        public string AvailableAccounts { get; set; }
    }

    public partial class Headers
    {
        [JsonProperty("X-Request-ID")]
        public string XRequestId { get; set; }

        [JsonProperty("LH-Correlation-ID")]
        public string LhCorrelationId { get; set; }

        [JsonProperty("LH-PSU-Token")]
        public string LhPsuToken { get; set; }

        [JsonProperty("Content-Type")]
        public string ContentType { get; set; }
    }

    public partial class Welcome
    {
        public static Welcome FromJson(string json) => JsonConvert.DeserializeObject<Welcome>(json, QuickType.Converter.Settings);
    }

    public static class Serialize
    {
        public static string ToJson(this Welcome self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
    }

    internal static class Converter
    {
        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
            Converters =
            {
                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
            },
        };
    }
}

Open in new window

Avatar of N M

ASKER

(Note: I understand the effort on the date property, thing is, apart from integers and boolean values, all rest are strings, so, no need for extra effort on converting dates etc, is all same for me)
Thank you also for the suggestion on the quicktype. Is very interesting. However, my problem seems to be exactly at the point where I assign the values... I am trying now and will post a sample *if it compiles...
can't compile for the moment, don't have the right machine
I will and try to provide a working sample until you do it before
ASKER CERTIFIED SOLUTION
Avatar of kaufmed
kaufmed
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of N M

ASKER

Thank you, it worked immediately.
Avatar of N M

ASKER

Thanks 'leakim971' for his advice, thank you 'kaufmed' for posting compiling code and explaining logic.