Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How are exs:identity numbers assigned? #454

Closed
gmkado opened this issue Sep 28, 2020 · 4 comments
Closed

How are exs:identity numbers assigned? #454

gmkado opened this issue Sep 28, 2020 · 4 comments
Assignees
Labels
bug (cc: fix) Something isn't working

Comments

@gmkado
Copy link

gmkado commented Sep 28, 2020

I am running into an issue when I enable references in my configuration.

In my application I determine whether a data object requires saving to file by comparing it's md5 hash to a previously saved hash value stored separately. For some reason my unchanged objects that had references were always requiring a resave.

I tracked it down to the exs:identity and exs:reference numbers being incremented with every serialization. I'm guessing this is because there is some internal cache of the references and my "SaveAndRestore" function is causing Ref1/Ref2 to no longer be the same object.

I only care that the references within a given object are maintained. Is there a way to reset this internal cache so my exs:identity and exs:reference numbers always start at the same index for a given serialization?

    public class Foo
    {
        public Foo Ref1 {get; set;}
        public Foo Ref2 { get; set;}
    }

    [Test]
    public void PlaygroundReferenceTest()
    {
        var serializer = new ConfigurationContainer()
            .UseAutoFormatting()
            .UseOptimizedNamespaces()
            .EnableReferences()
            .Create();

        var myRef = new Foo();
        Foo myObj = new Foo
        {
            Ref1 = myRef,
            Ref2 = myRef
        };

        var hashes = new List<string>();  // <--- THESE SHOULD ALL BE THE SAME AFTER THE FOR LOOP
        for (int i = 0; i < 10; i++)
        {
            myObj = SaveAndRestore(myObj);
            hashes.Add(GetHash(myObj));
        }

        // THIS IS HOW I CHECK IF THE OBJECT REQUIRES BEING SAVED TO DISK
        string GetHash(Foo obj)
        {
            var str = Serialize(obj);
            using (var md5 = MD5.Create())
            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(str)))
            {
                return Convert.ToBase64String(md5.ComputeHash(stream));
            }
        } 

        // THIS SIMULATES A SAVE TO DISK AND THEN RESTORE FROM DISK
        Foo SaveAndRestore(Foo obj)
        {
            return Deserialize(Serialize(obj));
        }

        string Serialize(object obj)
        {
            return serializer.Serialize(
                new XmlWriterSettings { Indent = true }, obj);
        }

        Foo Deserialize(string str)
        {
            return serializer.Deserialize<Foo>(str);
        }
    }

Result:
image

A comparison of the serialization shows the root cause:
image

@issue-label-bot
Copy link

Issue-Label Bot is automatically applying the label question to this issue, with a confidence of 0.86. Please mark this comment with 👍 or 👎 to give our bot feedback!

Links: app homepage, dashboard and code for this bot.

@issue-label-bot issue-label-bot bot added the question Further information is requested label Sep 28, 2020
@Mike-E-angelo Mike-E-angelo self-assigned this Sep 28, 2020
@Mike-E-angelo Mike-E-angelo added bug (cc: fix) Something isn't working and removed question Further information is requested labels Sep 28, 2020
@Mike-E-angelo
Copy link
Member

Good find, @gmkado! I am thinking that when I originally made this I was attempting to impact performance so that the generated id for each object in memory would only be calculated once per container/domain. As you denote, however, that results in unexpected IDs for subsequent serializations. I am in agreement that subsequent serializations of the same entity graph should produce the same XML each and every time (assuming all values/references are the same).

I have produced a build for you here that addresses this here:
#455 (comment)

That's the good news. The "bad" news is that while I could get this deployed to nuget tomorrow, I will be out of town for the following two weeks, and am hesitant to deploy to production and then ghost immediately. 😅

The concern here of course is that while all tests pass and everything "seems" to be OK with the new scope, someone might be using that as a "feature" (ahhh software!). I would rather be around to address this appropriately if that is the case.

So, if you're able to work with the above in the meantime and that works for you, then that works for me. 👍

@gmkado
Copy link
Author

gmkado commented Sep 28, 2020

Works for me, thanks!

@Mike-E-angelo
Copy link
Member

Mike-E-angelo commented Oct 13, 2020

Alrighty, this is now deployed and published in NuGet for you:
https://www.nuget.org/packages/ExtendedXmlSerializer/

Please let me know if you having any further problems and I will investigate. Closing for now.

An extensible Xml Serializer for .NET that builds on the functionality of the classic XmlSerializer with a powerful and robust extension model.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug (cc: fix) Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants