On Protobuf.Net, using AsReference and multiple instances of object which should be deserialized only once.

  • Posted on: 27 November 2014
  • By: Michał Turecki

There is a ProtoBuf.Net fact regarding using AsReference which somehow I missed when digging into why [ProtoAfterDeserialization] attribute is not applied for some objects.
The truth is that it is applied for some but not other objects even if I used AsReference attribute in some places. The AsReference attribute should be applied to ALL REFERENCES TO THE OBJECT, both collections and navigational properties, NOT JUST REFERENCES OTHER THAN THE REFERENCE WE CONSIDER MAIN ONE.

A simple test to prove it is below:

using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using NUnit.Framework;
using ProtoBuf;

namespace ProtoBufAsReferenceTest
{
    [ProtoContract]
    public class Office
    {
        public static int DeserializationCounter = 0;

        [ProtoMember(1)]
        public Collection<Computer> Computers { get; private set; }

        [ProtoMember(2)]
        public Collection<Person> People { get; private set; }

        public Office()
        {
            Computers = new Collection<Computer>();
            People = new Collection<Person>();
        }

        [ProtoAfterDeserialization]
        protected void OnDeserialize()
        {
            DeserializationCounter++;
            foreach(var computer in Computers)
            {
                computer.Office = this;
            }
            foreach(var person in People)
            {
                person.Office = this;
            }
        }
    }

    [ProtoContract]
    public class Computer
    {
        public static int DeserializationCounter = 0;

        [ProtoMember(1, AsReference = true)]
        public Person Person { get; set; }

        [ProtoIgnore]
        public Office Office { get; set; }

        [ProtoAfterDeserialization]
        protected void OnDeserialize()
        {
            DeserializationCounter++;
        }
    }

    [ProtoContract]
    public class Person
    {
        public static int DeserializationCounter = 0;

        [ProtoMember(1, AsReference = true)]
        public Computer Computer { get; set; }

        [ProtoIgnore]
        public Office Office { get; set; }

        [ProtoAfterDeserialization]
        protected void OnDeserialize()
        {
            DeserializationCounter++;
        }
    }

    [TestFixture]
    public class TestClasses
    {
        [Test]
        public void TestAsReference()
        {
            // 3 instances are created 1 of each type
            var office = new Office();
            var computer = new Computer();
            var developer = new Person();

            office.Computers.Add(computer);
            office.People.Add(developer);
            computer.Person = developer;
            developer.Computer = computer;

            using(var ms = new MemoryStream())
            {
                Serializer.NonGeneric.Serialize(ms, office);
                ms.Position = 0;
                Check(Serializer.Deserialize<Office>(ms));
            }
        }

        private void Check(Office office)
        {
            Assert.AreEqual(1, Office.DeserializationCounter);
            Assert.AreEqual(1, Person.DeserializationCounter); // fails - 2
            Assert.AreEqual(1, Computer.DeserializationCounter); // fails - 2
            var computer = office.People.First().Computer;
            Assert.IsNotNull(computer.Office); // fails - Office is null
        }
    }
}

Office class contains collections of Computers and Peoople without AsReference attribute. Person reference to the Computer for a change uses AsReference attribute. In the end 2 instances of Computer and 2 instances of Person are created.

Only change necessary to fix this problem is adding AsReference to the Office class collections:

        [ProtoMember(1, AsReference = true)]
        public Collection Computers { get; private set; }

        [ProtoMember(2, AsReference = true)]
        public Collection People { get; private set; }

I am not sure if this is common mistake people make when using ProtoBuf.Net but I suspect this might be the case as none of the questions on StackOverflow I've seen in the past mention this.
Or maybe it is only me who when using word "reference" thinks of references to the actual object which implies having at least a single copy of the actual object marked without "AsReference".
Bottom line is if you use AsReference, use it everywhere the object is referenced.

Comments

Generic Legally Levaquin Cravit Internet Low Price On Line Buy Propecia Usa Buy Propecia Online With No Prescription viagra Prix Du Viagra 25mg

Generic Legally Levaquin Cravit Internet Low Price On Line Buy Propecia Usa Buy Propecia Online With No Prescription viagra Prix Du Viagra 25mg

buy accutane paypal Buying Cheap Flagyl In Wichita Levitra 20mg 30 Tablet viagra Can Amoxil Expire Virgar

buy accutane paypal Buying Cheap Flagyl In Wichita Levitra 20mg 30 Tablet viagra Can Amoxil Expire Virgar

buy accutane paypal Buying Cheap Flagyl In Wichita Levitra 20mg 30 Tablet viagra Can Amoxil Expire Virgar

Free Shipping Worldwide Provera 5mg France Price Shop buy cialis online Cialis O Viagra Cual Es Mejor Action Clomid Glaire Cervicale Achat Viagra Pfizer

Free Shipping Worldwide Provera 5mg France Price Shop buy cialis online Cialis O Viagra Cual Es Mejor Action Clomid Glaire Cervicale Achat Viagra Pfizer

Take Pueraria Mirifica With Estrace cialis 5mg Progesterone Secure Ordering Best Website With Free Shipping

Take Pueraria Mirifica With Estrace cialis 5mg Progesterone Secure Ordering Best Website With Free Shipping

Take Pueraria Mirifica With Estrace cialis 5mg Progesterone Secure Ordering Best Website With Free Shipping

Take Pueraria Mirifica With Estrace cialis 5mg Progesterone Secure Ordering Best Website With Free Shipping

Viagra Gel Online viagra Cialis En Francais Dog Side Effects Of Amoxicillin Finasteride 1 Mg

Viagra Gel Online viagra Cialis En Francais Dog Side Effects Of Amoxicillin Finasteride 1 Mg

Viagra Gel Online viagra Cialis En Francais Dog Side Effects Of Amoxicillin Finasteride 1 Mg

Precio Levitra Farmatodo Antibotic Cephalexin cialis 5 mg Avana(Avanafil) Potenzmittel Cialis 20mg Us Pharmacy Prices For Cialis

Precio Levitra Farmatodo Antibotic Cephalexin cialis 5 mg Avana(Avanafil) Potenzmittel Cialis 20mg Us Pharmacy Prices For Cialis

Precio Levitra Farmatodo Antibotic Cephalexin cialis 5 mg Avana(Avanafil) Potenzmittel Cialis 20mg Us Pharmacy Prices For Cialis

Zithromax Pediatric Suspension Dosing Calculator Cialis Sans Ordonnance En Belgique order cialis online Cialis 20 Prix Discount

Zithromax Pediatric Suspension Dosing Calculator Cialis Sans Ordonnance En Belgique order cialis online Cialis 20 Prix Discount

Amoxicillin Use In First Trimester Pregnancy cialis canada Cialis 5mg Price Cheap Effective Propecia

Dextromethorphan And Amoxicillin Amoxicillin After Lap Band Surgery Antibiotics Similar To Amoxicillin canadian cialis Cephalexin Vaginal Bacteria Can I Purchase Fedex Acticin 30gm Mastercard Accepted Low Cost Drugs From Canada

How To Buy Cheap Generic Viagra Buy Amoxicillin Elixer Levitra And Cialis cialis sem receita Farmacia Andorra Propecia

How To Buy Cheap Generic Viagra Buy Amoxicillin Elixer Levitra And Cialis cialis sem receita Farmacia Andorra Propecia

Finasteride On Sale No Prescription Tadalafil 20mg For Sale Smoking Pot On Amoxicillin cialis Fedex Shipping Macrobid Online

Cialis Generique Tadalafil 30 Pilules Viagra Quanto Prima Profesional Viagra cheapest cialis 20mg Levitra Efectos En Jovenes Clomid Cycle Menstruel

Cialis Generique Tadalafil 30 Pilules Viagra Quanto Prima Profesional Viagra cheapest cialis 20mg Levitra Efectos En Jovenes Clomid Cycle Menstruel

Annonce De Clomid Generic Levitra Shipped From Usa viagra online prescription Xenical Orlistat 120 Mg

Annonce De Clomid Generic Levitra Shipped From Usa viagra online prescription Xenical Orlistat 120 Mg

Annonce De Clomid Generic Levitra Shipped From Usa viagra online prescription Xenical Orlistat 120 Mg

Escitalopram Canadian Pharmacy Viagra Generico 50 Mg viagra Generic Viagra Mastercard Cialis Fecha De Caducidad Vendo Cialis Napoli

Does Keflex Help Bronchitis Buy Fucidin Cream Online cialis 20mg price at walmart Tomar Propecia Estearato De Magnesio Priligy Comprimidos

Does Keflex Help Bronchitis Buy Fucidin Cream Online cialis 20mg price at walmart Tomar Propecia Estearato De Magnesio Priligy Comprimidos

Acquisto Viagra E Cialis Comparaison Prix Viagra Cialis Levitra viagra Articulo 138 Buy Doxycycline 100mg

Acquisto Viagra E Cialis Comparaison Prix Viagra Cialis Levitra viagra Articulo 138 Buy Doxycycline 100mg

Bactrim Roche Cialise Zithromax Can You Drink generic 5mg cialis best price Discount Legally Provera Irregular Periods Order Us Store Fish Amoxicillin Safe For Human

Bactrim Roche Cialise Zithromax Can You Drink generic 5mg cialis best price Discount Legally Provera Irregular Periods Order Us Store Fish Amoxicillin Safe For Human

Online Keflex No Rx Needed Cipla Viagra Products Keflex Drug Information cialis canada Rx Canadian Pharmacy

Online Keflex No Rx Needed Cipla Viagra Products Keflex Drug Information cialis canada Rx Canadian Pharmacy

Vardenafil Levitra Online tarif levitra Buying Toradol In Usa

Vardenafil Levitra Online tarif levitra Buying Toradol In Usa

Vardenafil Levitra Online tarif levitra Buying Toradol In Usa

Propecia Sas Baclofene Cerveau comprar cialis generico por telefono Cialis Es Bueno

Propecia Sas Baclofene Cerveau comprar cialis generico por telefono Cialis Es Bueno