e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
310 lines
13 KiB
C#
310 lines
13 KiB
C#
namespace System.Workflow.ComponentModel.Serialization
|
|
{
|
|
using System;
|
|
using System.CodeDom;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.Design;
|
|
using System.ComponentModel.Design.Serialization;
|
|
using System.Collections;
|
|
using System.Resources;
|
|
using System.Workflow.ComponentModel.Design;
|
|
using System.Collections.Generic;
|
|
using Microsoft.CSharp;
|
|
using System.Workflow.ComponentModel;
|
|
using System.Workflow.ComponentModel.Compiler;
|
|
using System.CodeDom.Compiler;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Diagnostics;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
#region Class ActivityCodeDomSerializationManager
|
|
/// <summary>
|
|
/// Serialization manager class for code only serialization which inherits from
|
|
/// WorkflowMarkupSerializationManager and overrides the GetService method to return the
|
|
/// code-only specific reference service.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Due to the fact that the base classes used by the code-only serializer from
|
|
/// System.Design rely on the reference service to generate code variable ids, we
|
|
/// need to supply our own version of the reference service, since the default
|
|
/// generates invalid variable ids for Activity based classes.
|
|
/// </remarks>
|
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
|
public class ActivityCodeDomSerializationManager : IDesignerSerializationManager
|
|
{
|
|
private ServiceContainer serviceContainer = null;
|
|
private IDesignerSerializationManager serializationManager;
|
|
private ResolveNameEventHandler resolveNameEventHandler;
|
|
private EventHandler serializationCompleteEventHandler;
|
|
|
|
public ActivityCodeDomSerializationManager(IDesignerSerializationManager manager)
|
|
{
|
|
if (manager == null)
|
|
throw new ArgumentNullException("manager");
|
|
|
|
this.serializationManager = manager;
|
|
this.serviceContainer = new ServiceContainer();
|
|
this.serializationManager.ResolveName += new ResolveNameEventHandler(OnResolveName);
|
|
this.serializationManager.SerializationComplete += new EventHandler(OnSerializationComplete);
|
|
if (this.serializationManager is DesignerSerializationManager)
|
|
((DesignerSerializationManager)this.serializationManager).SessionDisposed += new EventHandler(OnSessionDisposed);
|
|
}
|
|
void OnResolveName(object sender, ResolveNameEventArgs e)
|
|
{
|
|
if (this.resolveNameEventHandler != null)
|
|
this.resolveNameEventHandler(this, e);
|
|
}
|
|
|
|
void OnSerializationComplete(object sender, EventArgs e)
|
|
{
|
|
if (this.serializationCompleteEventHandler != null)
|
|
this.serializationCompleteEventHandler(this, e);
|
|
}
|
|
void OnSessionDisposed(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (this.serializationCompleteEventHandler != null)
|
|
this.serializationCompleteEventHandler(this, EventArgs.Empty);
|
|
}
|
|
finally
|
|
{
|
|
this.resolveNameEventHandler = null;
|
|
this.serializationCompleteEventHandler = null;
|
|
}
|
|
}
|
|
public event System.EventHandler SerializationComplete
|
|
{
|
|
add
|
|
{
|
|
this.serializationCompleteEventHandler += value;
|
|
}
|
|
remove
|
|
{
|
|
this.serializationCompleteEventHandler -= value;
|
|
}
|
|
}
|
|
|
|
public void SetName(object instance, string name)
|
|
{
|
|
// Need to check this since code dom deserialization tries to
|
|
// set name twice on all object creation statements.
|
|
if (GetInstance(name) != instance)
|
|
this.serializationManager.SetName(instance, name);
|
|
}
|
|
|
|
|
|
[SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", MessageId = "System.String.LastIndexOf(System.String)", Justification = "This is not a security threat since it is called only in XAML design time scenarios")]
|
|
public string GetName(object value)
|
|
{
|
|
string name = null;
|
|
Activity a = value as Activity;
|
|
if (a != null)
|
|
{
|
|
if (a.Parent == null)
|
|
{
|
|
name = a.GetValue(WorkflowMarkupSerializer.XClassProperty) as string;
|
|
if (name != null && name.LastIndexOf(".") > 0)
|
|
name = name.Substring(name.LastIndexOf('.') + 1);
|
|
}
|
|
else
|
|
name = a.QualifiedName.Replace('.', '_');
|
|
}
|
|
|
|
if (name == null)
|
|
name = this.serializationManager.GetName(value);
|
|
|
|
return name;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Overridded to force siteing of all Activity based instances created, enabling
|
|
/// code-only programmers to write activity.Activities.Add(new activityType());
|
|
/// </summary>
|
|
public object CreateInstance(Type type, ICollection arguments, string name, bool addToContainer)
|
|
{
|
|
return this.serializationManager.CreateInstance(type, arguments, name, false);
|
|
}
|
|
|
|
public object GetService(Type serviceType)
|
|
{
|
|
object service = null;
|
|
|
|
if (serviceType == typeof(IReferenceService))
|
|
service = new ActivityCodeDomReferenceService(this.serializationManager.GetService(serviceType) as IReferenceService);
|
|
|
|
if (serviceType == typeof(IServiceContainer))
|
|
{
|
|
service = serializationManager.GetService(serviceType);
|
|
|
|
if (service == null)
|
|
{
|
|
service = serviceContainer;
|
|
}
|
|
}
|
|
|
|
// If we haven't provded the service, try the serialization manager we wrap
|
|
if (service == null)
|
|
service = this.serializationManager.GetService(serviceType);
|
|
|
|
// Last ditch effort, see if our consumer had added the service
|
|
if (service == null)
|
|
service = serviceContainer.GetService(serviceType);
|
|
|
|
return service;
|
|
}
|
|
|
|
// work around : PD7's PrimitiveCodeDomSerializer does not handle well strings bigger than 200 characters,
|
|
// we push our own version to fix it.
|
|
public object GetSerializer(Type objectType, Type serializerType)
|
|
{
|
|
if (objectType == typeof(string))
|
|
{
|
|
return PrimitiveCodeDomSerializer.Default;
|
|
}
|
|
else if (objectType != null && TypeProvider.IsAssignable(typeof(ICollection<String>), objectType) && !objectType.IsArray && serializerType == typeof(CodeDomSerializer))
|
|
{
|
|
PropertyDescriptor pd = Context[typeof(PropertyDescriptor)] as PropertyDescriptor;
|
|
if (pd != null)
|
|
{
|
|
if (string.Equals(pd.Name, "SynchronizationHandles", StringComparison.Ordinal) && TypeProvider.IsAssignable(typeof(Activity), pd.ComponentType))
|
|
return new SynchronizationHandlesCodeDomSerializer();
|
|
}
|
|
else
|
|
{
|
|
// If property descriptor is not available, we then look at the expression context.
|
|
ExpressionContext context = Context[typeof(ExpressionContext)] as ExpressionContext;
|
|
if (context != null && context.Expression is CodePropertyReferenceExpression &&
|
|
string.Equals(((CodePropertyReferenceExpression)context.Expression).PropertyName, "SynchronizationHandles", StringComparison.Ordinal))
|
|
return new SynchronizationHandlesCodeDomSerializer();
|
|
}
|
|
}
|
|
|
|
object serializer = this.serializationManager.GetSerializer(objectType, serializerType);
|
|
if (!UseUserDefinedSerializer(objectType, serializerType))
|
|
serializer = new SerializableTypeCodeDomSerializer(serializer as CodeDomSerializer);
|
|
|
|
return serializer;
|
|
}
|
|
|
|
// We add this custom serializable to handler serializable types so they don't go into the resources
|
|
// as majority of our types will be serializable per WinOE runtime requirements.
|
|
// Note: we will not overwrite any custom serializer behaviors. If the serializer does not come
|
|
// from the Sytem.ComponentModel.dll, we will not overwrite it.
|
|
private bool UseUserDefinedSerializer(Type objectType, Type serializerType)
|
|
{
|
|
if (objectType == null || serializerType == null)
|
|
return true;
|
|
|
|
//If objectType is not serializable or we are not looking for codedomserializer then use user defined serializer
|
|
if (!objectType.IsSerializable || serializerType != typeof(CodeDomSerializer))
|
|
return true;
|
|
|
|
//For primitives always honor user defined serializer
|
|
if (objectType.IsPrimitive || objectType.IsEnum || objectType == typeof(string) || typeof(Activity).IsAssignableFrom(objectType))
|
|
return true;
|
|
|
|
//If user has defined instance descriptor then we always serialize to a create expression so we honor
|
|
//user defined serializer
|
|
TypeConverter converter = TypeDescriptor.GetConverter(objectType);
|
|
if (converter != null && converter.CanConvertTo(typeof(InstanceDescriptor)))
|
|
return true;
|
|
|
|
//If the serializer is a custom codedom serializer ie it does not come from our or system assembly
|
|
//defining codedomserializer then always honor user's serializer as user needs a way to override the
|
|
//serializartion process
|
|
object serializer = this.serializationManager.GetSerializer(objectType, serializerType);
|
|
if (serializer.GetType().Assembly != typeof(CodeDomSerializer).Assembly &&
|
|
serializer.GetType().Assembly != Assembly.GetExecutingAssembly() &&
|
|
serializer.GetType().Assembly != Assembly.Load(AssemblyRef.ActivitiesAssemblyRef))
|
|
return true;
|
|
|
|
//Special case for UI objects they need to always come from the resource only if we are not compiling
|
|
Activity activity = this.serializationManager.Context[typeof(Activity)] as Activity;
|
|
if (activity != null && activity.Site != null && activity.Site.Container != null &&
|
|
objectType.Namespace != null && objectType.Namespace.Equals(typeof(System.Drawing.Image).Namespace))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
public object GetInstance(string name)
|
|
{
|
|
return this.serializationManager.GetInstance(name);
|
|
}
|
|
|
|
public void AddSerializationProvider(IDesignerSerializationProvider provider)
|
|
{
|
|
this.serializationManager.AddSerializationProvider(provider);
|
|
}
|
|
|
|
public void RemoveSerializationProvider(IDesignerSerializationProvider provider)
|
|
{
|
|
this.serializationManager.RemoveSerializationProvider(provider);
|
|
}
|
|
|
|
public void ReportError(object errorInformation)
|
|
{
|
|
this.serializationManager.ReportError(errorInformation);
|
|
}
|
|
public ContextStack Context
|
|
{
|
|
get
|
|
{
|
|
return this.serializationManager.Context;
|
|
}
|
|
}
|
|
|
|
public event ResolveNameEventHandler ResolveName
|
|
{
|
|
add
|
|
{
|
|
this.resolveNameEventHandler += value;
|
|
}
|
|
remove
|
|
{
|
|
this.resolveNameEventHandler -= value;
|
|
}
|
|
}
|
|
|
|
public PropertyDescriptorCollection Properties
|
|
{
|
|
get
|
|
{
|
|
return this.serializationManager.Properties;
|
|
}
|
|
}
|
|
|
|
|
|
public Type GetType(string typeName)
|
|
{
|
|
Type type = this.serializationManager.GetType(typeName);
|
|
if (type == null)
|
|
{
|
|
// if this is a design time time
|
|
ITypeProvider typeProvider = this.GetService(typeof(ITypeProvider)) as ITypeProvider;
|
|
if (typeProvider != null)
|
|
type = typeProvider.GetType(typeName);
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
protected IDesignerSerializationManager SerializationManager
|
|
{
|
|
get
|
|
{
|
|
return this.serializationManager;
|
|
}
|
|
|
|
set
|
|
{
|
|
this.serializationManager = value;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
}
|