XeroAPI / Xero-NetStandard

A wrapper of the Xero API in the .NetStandard 2.0 framework. Supports Accounting, Payroll AU/US, and Files
MIT License
118 stars 119 forks source link

Unable to serialize Invoice to XML when the contact belongs to a contact group #368

Open bryanallott opened 2 years ago

bryanallott commented 2 years ago

C# Xero.NetStandard.OAuth2Client.1.3.3 Xero.NetStandard.OAuth2.3.17.0

I am unable to instantiate an XML serializer as before on the previous SDK Xero.API.SDK.Minimal.2.2.9.

var serializer = new XmlSerializer(typeof(Xero.NetStandard.OAuth2.Model.Accounting.Invoice));

Since StatusEnum on the ContactGroup and the Invoice are conflicting.

Serializing the invoice to XML throws System.InvalidOperationException: There was an error reflecting type 'Xero.NetStandard.OAuth2.Model.Accounting.Invoice'

System.InvalidOperationException: There was an error reflecting type 'Xero.NetStandard.OAuth2.Model.Accounting.Invoice'. ---> System.InvalidOperationException: There was an error reflecting property 'Contact'. ---> System.InvalidOperationException: There was an error reflecting type 'Xero.NetStandard.OAuth2.Model.Accounting.Contact'. ---> System.InvalidOperationException: There was an error reflecting property 'ContactGroups'. ---> System.InvalidOperationException: There was an error reflecting type 'Xero.NetStandard.OAuth2.Model.Accounting.ContactGroup'. ---> System.InvalidOperationException: There was an error reflecting property 'Status'. ---> System.InvalidOperationException: There was an error reflecting type 'Xero.NetStandard.OAuth2.Model.Accounting.ContactGroup.StatusEnum'. ---> System.InvalidOperationException: Types 'Xero.NetStandard.OAuth2.Model.Accounting.ContactGroup.StatusEnum' and 'Xero.NetStandard.OAuth2.Model.Accounting.Invoice.StatusEnum' both use the XML type name, 'StatusEnum', from namespace ''. Use XML attributes to specify a unique XML name and/or namespace for the type.

There might be a way using XMLAttributeOverrides in C# (but i haven't used those before so not sure and still trying)?

Simplified from ContactGroup and Invoice to find the issue where both have a public enum definition of the same name followed by a property public StatusEnum Status. In XML serialization, without any specific namespaces, the exception occurs on creating XmlSerializer.

public class ContactGroup
    {
        public string Name { get; set; }
        public enum StatusEnum
        {
            DRAFT = 1,
        }
        public StatusEnum Status { get; set; }
    }
    public class Invoice
    {
        public ContactGroup ContactGroup {get;set;}
        public enum StatusEnum
        {
            ACTIVE = 1,
        }
        public StatusEnum Status { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var serializer = new XmlSerializer(typeof(Invoice)); //throws
        }
    }
bryanallott commented 2 years ago

Looks like some inconsistencies with the naming of nested enums contribute here.

For example, TypeEnum (shared across BankTransaction, BatchPayment, BrandingTheme, Budget, CreditNote, Invoice, LinkedTransaction, Overpayment but in other classes it's named CLASSNAMETypeEnum) and then StatusEnum (shared across a lot more, also in some classes it's named CLASSNAMEStatusEnum while just StatusEnum in others).

On its own, probably ok, but when objects have relationships or their collections have relationships where the nested types share the same name then it appears to trigger this bug coming from a change in the Microsoft.XmlSerializer. https://github.com/dotnet/runtime/issues/36925

Maybe a consistent naming of all the nested types to CLASSNAMEEnumType would be good?.