|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
/*++
Abstract:
This file contains the definition of a Base class that defines
the common functionality required to serialie on type in a
graph of types rooted by some object instance
--*/
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Xml;
using System.IO;
using System.Security;
using System.ComponentModel.Design.Serialization;
using System.Windows.Xps.Packaging;
using System.Windows.Documents;
using System.Windows.Media;
namespace System.Windows.Xps.Serialization
{
/// <summary>
/// Base class defining common functionalities required to
/// serialize one type.
/// </summary>
internal abstract class ReachSerializer :
IDisposable
{
#region Constructor
/// <summary>
/// Constructor for class ReachSerializer
/// </summary>
/// <param name="manager">
/// The serializtion manager, the services of which are
/// used later for the serialization process of the type.
/// </param>
public
ReachSerializer(
PackageSerializationManager manager
)
{
ArgumentNullException.ThrowIfNull(manager);
_serializationManager = manager;
_xmlWriter = null;
}
/// <summary>
/// Constructor for class ReachSerializer
/// </summary>
internal
ReachSerializer(
)
{
_serializationManager = null;
_xmlWriter = null;
}
#endregion Constructor
#region Public Methods
/// <summary>
/// The main method that is called to serialize the object of
/// that given type.
/// </summary>
/// <param name="serializedObject">
/// Instance of object to be serialized.
/// </param>
public
virtual
void
SerializeObject(
Object serializedObject
)
{
ArgumentNullException.ThrowIfNull(serializedObject);
if (SerializationManager == null)
{
throw new XpsSerializationException(SR.ReachSerialization_MustHaveSerializationManager);
}
//
// At this stage discover the graph of properties of the object that
// need to be serialized
//
SerializableObjectContext serializableObjectContext = DiscoverObjectData(serializedObject,
null);
if(serializableObjectContext!=null)
{
//
// Push the object at hand on the context stack
//
SerializationManager.GraphContextStack.Push(serializableObjectContext);
//
// At this stage we should start streaming the markup representing the
// object graph to the corresponding destination
//
PersistObjectData(serializableObjectContext);
//
// Pop the object from the context stack
//
SerializationManager.GraphContextStack.Pop();
//
// Recycle the used SerializableObjectContext
//
SerializableObjectContext.RecycleContext(serializableObjectContext);
}
}
#endregion Public Methods
#region Internal Methods
/// <summary>
/// The main method that is called to serialize the object of
/// that given type and that is usually called from within the
/// serialization manager when a node in the graph of objects is
/// at a turn where it should be serialized.
/// </summary>
/// <param name="serializedProperty">
/// The context of the property being serialized at this time and
/// it points internally to the object encapsulated by that node.
/// </param>
internal
virtual
void
SerializeObject(
SerializablePropertyContext serializedProperty
)
{
ArgumentNullException.ThrowIfNull(serializedProperty);
if (SerializationManager == null)
{
throw new XpsSerializationException(SR.ReachSerialization_MustHaveSerializationManager);
}
//
// At this stage discover the graph of properties of the object that
// need to be serialized
//
SerializableObjectContext serializableObjectContext = DiscoverObjectData(serializedProperty.Value,
serializedProperty);
if(serializableObjectContext!=null)
{
//
// Push the object at hand on the context stack
//
SerializationManager.GraphContextStack.Push(serializableObjectContext);
//
// At this stage we should start streaming the markup representing the
// object graph to the corresponding destination
//
PersistObjectData(serializableObjectContext);
//
// Pop the object from the context stack
//
SerializationManager.GraphContextStack.Pop();
//
// Recycle the used SerializableObjectContext
//
SerializableObjectContext.RecycleContext(serializableObjectContext);
}
}
/// <summary>
/// The method is called once the object data is discovered at that
/// point of the serialization process.
/// </summary>
/// <param name="serializableObjectContext">
/// The context of the object to be serialized at this time.
/// </param>
internal
abstract
void
PersistObjectData(
SerializableObjectContext serializableObjectContext
);
/// <summary>
/// Serialize the properties within the object
/// context into METRO
/// </summary>
/// <remarks>
/// Method follows these steps
/// 1. Serializes the instance as string content
/// if is not meant to be a complex value. Else ...
/// 2. Serialize Properties as attributes
/// 3. Serialize Complex Properties as separate parts
/// through calling separate serializers
/// Also this is the virtual to override custom attributes or
/// contents need to be serialized
/// </remarks>
/// <param name="serializableObjectContext">
/// The context of the object to be serialized at this time.
/// </param>
internal
virtual
void
SerializeObjectCore(
SerializableObjectContext serializableObjectContext
)
{
ArgumentNullException.ThrowIfNull(serializableObjectContext);
if (!serializableObjectContext.IsReadOnlyValue &&
serializableObjectContext.IsComplexValue)
{
SerializeProperties(serializableObjectContext);
}
}
/// <summary>
/// This method is the one that writes out the attribute within
/// the xml stream when serializing simple properites.
/// </summary>
/// <param name="serializablePropertyContext">
/// The property that is to be serialized as an attribute at this time.
/// </param>
internal
virtual
void
WriteSerializedAttribute(
SerializablePropertyContext serializablePropertyContext
)
{
ArgumentNullException.ThrowIfNull(serializablePropertyContext);
}
#endregion Internal Methods
#region Private Methods
/// <summary>
/// This method is the one that parses down the object at hand
/// to discover all the properties that are expected to be serialized
/// at that object level.
/// the xml stream when serializing simple properties.
/// </summary>
/// <param name="serializedObject">
/// The instance of the object being serialized.
/// </param>
/// <param name="serializedProperty">
/// The instance of property on the parent object from which this
/// object stemmed. This could be null if this is the node object
/// or the object has no parent.
/// </param>
private
SerializableObjectContext
DiscoverObjectData(
Object serializedObject,
SerializablePropertyContext serializedProperty
)
{
//
// Trying to figure out the parent of this node, which is at this stage
// the same node previously pushed on the stack or in other words it is
// the node that is currently on the top of the stack
//
SerializableObjectContext
serializableObjectParentContext = (SerializableObjectContext)SerializationManager.
GraphContextStack[typeof(SerializableObjectContext)];
//
// Create the context for the current object
//
SerializableObjectContext serializableObjectContext =
SerializableObjectContext.CreateContext(SerializationManager,
serializedObject,
serializableObjectParentContext,
serializedProperty);
//
// Set the root object to be serialized at the level of the SerializationManager
//
if(SerializationManager.RootSerializableObjectContext == null)
{
SerializationManager.RootSerializableObjectContext = serializableObjectContext;
}
return serializableObjectContext;
}
/// <summary>
/// Trigger all properties serialization
/// </summary>
private
void
SerializeProperties(
SerializableObjectContext serializableObjectContext
)
{
ArgumentNullException.ThrowIfNull(serializableObjectContext);
SerializablePropertyCollection propertyCollection = serializableObjectContext.PropertiesCollection;
if(propertyCollection!=null)
{
for(propertyCollection.Reset();
propertyCollection.MoveNext();)
{
SerializablePropertyContext serializablePropertyContext =
(SerializablePropertyContext)propertyCollection.Current;
if(serializablePropertyContext!=null)
{
SerializeProperty(serializablePropertyContext);
}
}
}
}
/// <summary>
/// Trigger serializing one property at a time.
/// </summary>
private
void
SerializeProperty(
SerializablePropertyContext serializablePropertyContext
)
{
ArgumentNullException.ThrowIfNull(serializablePropertyContext);
if (!serializablePropertyContext.IsComplex)
{
//
// Non-Complex Properties are serialized as attributes
//
WriteSerializedAttribute(serializablePropertyContext);
}
else
{
//
// Complex properties could be treated in different ways
// based on their type. Examples of that are:
//
//
//
ReachSerializer serializer = SerializationManager.GetSerializer(serializablePropertyContext.Value);
// If there is no serializer for this type, we won't serialize this property
if(serializer!=null)
{
serializer.SerializeObject(serializablePropertyContext);
}
}
}
#endregion Private Methods
#region Public Properties
/// <summary>
/// Query / Set Xml Writer for the equivelan part
/// </summary>
public
virtual
XmlWriter
XmlWriter
{
get
{
return _xmlWriter;
}
set
{
_xmlWriter = value;
}
}
/// <summary>
/// Query the SerializationManager used by this serializer.
/// </summary>
public
virtual
PackageSerializationManager
SerializationManager
{
get
{
return _serializationManager;
}
}
#endregion Public Properties
#region IDisposable implementation
void
IDisposable.Dispose()
{
GC.SuppressFinalize(this);
}
#endregion IDisposable implementation
#region Private Data members
private
PackageSerializationManager _serializationManager;
private
XmlWriter _xmlWriter;
#endregion Private Data members
};
}
|