C# - JSON Serialization using model

N M
N M used Ask the Experts™
on
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

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
N MConsultant

Author

Commented:
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..
leakim971Multitechnician
Top Expert 2014

Commented:
"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

N MConsultant

Author

Commented:
Thank you, did that already (adding JSON prooerties)

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

Any suggestions?

Thank you very much
Fundamentals of JavaScript

Learn the fundamentals of the popular programming language JavaScript so that you can explore the realm of web development.

leakim971Multitechnician
Top Expert 2014

Commented:
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
N MConsultant

Author

Commented:
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..
leakim971Multitechnician
Top Expert 2014

Commented:
Body class the B is uppercase, is it OK ?
N MConsultant

Author

Commented:
Yes, it works as well in lowercase.
leakim971Multitechnician
Top Expert 2014

Commented:
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

N MConsultant

Author

Commented:
(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...
leakim971Multitechnician
Top Expert 2014

Commented:
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
Glanced up at my screen and thought I had coded the Matrix...  Turns out, I just fell asleep on the keyboard.
Most Valuable Expert 2011
Top Expert 2015
Commented:
Cannot implement type blahblah with a collection initializer because it does not implement 'System.Collections.IEnumerable'
That's because your syntax is incorrect.

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...
};

Open in new window


When you use object initialization, you don't include the variable name on each property--just use the property name:

Consent cust_consent = new Consent
{
    headers.Request_ID  = "something",
    body.access.allPs = "new_value",
    body.access.availableAccounts = "new_value",
    body.combinedServiceIndicator = false,
    body.frequencyPerDay = 4,
    body.recurringIndicator = false,
    body.validUntil = "some_date_YYYYMMDD"
    ...etc...
};

Open in new window


But that leaves you with another problem:  Properties of a class aren't automatically initialized unless you initialize them in the constructor (or another object initializer). You're going to encounter a NullReferenceException when you try to access member of body (and likewise headers). You need to initialize those also:

Consent cust_consent = new Consent
{
    headers = new headers()
              {
                  Request_ID  = "something",
              }
    body = new Body()
           {
               access = new access()
                        {
                            allPs = "new_value",
                            availableAccounts = "new_value",
                        }
               combinedServiceIndicator = false,
               frequencyPerDay = 4,
               recurringIndicator = false,
               validUntil = "some_date_YYYYMMDD"
           }
    ...etc...
};

Open in new window


Read more about object initializers.
N MConsultant

Author

Commented:
Thank you, it worked immediately.
N MConsultant

Author

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

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial