// // System.ComponentModel.Design.Serialization.CodeDomComponentSerializationService // // Authors: // Ivan N. Zlatev (contact@i-nZ.net) // // (C) 2007 Ivan N. Zlatev // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // #if NET_2_0 using System; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Collections; using System.Collections.Generic; using System.IO; namespace System.ComponentModel.Design.Serialization { // A ComponentSerializationService that uses a CodeDomSerializationStore // to serialize Components and MemberDescriptors to CodeStatement and CodeStatementCollection // public sealed class CodeDomComponentSerializationService : ComponentSerializationService { [Serializable] private class CodeDomSerializationStore : SerializationStore, ISerializable { [Serializable] private class Entry { private bool _isSerialized; private object _serialized; private bool _absolute; private string _name; protected Entry () { } public Entry (string name) { if (name == null) throw new ArgumentNullException ("name"); _name = name; _isSerialized = false; _absolute = false; } public bool IsSerialized { get { return _isSerialized; } set { _isSerialized = value; } } public object Serialized { get { return _serialized; } set { _serialized = value; _isSerialized = true; } } public bool Absolute { get { return _absolute; } set { _absolute = value; } } public string Name { get { return _name; } set { _name = value; } } } [Serializable] private class MemberEntry : Entry { private MemberDescriptor _descriptor; protected MemberEntry () { } public MemberEntry (MemberDescriptor descriptor) { if (descriptor == null) throw new ArgumentNullException ("descriptor"); _descriptor = descriptor; base.Name = descriptor.Name; } public MemberDescriptor Descriptor { get { return _descriptor; } set { _descriptor = value; } } } [Serializable] private class ObjectEntry : Entry { private Type _type; [NonSerialized] private object _instance; private Dictionary _members; private bool _entireObject; protected ObjectEntry () { } public ObjectEntry (object instance, string name) : base (name) { if (instance == null) throw new ArgumentNullException ("instance"); _instance = instance; _type = instance.GetType (); _entireObject = false; } public Type Type { get { return _type; } } public object Instance { get { return _instance; } set { _instance = value; if (value != null) _type = value.GetType (); } } public Dictionary Members { get { if (_members == null) _members = new Dictionary (); return _members; } set { _members = value; } } public bool IsEntireObject { get { return _entireObject; } set { _entireObject = value; } } } // When e.g Copy->Pasting a component will not be preserved, but the serialized // data will contain references to the original component name. We handle this // here by checking whether CreateInstance returns a component with a different // name and we map the old name to the new one so that GetInstance will return // a reference to the new component. // private class InstanceRedirectorDesignerSerializationManager : IDesignerSerializationManager, IServiceProvider { DesignerSerializationManager _manager; private Dictionary _nameMap; public InstanceRedirectorDesignerSerializationManager (IServiceProvider provider, IContainer container, bool validateRecycledTypes) { if (provider == null) throw new ArgumentNullException ("provider"); DesignerSerializationManager manager = new DesignerSerializationManager (provider); manager.PreserveNames = false; if (container != null) manager.Container = container; manager.ValidateRecycledTypes = validateRecycledTypes; _manager = manager; } public IDisposable CreateSession () { return _manager.CreateSession (); } public IList Errors { get { return _manager.Errors; } } object IServiceProvider.GetService (Type service) { return ((IServiceProvider)_manager).GetService (service); } #region IDesignerSerializationManager Wrapper Implementation void IDesignerSerializationManager.AddSerializationProvider (IDesignerSerializationProvider provider) { ((IDesignerSerializationManager)_manager).AddSerializationProvider (provider); } void IDesignerSerializationManager.RemoveSerializationProvider (IDesignerSerializationProvider provider) { ((IDesignerSerializationManager)_manager).RemoveSerializationProvider (provider); } object IDesignerSerializationManager.CreateInstance (Type type, ICollection arguments, string name, bool addToContainer) { object instance = ((IDesignerSerializationManager)_manager).CreateInstance (type, arguments, name, addToContainer); string newName = ((IDesignerSerializationManager)_manager).GetName (instance); if (newName != name) { if (_nameMap == null) _nameMap = new Dictionary (); _nameMap[name] = newName; } return instance; } object IDesignerSerializationManager.GetInstance (string name) { if (_nameMap != null && _nameMap.ContainsKey (name)) return ((IDesignerSerializationManager)_manager).GetInstance (_nameMap[name]); return ((IDesignerSerializationManager)_manager).GetInstance (name); } Type IDesignerSerializationManager.GetType (string name) { return ((IDesignerSerializationManager)_manager).GetType (name); } object IDesignerSerializationManager.GetSerializer (Type type, Type serializerType) { return ((IDesignerSerializationManager)_manager).GetSerializer (type, serializerType); } string IDesignerSerializationManager.GetName (object instance) { return ((IDesignerSerializationManager)_manager).GetName (instance); } void IDesignerSerializationManager.SetName (object instance, string name) { ((IDesignerSerializationManager)_manager).SetName (instance, name); } void IDesignerSerializationManager.ReportError (object error) { ((IDesignerSerializationManager)_manager).ReportError (error); } ContextStack IDesignerSerializationManager.Context { get { return ((IDesignerSerializationManager)_manager).Context; } } PropertyDescriptorCollection IDesignerSerializationManager.Properties { get { return ((IDesignerSerializationManager)_manager).Properties; } } event EventHandler IDesignerSerializationManager.SerializationComplete { add { ((IDesignerSerializationManager)_manager).SerializationComplete += value; } remove { ((IDesignerSerializationManager)_manager).SerializationComplete -= value; } } event ResolveNameEventHandler IDesignerSerializationManager.ResolveName { add { ((IDesignerSerializationManager)_manager).ResolveName += value; } remove { ((IDesignerSerializationManager)_manager).ResolveName -= value; } } #endregion } // InstanceRedirectorDesignerSerializationManager private bool _closed; private Dictionary _objects; private IServiceProvider _provider; private ICollection _errors; internal CodeDomSerializationStore () : this (null) { } internal CodeDomSerializationStore (IServiceProvider provider) { _provider = provider; } private CodeDomSerializationStore (SerializationInfo info, StreamingContext context) { _objects = (Dictionary) info.GetValue ("objects", typeof (Dictionary)); _closed = (bool) info.GetValue ("closed", typeof (bool)); } void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) { info.AddValue ("objects", _objects); info.AddValue ("closed", _closed); } public override void Close () { if (!_closed) { Serialize (_provider); _closed = true; } } internal static CodeDomSerializationStore Load (Stream stream) { return new BinaryFormatter ().Deserialize (stream) as CodeDomSerializationStore; } public override void Save (Stream stream) { Close (); new BinaryFormatter ().Serialize (stream, this); } private void Serialize (IServiceProvider provider) { if (provider == null || _objects == null) return; // Use a new serialization manager to prevent from "deadlocking" the surface one // by trying to create new session when one currently exists // InstanceRedirectorDesignerSerializationManager manager = new InstanceRedirectorDesignerSerializationManager (provider, null, false); ((IDesignerSerializationManager)manager).AddSerializationProvider (CodeDomSerializationProvider.Instance); IDisposable session = manager.CreateSession (); foreach (ObjectEntry objectEntry in _objects.Values) { if (objectEntry.IsEntireObject) { CodeDomSerializer serializer = (CodeDomSerializer) ((IDesignerSerializationManager)manager).GetSerializer (objectEntry.Type, typeof (CodeDomSerializer)); if (serializer != null) { object serialized = null; if (objectEntry.Absolute) serialized = serializer.SerializeAbsolute (manager, objectEntry.Instance); else serialized = serializer.Serialize (manager, objectEntry.Instance); objectEntry.Serialized = serialized; } } else { foreach (MemberEntry memberEntry in objectEntry.Members.Values) { CodeDomSerializer serializer = (CodeDomSerializer) ((IDesignerSerializationManager)manager).GetSerializer ( objectEntry.Type, typeof (CodeDomSerializer)); if (serializer != null) { object serialized = null; if (memberEntry.Absolute) { serialized = serializer.SerializeMemberAbsolute (manager, objectEntry.Instance, memberEntry.Descriptor); } else { serialized = serializer.SerializeMember (manager, objectEntry.Instance, memberEntry.Descriptor); } memberEntry.Serialized = serialized; } } } _errors = manager.Errors; } _errors = manager.Errors; session.Dispose (); } internal void AddObject (object instance, bool absolute) { if (_closed) throw new InvalidOperationException ("store is closed"); if (_objects == null) _objects = new Dictionary (); string objectName = GetName (instance); if (!_objects.ContainsKey (objectName)) { ObjectEntry objectEntry = new ObjectEntry (instance, objectName); objectEntry.Absolute = absolute; objectEntry.IsEntireObject = true; _objects[objectName] = objectEntry; } } internal void AddMember (object owner, MemberDescriptor member, bool absolute) { if (_closed) throw new InvalidOperationException ("store is closed"); if (member == null) throw new ArgumentNullException ("member"); if (owner == null) throw new ArgumentNullException ("owner"); if (_objects == null) _objects = new Dictionary (); string objectName = GetName (owner); if (!_objects.ContainsKey (objectName)) _objects.Add (objectName, new ObjectEntry (owner, objectName)); MemberEntry memberEntry = new MemberEntry (member); memberEntry.Absolute = absolute; _objects[objectName].Members[member.Name] = memberEntry; } private string GetName (object value) { if (value == null) throw new ArgumentNullException ("value"); string name = null; IComponent component = value as IComponent; if (component != null && component.Site != null) { if (component.Site is INestedSite) name = ((INestedSite)component.Site).FullName; else name = component.Site != null ? component.Site.Name : null; } else if (value is MemberDescriptor) { name = ((MemberDescriptor) value).Name; } else { name = value.GetHashCode ().ToString (); } return name; } internal ICollection Deserialize (IServiceProvider provider, IContainer container, bool validateRecycledTypes, bool applyDefaults) { List objectInstances = new List (); if (provider == null || _objects == null) return objectInstances; _provider = provider; // Use a new serialization manager to prevent from "deadlocking" the surface one // by trying to create new session when one currently exists // InstanceRedirectorDesignerSerializationManager manager = new InstanceRedirectorDesignerSerializationManager (provider, container, validateRecycledTypes); ((IDesignerSerializationManager)manager).AddSerializationProvider (CodeDomSerializationProvider.Instance); IDisposable session = manager.CreateSession (); foreach (ObjectEntry entry in _objects.Values) objectInstances.Add (DeserializeEntry (manager, entry)); _errors = manager.Errors; session.Dispose (); return objectInstances; } private object DeserializeEntry (IDesignerSerializationManager manager, ObjectEntry objectEntry) { object deserialized = null; if (objectEntry.IsEntireObject) { CodeDomSerializer serializer = (CodeDomSerializer) manager.GetSerializer (objectEntry.Type, typeof (CodeDomSerializer)); if (serializer != null) { deserialized = serializer.Deserialize (manager, objectEntry.Serialized); // check if the name of the object has changed // (if it e.g clashes with another name) string newName = manager.GetName (deserialized); if (newName != objectEntry.Name) objectEntry.Name = newName; } } else { foreach (MemberEntry memberEntry in objectEntry.Members.Values) { CodeDomSerializer serializer = (CodeDomSerializer) manager.GetSerializer (objectEntry.Type, typeof (CodeDomSerializer)); if (serializer != null) serializer.Deserialize (manager, memberEntry.Serialized); } } return deserialized; } public override ICollection Errors { get { if (_errors == null) _errors = new object[0]; return _errors; } } } // CodeDomSerializationStore private IServiceProvider _provider; public CodeDomComponentSerializationService () : this (null) { } public CodeDomComponentSerializationService (IServiceProvider provider) { _provider = provider; } public override SerializationStore CreateStore () { return new CodeDomSerializationStore (_provider); } public override SerializationStore LoadStore (Stream stream) { return CodeDomSerializationStore.Load (stream); } public override ICollection Deserialize (SerializationStore store) { return this.Deserialize (store, null); } public override ICollection Deserialize (SerializationStore store, IContainer container) { return DeserializeCore (store, container, true, true); } public override void DeserializeTo (SerializationStore store, IContainer container, bool validateRecycledTypes, bool applyDefaults) { DeserializeCore (store, container, validateRecycledTypes, applyDefaults); } private ICollection DeserializeCore (SerializationStore store, IContainer container, bool validateRecycledTypes, bool applyDefaults) { CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore; if (codeDomStore == null) throw new InvalidOperationException ("store type unsupported"); return codeDomStore.Deserialize (_provider, container, validateRecycledTypes, applyDefaults); } public override void Serialize (SerializationStore store, object value) { SerializeCore (store, value, false); } public override void SerializeAbsolute (SerializationStore store, object value) { SerializeCore (store, value, true); } public override void SerializeMember (SerializationStore store, object owningObject, MemberDescriptor member) { SerializeMemberCore (store, owningObject, member, false); } public override void SerializeMemberAbsolute (SerializationStore store, object owningObject, MemberDescriptor member) { SerializeMemberCore (store, owningObject, member, true); } private void SerializeCore (SerializationStore store, object value, bool absolute) { if (value == null) throw new ArgumentNullException ("value"); if (store == null) throw new ArgumentNullException ("store"); CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore; if (store == null) throw new InvalidOperationException ("store type unsupported"); codeDomStore.AddObject (value, absolute); } private void SerializeMemberCore (SerializationStore store, object owningObject, MemberDescriptor member, bool absolute) { if (member == null) throw new ArgumentNullException ("member"); if (owningObject == null) throw new ArgumentNullException ("owningObject"); if (store == null) throw new ArgumentNullException ("store"); CodeDomSerializationStore codeDomStore = store as CodeDomSerializationStore; if (codeDomStore == null) throw new InvalidOperationException ("store type unsupported"); codeDomStore.AddMember (owningObject, member, absolute); } } } #endif