locked
Circular reference error with asmx service RRS feed

  • Question

  • User-1526035670 posted
    /// <summary>

    /// Summary description for CompanyServices

    /// </summary>

    [WebService(Namespace = "http://tempuri.org/")]

    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

    [System.ComponentModel.ToolboxItem(false)]

    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.

    // [System.Web.Script.Services.ScriptService]

    public class TestServices: System.Web.Services.WebService

    {

    private MyService _myService;



    private MyService myService

    {

    get

    {

    if (_myService == null)

    {

    _myService = new MyService();

    }



    return _myService;

    }

    }



    [WebMethod]

    public List<Customers> GetData(int companyId, int custType)

    {

    return myService.GetData(companyId, custType).ToList();

    }



    I get the error System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: A circular reference was detected while serializing an object of type Company


    As far as i understand, it seems to be due to returning a List but not entirely sure how to go about resolving this?
    Thursday, April 2, 2020 7:38 PM

Answers

  • User475983607 posted

    What I did was I created the same type and added each column one at a time. I noticed if I had a foreign key to another table this caused the issue.

    Removing that column resolved it. Is there a workaround on that?

    Keep in mind, this is a well know programming/design bug when using an ORM like Entity Framework.  In Entity Framework, a foreign key generates a navigation property.  Serializing the foreign key causes a query that get the related records. 

    I've explained the workaround.  Fill a POCO using the persistence layer and return the POCO not your persistence layer. 

    You can also try data annotations [XmlIgnore].

    https://docs.microsoft.com/en-us/dotnet/standard/serialization/controlling-xml-serialization-using-attributes

    Finally read the documentation for the DBML you are using.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, April 3, 2020 11:46 AM

All replies

  • User415553908 posted

    it appears MyService.GetData() returns a Customer that has self-reference somewhere.
    I presume you've got some sort of hierarchy with your customers and it's very possible that one of your Customers are incorrectly set to be their own parent in this hierarchy.

    To fix it you would either:
    1. correct the data issue (if it is indeed the case)
    2. find where the objects references self and decorate that property with NonSerializedAttribute.

    Thursday, April 2, 2020 7:59 PM
  • User475983607 posted

    This error happens when you try to serialize an entity that has navigation properties which cause a new query to populate the data.  The standard convention is returning a class or la list of a class not an entity. Anyway, you have not shared what myService is so this is just a guess.  

    Thursday, April 2, 2020 8:03 PM
  • User-1526035670 posted
    Hi

    MyService is a class which calls my Data context (DBML) similar to

    Return MyContext.Customers.Where(c=> c.CompanyId=companyId && c.customerType =custType).To list();

    That's an example of my code for the method I'm calling. Company id is referenced from another table.

    I'm returning a list but not sure what you're suggesting to do here? Do you have an example?
    Thursday, April 2, 2020 8:16 PM
  • User-1526035670 posted
    Timur, I don't think I have a self reference or do you have an example of how this may look like so I can double check?

    Regarding number 2 if this was the case where am I applying this?
    Thursday, April 2, 2020 8:19 PM
  • User415553908 posted

    It's a bit hard to say where the issue is without seeing your models and LINQ queries you use (epsecially those to do with navigation properties). 

    Suppose, your Customer class looks like so:

    class Customer {
        public int Id {get;set;}

    public int CompanyId {get;set;
    public Company Company {get;set;} // another way it can happen would be through the use of navigation properties that reference back, see next class
    public Customer ParentCustomer {get;set;} // this would be the prime example of self reference, when ParentCustomer = this }
    class Company {
    public int Id {get;set;}
    //see documentation for more context: https://docs.microsoft.com/en-us/ef/ef6/querying/related-data#turn-lazy-loading-off-for-serialization
    public virtual List<Customer> Customers {get;set;} // given this is lazily loaded, you risk geting into a loop where your company will have a reference to a customer, that will in turn have reference to the company...
    }

    to fix this you could change the above structure to add the NotSerialized as follows:

    class Customer {
        public int Id {get;set;}
       
        public int CompanyId {get;set;   
        [NonSerialized]
        public Customer ParentCustomer {get;set;} // now this will not get serialised into XML
    }
    class Company {
        public int Id {get;set;}
    //see documentation for more context: https://docs.microsoft.com/en-us/ef/ef6/querying/related-data#turn-lazy-loading-off-for-serialization public List<Customer> Customers {get;set;} // assuming you use EF6, switch to eagerly loading the entities you require }

    I hope this makse sense

    Thursday, April 2, 2020 10:51 PM
  • User-1526035670 posted
    Hi
    I believe the code above is using code first approach? If yes I'm not using that but a simple DBML file which has tables from a SQL database.

    Now I think what might be happening is the customers table might have a foreign key to itself as one of the columns is the ParentID for the records in the same table.

    Could this be the problem? I can show the DBML file or is there anything I'm looking out for?

    Many thanks
    Friday, April 3, 2020 2:28 AM
  • User-1526035670 posted
    I created a new class within my asmx file for the customer, added the required properties and added a new for each loop. Added each row from the list from the database into the new class (list) and this worked? I can't understand where and what is causing this circular reference.
    Friday, April 3, 2020 6:24 AM
  • User415553908 posted

    I believe the code above is using code first approach? If yes I'm not using that but a simple DBML file which has tables from a SQL database.
    Now I think what might be happening is the customers table might have a foreign key to itself as one of the columns is the ParentID for the records in the same table.
    Could this be the problem?

    Well, code-first was just to illustrate a point. It seems you've already found your culprit.

    I created a new class within my asmx file for the customer, added the required properties and added a new for each loop. Added each row from the list from the database into the new class (list) and this worked?

    Hard to say without knowing your data model and going through the diffs. If it works now then compare the models before and after - you will probably see that ParentID column that you mentioned above.

    Friday, April 3, 2020 9:23 AM
  • User-1526035670 posted
    Hi

    I don't think it was that..... There was no foreign key.

    What I did was I created the same type and added each column one at a time. I noticed if I had a foreign key to another table this caused the issue.

    Removing that column resolved it. Is there a workaround on that?
    Friday, April 3, 2020 9:50 AM
  • User475983607 posted

    What I did was I created the same type and added each column one at a time. I noticed if I had a foreign key to another table this caused the issue.

    Removing that column resolved it. Is there a workaround on that?

    Keep in mind, this is a well know programming/design bug when using an ORM like Entity Framework.  In Entity Framework, a foreign key generates a navigation property.  Serializing the foreign key causes a query that get the related records. 

    I've explained the workaround.  Fill a POCO using the persistence layer and return the POCO not your persistence layer. 

    You can also try data annotations [XmlIgnore].

    https://docs.microsoft.com/en-us/dotnet/standard/serialization/controlling-xml-serialization-using-attributes

    Finally read the documentation for the DBML you are using.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, April 3, 2020 11:46 AM