0

The error I'm getting is as follows:

{"Cannot create and populate list type ReasonCodeList. Path 'AppointmentReasonList[0].ReasonCodeList', line 1, position 162."}

I'm getting this error when converting the following sample JSON data:

{
    "ErrorCode":""
    ,"ErrorMessage":""
    ,"AppointmentReasonList":[
        {
            "ClassCode":"851"
            ,"ClassDescription":"newpat"
            ,"Active":true
            ,"IsPatientRelated":true
            ,"ReasonCodeList":[
                {
                    "Code":"851"
                    ,"Description":"Emergency New Patient Visit"
                    ,"Duration":15
                    ,"Active":true
                }
                ,{
                    "Code":"BH NEW"
                    ,"Description":"BH NEW"
                    ,"Duration":15
                    ,"Active":true
                }
                            ]
        }
        ,{
            "ClassCode":"ANE"
            ,"ClassDescription":"Anesthesia"
            ,"Active":true
            ,"IsPatientRelated":true
            ,"ReasonCodeList":[
                {
                    "Code":"123456"
                    ,"Description":"This is only a test"
                    ,"Duration":15
                    ,"Active":true
                }
                                ]
        }                   
                            ]
}

I've created the following classes to try and match the data structure.

public class AppointmentReasonResponse
        {
            public string ErrorCode { get; set; }
            public string ErrorMessage { get; set; }
            public List<AppointmentReason> AppointmentReasonList { get; set; }
        }

        public class AppointmentReason
        {
            public string ClassCode { get; set; }
            public string ClassDescription { get; set; }
            public bool Active { get; set; }
            public bool IsPatientRelated { get; set; }
            public ReasonCodeList ReasonCodeList { get; set; }
        }

        public class ReasonCodeList:IEnumerable<ReasonCode>
        {
            public List<ReasonCode> ReasonCodeLi { get; set; }

            IEnumerator<ReasonCode> IEnumerable<ReasonCode>.GetEnumerator()
            {
                // Return the array object's IEnumerator.
                foreach (ReasonCode Reason in ReasonCodeLi)
                {
                    yield return Reason;
                }
            }

            public IEnumerator<ReasonCode> GetEnumerator()
            {
                // Return the array object's IEnumerator.
                return ReasonCodeLi.GetEnumerator();
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                // call the generic version of the method
                return this.GetEnumerator();
            }
        }

        public class ReasonCode
        {
            public string Code { get; set; }
            public string Description { get; set; }
            public int Duration { get; set; }
            public bool Active { get; set; }
        }

If, you've made it this far, I apologize for the verbose amount of code but I think all of it was necessary details.

Originally I was getting the same error for this question.

When I adjusted my class structure by adding the ReasonCodeList class I began getting the new error.

The end objective is to extract every Code and Description for every reason object in the JSON and use them as parameters in an SQL Procedure.

This will require two foreach loops and the ReasonCodeList custom collection must implement IEnumerable to do so.

Any help will be greatly appreciated. I'm unfamiliar with the IEnumerable interface and the restrictions surrounding it.

EDIT:

In response to @Mr Hery: The following error occurs when I try to structure the AppointmentReason class as you suggested:

{"Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"}) into type ReasonCodeList' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.\r\nPath 'AppointmentReasonList[0].ReasonCodeList[0].Code', line 1, position 170."}

I originally had this class structured with the ReasonCodeList attribute being a type of List as that's essentially what it is but got the same error. I tried replacing that with the ReasonCodeList object as was suggested in the referenced answer in the previous original post section.

When I made the changes, the error at the very top of this question is what occurred.

EDIT #2

In response to @Frank Fajardo & his suggestion, this is what the deserialized AppointReasonResponse object will be used for:

    jarray = JsonConvert.DeserializeObject<AppointmentReasonResponse>(json);
    foreach (AppointmentReason ApptReason in jarray.AppointmentReasonList)
    {
        foreach (ReasonCode Reason in ApptReason)
        {
            AddInterfacePMReasonCode(PracticeID, Reason.Code, Reason.Description);
        }
    }

The attributes for the class ReasonCode due to the following error:

Error 105 foreach statement cannot operate on variables of type 'AppointmentReason' because 'AppointmentReason' does not contain a public definition for 'GetEnumerator'

EDIT 3

As @Frank Fajardo pointed out, the inner foreach loop in Edit #2 was looking at the AppointmentReason object and not its list property. When the code is fixed, an error is returned much like the one I posted originally in this post.

New class object and modified foreach loop:

public class AppointmentReasonResponse
        {
            public string ErrorCode { get; set; }
            public string ErrorMessage { get; set; }
            public AppointmentReasonList AppointmentReasonList { get; set; }
        }

        public class AppointmentReasonList : IEnumerable<AppointmentReason>
        {

            public List<AppointmentReason> AppointmentReasonLi { get; set; }

            IEnumerator<AppointmentReason> IEnumerable<AppointmentReason>.GetEnumerator()
            {
                foreach (AppointmentReason ApptReason in AppointmentReasonLi)
                {
                    yield return ApptReason;
                }
            }

            public IEnumerator<AppointmentReason> GetEnumerator()
            {
                return AppointmentReasonLi.GetEnumerator();
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return this.GetEnumerator();
            }
        }

foreach (AppointmentReason ApptReason in jarray.AppointmentReasonList)
                {
                    foreach (ReasonCode Reason in ApptReason.ReasonCodeList)
                    {
                        AddInterfacePMReasonCode(PracticeID, Reason.Code, Reason.Description);
                    }
                }

Error received:

{"Cannot create and populate list type AppointmentReasonList. Path 'AppointmentReasonList', line 1, position 59."}

W.Harr
  • 303
  • 1
  • 4
  • 15
  • Please put the code that do the deserialize too. – Mr Hery Apr 13 '18 at 14:46
  • The `public ReasonCodeList ReasonCodeList { get; set; }` must be `public List ReasonCodeList { get; set; }` – Mr Hery Apr 13 '18 at 14:53
  • Have you Clear you build and then rebuild? If the error still came up, maybe can try to modified the enum of `ReasonCodeList` class. – Mr Hery Apr 14 '18 at 08:52
  • Also dont forget to check the data the came up from the `ReasonCodeList`. They must be equal with the JSON data. – Mr Hery Apr 14 '18 at 08:53
  • @Mr Hery I cleaned and then rebuilt the project as you suggested and am getting the same error. Also, I double checked the ReasonCodeResponse along with the rest of the class objects with the sample JSON response I provided. I don't see any inconsistencies – W.Harr Apr 16 '18 at 16:34

4 Answers4

1

Maybe change your AppointmentReasonto:

    public class AppointmentReason
    {
        public string ClassCode { get; set; }
        public string ClassDescription { get; set; }
        public bool Active { get; set; }
        public bool IsPatientRelated { get; set; }
        public List<ReasonCode> ReasonCodeList { get; set; }
    }

UPDATE

Your loop ode is incorrect. It should be like this (notice the AppReason.ReasonCodeList instead of just AppReason in the inner foreach loop):

jarray = JsonConvert.DeserializeObject<AppointmentReasonResponse>(json);
foreach (AppointmentReason ApptReason in jarray.AppointmentReasonList)
{
    foreach (ReasonCode Reason in ApptReason.ReasonCodeList)
    {
        AddInterfacePMReasonCode(PracticeID, Reason.Code, Reason.Description);
    }
}

UPDATE 2

I have no idea why you changed your AppointmentReasonResponse.AppointmentReasonList property from being of type List<AppointmentReason> to a new type AppointmentReasonList? But it appears you think you need to introduce a property which implements an enumerator. But you do not need it. A List<T> implements IEnumerable<T>.

So your classes should really be just like these:

    public class AppointmentReasonResponse
    {
        public string ErrorCode { get; set; }
        public string ErrorMessage { get; set; }
        public List<AppointmentReason> AppointmentReasonList { get; set; }
    }

    public class AppointmentReason
    {
        public string ClassCode { get; set; }
        public string ClassDescription { get; set; }
        public bool Active { get; set; }
        public bool IsPatientRelated { get; set; }
        public List<ReasonCode> ReasonCodeList { get; set; }
    }

    public class ReasonCode
    {
        public string Code { get; set; }
        public string Description { get; set; }
        public int Duration { get; set; }
        public bool Active { get; set; }
    }

Then you deserialise and use it as I indicated above.

Frank Fajardo
  • 7,034
  • 1
  • 29
  • 47
  • Thanks for your response. Refer to the edit made in the question in reference to the answer by Mr Hery as to the error that occurs when your suggestion is made. – W.Harr Apr 16 '18 at 15:44
  • Have you tried what I suggested? (It doesn't look like you have.) – Frank Fajardo Apr 16 '18 at 23:37
  • You are correct Frank. I thought the suggestion you made was the same as Mr Hery's but I was mistaken. Even though this will correctly deserialize into the AppointmentReasonResponse, the new object will not be able to perform its end task which is to be looped through and add its attributes as parameters to a SQL connection. I will post the associated code and error as an edit in the answer – W.Harr Apr 27 '18 at 19:50
  • @W.Harr, your inner `foreach` loop is looking at an object (of type `AppointmentReason`) rather than a list property in that object (which is the property named `ReasonCodeList`), so it is complaining that the object is not an enumerable/collection. See my update on how you should do it. – Frank Fajardo Apr 28 '18 at 00:33
  • you are right in pointing out that the inner foreach loop was not looking at the list property in the object. I updated my code as you suggested but I began receiving the same type of error I posted in the beginning of my questions where the program is unable to create and populate the object. I will post the exact error in the post. – W.Harr Apr 28 '18 at 14:30
  • @W.Harr see my *Update 2. – Frank Fajardo Apr 29 '18 at 10:12
  • Appreciate you sticking this one out with me. I implemented your suggestions and I got the same error that I posted in edit #2 of my question. You are correct however in pointing out that the enumerable implementation is unnecessary. I got a slightly modified version of your answer on a separate forum that defines a class of the List type and uses that class as the type for the respective properties for each object that needs to be iterated. Not sure why this way works and yours doesn't because they essentially do the same thing. Regardless, a million thanks for all your help – W.Harr Apr 30 '18 at 15:48
1

Thanks everybody for all your suggestions. I posted this question on a separate forum and received an answer the worked from Eric Lynch at codeproject.com

You can view his answer here: https://www.codeproject.com/Questions/1241686/JSON-deserializer-cannot-create-populate-object

As Eric and @Frank Fajardo point out, neither the AppointmentReasonList nor the ReasonCodeList classes need to implement IEnumerable{T}, as the List{T} type already implements the interface.

For some reason, you have to define classes that inherit from List{T} and use that class as the collection type, as opposed to just defining the property itself of a type List{T}.

I'm not sure why this is, because both methods seem to be doing the same thing, but when using the second method you get the following error when you try to iterate through the resulting object:

Error 105 foreach statement cannot operate on variables of type 'AppointmentReason' because 'AppointmentReason' does not contain a public definition for 'GetEnumerator'

Not sure why this is, but at the end of the day, Eric Lynch's answer provided the desired result.

W.Harr
  • 303
  • 1
  • 4
  • 15
0

The error says that cannot create and populate list is because you have missing List<> in your code. Here's the correction:

public class AppointmentReasonResponse
{
    public string ErrorCode { get; set; }
    public string ErrorMessage { get; set; }
    public List<AppointmentReason> AppointmentReasonList { get; set; }
}

public class AppointmentReason
{
    public string ClassCode { get; set; }
    public string ClassDescription { get; set; }
    public bool Active { get; set; }
    public bool IsPatientRelated { get; set; }
    public List<ReasonCodeList> ReasonCodeList { get; set; }
}

public class ReasonCodeList:IEnumerable<ReasonCode>
{
    public List<ReasonCode> ReasonCodeLi { get; set; }

    IEnumerator<ReasonCode> IEnumerable<ReasonCode>.GetEnumerator()
    {
        // Return the array object's IEnumerator.
        foreach (ReasonCode Reason in ReasonCodeLi)
        {
            yield return Reason;
        }
    }

    public IEnumerator<ReasonCode> GetEnumerator()
    {
        // Return the array object's IEnumerator.
        return ReasonCodeLi.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        // call the generic version of the method
        return this.GetEnumerator();
    }
}

public class ReasonCode
{
    public string Code { get; set; }
    public string Description { get; set; }
    public int Duration { get; set; }
    public bool Active { get; set; }
}

Your JSON return an array data, so you need to put the List<>

Mr Hery
  • 829
  • 1
  • 7
  • 25
-1

When you have the JSON, don't hand-craft the class or guess at them, just head over to http://json2csharp.com, plug in the JSON, and let it generate the classes for you.

public class ReasonCodeList
{
    public string Code { get; set; }
    public string Description { get; set; }
    public int Duration { get; set; }
    public bool Active { get; set; }
}

public class AppointmentReasonList
{
    public string ClassCode { get; set; }
    public string ClassDescription { get; set; }
    public bool Active { get; set; }
    public bool IsPatientRelated { get; set; }
    public List<ReasonCodeList> ReasonCodeList { get; set; }
}

public class RootObject
{
    public string ErrorCode { get; set; }
    public string ErrorMessage { get; set; }
    public List<AppointmentReasonList> AppointmentReasonList { get; set; }
}

var root = JsonConvert.DeserializeObject<RootObject>(json);

foreach (var appointmentReason in root.AppointmentReasonList)
{
    foreach (var reasonCode in appointmentReason.ReasonCodeList)
    {
        Console.WriteLine($"Code: {reasonCode.Code}; Description {reasonCode.Description}");
    }
}

Given you original JSON, the above produced the following output.

Code: 851; Description Emergency New Patient Visit

Code: BH NEW; Description BH NEW

Code: 123456; Description This is only a test

I also created a Fiddle at https://dotnetfiddle.net/170Xob.

Community
  • 1
  • 1
Craig W.
  • 17,838
  • 6
  • 49
  • 82
  • I actually did use that exact link initially initially. The problem with it is that it doesn't employ the IEnumerable interface for any of the classes it makes so I can't loop over the objects the way that I need to. – W.Harr Apr 27 '18 at 20:34
  • Your statement doesn't make sense given that your original post says the "end objective is to extract every Code and Description for every reason object..." Check the update above. – Craig W. Apr 27 '18 at 20:59