2 // System.ComponentModel.Design.Serialization.CodeDomComponentSerializationService
5 // Ivan N. Zlatev (contact@i-nZ.net)
7 // (C) 2007 Ivan N. Zlatev
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System
.Runtime
.Serialization
;
34 using System
.Runtime
.Serialization
.Formatters
.Binary
;
35 using System
.ComponentModel
;
36 using System
.ComponentModel
.Design
.Serialization
;
37 using System
.Collections
;
38 using System
.Collections
.Generic
;
41 namespace System
.ComponentModel
.Design
.Serialization
43 // A ComponentSerializationService that uses a CodeDomSerializationStore
44 // to serialize Components and MemberDescriptors to CodeStatement and CodeStatementCollection
46 public sealed class CodeDomComponentSerializationService
: ComponentSerializationService
49 private class CodeDomSerializationStore
: SerializationStore
, ISerializable
54 private bool _isSerialized
;
55 private object _serialized
;
56 private bool _absolute
;
63 public Entry (string name
)
66 throw new ArgumentNullException ("name");
68 _isSerialized
= false;
72 public bool IsSerialized
{
73 get { return _isSerialized; }
74 set { _isSerialized = value; }
77 public object Serialized
{
78 get { return _serialized; }
85 public bool Absolute
{
86 get { return _absolute; }
87 set { _absolute = value; }
92 set { _name = value; }
97 private class MemberEntry
: Entry
99 private MemberDescriptor _descriptor
;
101 protected MemberEntry ()
105 public MemberEntry (MemberDescriptor descriptor
)
107 if (descriptor
== null)
108 throw new ArgumentNullException ("descriptor");
109 _descriptor
= descriptor
;
110 base.Name
= descriptor
.Name
;
113 public MemberDescriptor Descriptor
{
114 get { return _descriptor; }
115 set { _descriptor = value; }
120 private class ObjectEntry
: Entry
124 private object _instance
;
125 private Dictionary
<string,MemberEntry
> _members
;
126 private bool _entireObject
;
128 protected ObjectEntry ()
132 public ObjectEntry (object instance
, string name
) : base (name
)
134 if (instance
== null)
135 throw new ArgumentNullException ("instance");
136 _instance
= instance
;
137 _type
= instance
.GetType ();
138 _entireObject
= false;
142 get { return _type; }
145 public object Instance
{
146 get { return _instance; }
150 _type
= value.GetType ();
154 public Dictionary
<string,MemberEntry
> Members
{
156 if (_members
== null)
157 _members
= new Dictionary
<string, MemberEntry
> ();
160 set { _members = value; }
163 public bool IsEntireObject
{
164 get { return _entireObject; }
165 set { _entireObject = value; }
169 // When e.g Copy->Pasting a component will not be preserved, but the serialized
170 // data will contain references to the original component name. We handle this
171 // here by checking whether CreateInstance returns a component with a different
172 // name and we map the old name to the new one so that GetInstance will return
173 // a reference to the new component.
175 private class InstanceRedirectorDesignerSerializationManager
: IDesignerSerializationManager
, IServiceProvider
177 DesignerSerializationManager _manager
;
178 private Dictionary
<string, string> _nameMap
;
180 public InstanceRedirectorDesignerSerializationManager (IServiceProvider provider
, IContainer container
,
181 bool validateRecycledTypes
)
183 if (provider
== null)
184 throw new ArgumentNullException ("provider");
185 DesignerSerializationManager manager
= new DesignerSerializationManager (provider
);
186 manager
.PreserveNames
= false;
187 if (container
!= null)
188 manager
.Container
= container
;
189 manager
.ValidateRecycledTypes
= validateRecycledTypes
;
193 public IDisposable
CreateSession ()
195 return _manager
.CreateSession ();
198 public IList Errors
{
199 get { return _manager.Errors; }
202 object IServiceProvider
.GetService (Type service
)
204 return ((IServiceProvider
)_manager
).GetService (service
);
207 #region IDesignerSerializationManager Wrapper Implementation
209 void IDesignerSerializationManager
.AddSerializationProvider (IDesignerSerializationProvider provider
)
211 ((IDesignerSerializationManager
)_manager
).AddSerializationProvider (provider
);
214 void IDesignerSerializationManager
.RemoveSerializationProvider (IDesignerSerializationProvider provider
)
216 ((IDesignerSerializationManager
)_manager
).RemoveSerializationProvider (provider
);
219 object IDesignerSerializationManager
.CreateInstance (Type type
, ICollection arguments
, string name
, bool addToContainer
)
221 object instance
= ((IDesignerSerializationManager
)_manager
).CreateInstance (type
, arguments
, name
, addToContainer
);
222 string newName
= ((IDesignerSerializationManager
)_manager
).GetName (instance
);
223 if (newName
!= name
) {
224 if (_nameMap
== null)
225 _nameMap
= new Dictionary
<string, string> ();
226 _nameMap
[name
] = newName
;
231 object IDesignerSerializationManager
.GetInstance (string name
)
233 if (_nameMap
!= null && _nameMap
.ContainsKey (name
))
234 return ((IDesignerSerializationManager
)_manager
).GetInstance (_nameMap
[name
]);
235 return ((IDesignerSerializationManager
)_manager
).GetInstance (name
);
238 Type IDesignerSerializationManager
.GetType (string name
)
240 return ((IDesignerSerializationManager
)_manager
).GetType (name
);
243 object IDesignerSerializationManager
.GetSerializer (Type type
, Type serializerType
)
245 return ((IDesignerSerializationManager
)_manager
).GetSerializer (type
, serializerType
);
248 string IDesignerSerializationManager
.GetName (object instance
)
250 return ((IDesignerSerializationManager
)_manager
).GetName (instance
);
253 void IDesignerSerializationManager
.SetName (object instance
, string name
)
255 ((IDesignerSerializationManager
)_manager
).SetName (instance
, name
);
258 void IDesignerSerializationManager
.ReportError (object error
)
260 ((IDesignerSerializationManager
)_manager
).ReportError (error
);
263 ContextStack IDesignerSerializationManager
.Context
{
264 get { return ((IDesignerSerializationManager)_manager).Context; }
267 PropertyDescriptorCollection IDesignerSerializationManager
.Properties
{
268 get { return ((IDesignerSerializationManager)_manager).Properties; }
271 event EventHandler IDesignerSerializationManager
.SerializationComplete
{
272 add { ((IDesignerSerializationManager)_manager).SerializationComplete += value; }
273 remove { ((IDesignerSerializationManager)_manager).SerializationComplete -= value; }
276 event ResolveNameEventHandler IDesignerSerializationManager
.ResolveName
{
277 add { ((IDesignerSerializationManager)_manager).ResolveName += value; }
278 remove { ((IDesignerSerializationManager)_manager).ResolveName -= value; }
281 } // InstanceRedirectorDesignerSerializationManager
283 private bool _closed
;
284 private Dictionary
<string, ObjectEntry
> _objects
;
285 private IServiceProvider _provider
;
286 private ICollection _errors
;
288 internal CodeDomSerializationStore () : this (null)
292 internal CodeDomSerializationStore (IServiceProvider provider
)
294 _provider
= provider
;
297 private CodeDomSerializationStore (SerializationInfo info
, StreamingContext context
)
299 _objects
= (Dictionary
<string, ObjectEntry
>) info
.GetValue ("objects", typeof (Dictionary
<string, ObjectEntry
>));
300 _closed
= (bool) info
.GetValue ("closed", typeof (bool));
303 void ISerializable
.GetObjectData (SerializationInfo info
, StreamingContext context
)
305 info
.AddValue ("objects", _objects
);
306 info
.AddValue ("closed", _closed
);
309 public override void Close ()
312 Serialize (_provider
);
317 internal static CodeDomSerializationStore
Load (Stream stream
)
319 return new BinaryFormatter ().Deserialize (stream
) as CodeDomSerializationStore
;
322 public override void Save (Stream stream
)
325 new BinaryFormatter ().Serialize (stream
, this);
328 private void Serialize (IServiceProvider provider
)
330 if (provider
== null || _objects
== null)
333 // Use a new serialization manager to prevent from "deadlocking" the surface one
334 // by trying to create new session when one currently exists
336 InstanceRedirectorDesignerSerializationManager manager
=
337 new InstanceRedirectorDesignerSerializationManager (provider
, null, false);
338 ((IDesignerSerializationManager
)manager
).AddSerializationProvider (CodeDomSerializationProvider
.Instance
);
339 IDisposable session
= manager
.CreateSession ();
340 foreach (ObjectEntry objectEntry
in _objects
.Values
) {
341 if (objectEntry
.IsEntireObject
) {
342 CodeDomSerializer serializer
= (CodeDomSerializer
) ((IDesignerSerializationManager
)manager
).GetSerializer (objectEntry
.Type
,
343 typeof (CodeDomSerializer
));
344 if (serializer
!= null) {
345 object serialized
= null;
346 if (objectEntry
.Absolute
)
347 serialized
= serializer
.SerializeAbsolute (manager
,
348 objectEntry
.Instance
);
350 serialized
= serializer
.Serialize (manager
, objectEntry
.Instance
);
351 objectEntry
.Serialized
= serialized
;
354 foreach (MemberEntry memberEntry
in objectEntry
.Members
.Values
) {
355 CodeDomSerializer serializer
= (CodeDomSerializer
) ((IDesignerSerializationManager
)manager
).GetSerializer (
356 objectEntry
.Type
, typeof (CodeDomSerializer
));
357 if (serializer
!= null) {
358 object serialized
= null;
359 if (memberEntry
.Absolute
) {
360 serialized
= serializer
.SerializeMemberAbsolute (manager
,
361 objectEntry
.Instance
,
362 memberEntry
.Descriptor
);
364 serialized
= serializer
.SerializeMember (manager
,
365 objectEntry
.Instance
,
366 memberEntry
.Descriptor
);
368 memberEntry
.Serialized
= serialized
;
373 _errors
= manager
.Errors
;
377 internal void AddObject (object instance
, bool absolute
)
380 throw new InvalidOperationException ("store is closed");
382 if (_objects
== null)
383 _objects
= new Dictionary
<string, ObjectEntry
> ();
384 string objectName
= GetName (instance
);
386 if (!_objects
.ContainsKey (objectName
)) {
387 ObjectEntry objectEntry
= new ObjectEntry (instance
, objectName
);
388 objectEntry
.Absolute
= absolute
;
389 objectEntry
.IsEntireObject
= true;
390 _objects
[objectName
] = objectEntry
;
394 internal void AddMember (object owner
, MemberDescriptor member
, bool absolute
)
397 throw new InvalidOperationException ("store is closed");
399 throw new ArgumentNullException ("member");
401 throw new ArgumentNullException ("owner");
403 if (_objects
== null)
404 _objects
= new Dictionary
<string, ObjectEntry
> ();
406 string objectName
= GetName (owner
);
407 if (!_objects
.ContainsKey (objectName
))
408 _objects
.Add (objectName
, new ObjectEntry (owner
, objectName
));
409 MemberEntry memberEntry
= new MemberEntry (member
);
410 memberEntry
.Absolute
= absolute
;
411 _objects
[objectName
].Members
[member
.Name
] = memberEntry
;
414 private string GetName (object value)
417 throw new ArgumentNullException ("value");
420 IComponent component
= value as IComponent
;
421 if (component
!= null && component
.Site
!= null) {
422 if (component
.Site
is INestedSite
)
423 name
= ((INestedSite
)component
.Site
).FullName
;
425 name
= component
.Site
!= null ? component
.Site
.Name
: null;
426 } else if (value is MemberDescriptor
) {
427 name
= ((MemberDescriptor
) value).Name
;
429 name
= value.GetHashCode ().ToString ();
435 internal ICollection
Deserialize (IServiceProvider provider
, IContainer container
,
436 bool validateRecycledTypes
, bool applyDefaults
)
438 List
<object> objectInstances
= new List
<object> ();
440 if (provider
== null || _objects
== null)
441 return objectInstances
;
442 _provider
= provider
;
444 // Use a new serialization manager to prevent from "deadlocking" the surface one
445 // by trying to create new session when one currently exists
447 InstanceRedirectorDesignerSerializationManager manager
=
448 new InstanceRedirectorDesignerSerializationManager (provider
, container
, validateRecycledTypes
);
449 ((IDesignerSerializationManager
)manager
).AddSerializationProvider (CodeDomSerializationProvider
.Instance
);
450 IDisposable session
= manager
.CreateSession ();
451 foreach (ObjectEntry entry
in _objects
.Values
)
452 objectInstances
.Add (DeserializeEntry (manager
, entry
));
453 _errors
= manager
.Errors
;
455 return objectInstances
;
458 private object DeserializeEntry (IDesignerSerializationManager manager
, ObjectEntry objectEntry
)
460 object deserialized
= null;
462 if (objectEntry
.IsEntireObject
) {
463 CodeDomSerializer serializer
= (CodeDomSerializer
) manager
.GetSerializer (objectEntry
.Type
,
464 typeof (CodeDomSerializer
));
465 if (serializer
!= null) {
466 deserialized
= serializer
.Deserialize (manager
, objectEntry
.Serialized
);
467 // check if the name of the object has changed
468 // (if it e.g clashes with another name)
469 string newName
= manager
.GetName (deserialized
);
470 if (newName
!= objectEntry
.Name
)
471 objectEntry
.Name
= newName
;
474 foreach (MemberEntry memberEntry
in objectEntry
.Members
.Values
) {
475 CodeDomSerializer serializer
= (CodeDomSerializer
) manager
.GetSerializer (objectEntry
.Type
,
476 typeof (CodeDomSerializer
));
477 if (serializer
!= null)
478 serializer
.Deserialize (manager
, memberEntry
.Serialized
);
485 public override ICollection Errors
{
488 _errors
= new object[0];
492 } // CodeDomSerializationStore
494 private IServiceProvider _provider
;
496 public CodeDomComponentSerializationService () : this (null)
500 public CodeDomComponentSerializationService (IServiceProvider provider
)
502 _provider
= provider
;
505 public override SerializationStore
CreateStore ()
507 return new CodeDomSerializationStore (_provider
);
510 public override SerializationStore
LoadStore (Stream stream
)
512 return CodeDomSerializationStore
.Load (stream
);
515 public override ICollection
Deserialize (SerializationStore store
)
517 return this.Deserialize (store
, null);
520 public override ICollection
Deserialize (SerializationStore store
, IContainer container
)
522 return DeserializeCore (store
, container
, true, true);
525 public override void DeserializeTo (SerializationStore store
, IContainer container
, bool validateRecycledTypes
, bool applyDefaults
)
527 DeserializeCore (store
, container
, validateRecycledTypes
, applyDefaults
);
530 private ICollection
DeserializeCore (SerializationStore store
, IContainer container
, bool validateRecycledTypes
,
533 CodeDomSerializationStore codeDomStore
= store
as CodeDomSerializationStore
;
534 if (codeDomStore
== null)
535 throw new InvalidOperationException ("store type unsupported");
536 return codeDomStore
.Deserialize (_provider
, container
, validateRecycledTypes
, applyDefaults
);
539 public override void Serialize (SerializationStore store
, object value)
541 SerializeCore (store
, value, false);
544 public override void SerializeAbsolute (SerializationStore store
, object value)
546 SerializeCore (store
, value, true);
549 public override void SerializeMember (SerializationStore store
, object owningObject
, MemberDescriptor member
)
551 SerializeMemberCore (store
, owningObject
, member
, false);
554 public override void SerializeMemberAbsolute (SerializationStore store
, object owningObject
, MemberDescriptor member
)
556 SerializeMemberCore (store
, owningObject
, member
, true);
559 private void SerializeCore (SerializationStore store
, object value, bool absolute
)
562 throw new ArgumentNullException ("value");
564 throw new ArgumentNullException ("store");
566 CodeDomSerializationStore codeDomStore
= store
as CodeDomSerializationStore
;
568 throw new InvalidOperationException ("store type unsupported");
570 codeDomStore
.AddObject (value, absolute
);
573 private void SerializeMemberCore (SerializationStore store
, object owningObject
, MemberDescriptor member
, bool absolute
)
576 throw new ArgumentNullException ("member");
577 if (owningObject
== null)
578 throw new ArgumentNullException ("owningObject");
580 throw new ArgumentNullException ("store");
582 CodeDomSerializationStore codeDomStore
= store
as CodeDomSerializationStore
;
583 if (codeDomStore
== null)
584 throw new InvalidOperationException ("store type unsupported");
585 codeDomStore
.AddMember (owningObject
, member
, absolute
);