Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WF / RunTime / WorkflowDefinitionDispenser.cs / 1407647 / WorkflowDefinitionDispenser.cs
#region Imports using System; using System.ComponentModel; using System.ComponentModel.Design; using System.ComponentModel.Design.Serialization; using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Collections.ObjectModel; using System.Configuration; using System.Reflection; using System.Threading; using System.Globalization; using System.IO; using System.Xml; using System.Text; using System.Workflow.Runtime.Hosting; using System.Workflow.Runtime.Configuration; using System.Workflow.ComponentModel; using System.Workflow.Runtime.Tracking; using System.Workflow.ComponentModel.Compiler; using System.Workflow.ComponentModel.Serialization; using System.Security.Cryptography; using System.Workflow.ComponentModel.Design; #endregion namespace System.Workflow.Runtime { internal sealed class WorkflowDefinitionDispenser : IDisposable { private MruCache workflowTypes; private MruCache xomlFragments; private Dictionary> workflowOutParameters; private WorkflowRuntime workflowRuntime; private bool validateOnCreate = true; internal static DependencyProperty WorkflowDefinitionHashCodeProperty = DependencyProperty.RegisterAttached("WorkflowDefinitionHashCode", typeof(byte[]), typeof(WorkflowDefinitionDispenser)); internal event EventHandler WorkflowDefinitionLoaded; private ReaderWriterLock parametersLock; internal WorkflowDefinitionDispenser(WorkflowRuntime runtime, bool validateOnCreate, int capacity) { if (capacity <= 0) { capacity = 2000; } this.workflowRuntime = runtime; this.workflowTypes = new MruCache(capacity, this, CacheType.Type); this.xomlFragments = new MruCache(capacity, this, CacheType.Xoml); this.workflowOutParameters = new Dictionary >(); this.parametersLock = new ReaderWriterLock(); this.validateOnCreate = validateOnCreate; } internal ReadOnlyCollection GetOutputParameters(Activity rootActivity) { Type workflowType = rootActivity.GetType(); this.parametersLock.AcquireReaderLock(-1); try { if (this.workflowOutParameters.ContainsKey(workflowType)) return new ReadOnlyCollection (this.workflowOutParameters[workflowType]); } finally { this.parametersLock.ReleaseLock(); } // We will recurse at most once because CacheOutputParameters() will perform negative caching. CacheOutputParameters(rootActivity); return GetOutputParameters(rootActivity); } internal void GetWorkflowTypes(out ReadOnlyCollection keys, out ReadOnlyCollection values) { this.workflowTypes.GetWorkflowDefinitions (out keys, out values); } internal void GetWorkflowDefinitions(out ReadOnlyCollection keys, out ReadOnlyCollection values) { this.xomlFragments.GetWorkflowDefinitions (out keys, out values); } internal Activity GetWorkflowDefinition(byte[] xomlHashCode) { Activity workflowDefinition = null; if (xomlHashCode == null) throw new ArgumentNullException("xomlHashCode"); workflowDefinition = xomlFragments.GetDefinition(xomlHashCode); if(workflowDefinition == null) throw new ArgumentException("xomlHashCode"); return workflowDefinition; } internal Activity GetWorkflowDefinition(Type workflowType) { if (workflowType == null) throw new ArgumentNullException("workflowType"); return this.GetRootActivity(workflowType, false, true); } internal Activity GetRootActivity(Type workflowType, bool createNew, bool initForRuntime) { Activity root = null; if (createNew) return LoadRootActivity(workflowType, false, initForRuntime); bool exist; root = workflowTypes.GetOrGenerateDefinition(workflowType, null, null, null, initForRuntime, out exist); if (exist) { return root; } // Set the locking object used for cloning the definition // for non-internal use (WorkflowInstance.GetWorkflowDefinition // and WorkflowCompletedEventArgs.WorkflowDefinition) WorkflowDefinitionLock.SetWorkflowDefinitionLockObject(root, new object()); EventHandler localWorkflowDefinitionLoaded = WorkflowDefinitionLoaded; if (localWorkflowDefinitionLoaded != null) localWorkflowDefinitionLoaded(this.workflowRuntime, new WorkflowDefinitionEventArgs(workflowType)); return root; } // This function will create a new root activity definition tree by deserializing the xoml and the rules file. // The last parameter createNew should be true when the caller is asking for a new definition for performing // dynamic updates instead of a cached definition. internal Activity GetRootActivity(string xomlText, string rulesText, bool createNew, bool initForRuntime) { if (string.IsNullOrEmpty(xomlText)) throw new ArgumentNullException("xomlText"); //calculate the "hash". Think 60s! byte[] xomlHashCode = null; MemoryStream xomlBytesStream = new MemoryStream(); using (StreamWriter streamWriter = new StreamWriter(xomlBytesStream)) { streamWriter.Write(xomlText); //consider rules, if they exist if (!string.IsNullOrEmpty(rulesText)) streamWriter.Write(rulesText); streamWriter.Flush(); xomlBytesStream.Position = 0; xomlHashCode = MD5HashHelper.ComputeHash(xomlBytesStream.GetBuffer()); } if (createNew) return LoadRootActivity(xomlText, rulesText, xomlHashCode, false, initForRuntime); bool exist; Activity root = xomlFragments.GetOrGenerateDefinition(null, xomlText, rulesText, xomlHashCode, initForRuntime, out exist); if (exist) { return root; } // Set the locking object used for cloning the definition // for non-internal use (WorkflowInstance.GetWorkflowDefinition // and WorkflowCompletedEventArgs.WorkflowDefinition) WorkflowDefinitionLock.SetWorkflowDefinitionLockObject(root, new object()); EventHandler localWorkflowDefinitionLoaded = WorkflowDefinitionLoaded; if (localWorkflowDefinitionLoaded != null) localWorkflowDefinitionLoaded(this.workflowRuntime, new WorkflowDefinitionEventArgs(xomlHashCode)); return root; } internal void ValidateDefinition(Activity root, bool isNewType, ITypeProvider typeProvider) { if (!this.validateOnCreate) return; ValidationErrorCollection errors = new ValidationErrorCollection(); // For validation purposes, create a type provider in the type case if the // host did not push one. if (typeProvider == null) typeProvider = WorkflowRuntime.CreateTypeProvider(root); // Validate that we are purely XAML. if (!isNewType) { if (!string.IsNullOrEmpty(root.GetValue(WorkflowMarkupSerializer.XClassProperty) as string)) errors.Add(new ValidationError(ExecutionStringManager.XomlWorkflowHasClassName, ErrorNumbers.Error_XomlWorkflowHasClassName)); Queue compositeActivities = new Queue(); compositeActivities.Enqueue(root); while (compositeActivities.Count > 0) { Activity activity = compositeActivities.Dequeue() as Activity; if (activity.GetValue(WorkflowMarkupSerializer.XCodeProperty) != null) errors.Add(new ValidationError(ExecutionStringManager.XomlWorkflowHasCode, ErrorNumbers.Error_XomlWorkflowHasCode)); CompositeActivity compositeActivity = activity as CompositeActivity; if (compositeActivity != null) { foreach (Activity childActivity in compositeActivity.EnabledActivities) compositeActivities.Enqueue(childActivity); } } } ServiceContainer serviceContainer = new ServiceContainer(); serviceContainer.AddService(typeof(ITypeProvider), typeProvider); ValidationManager validationManager = new ValidationManager(serviceContainer); using (WorkflowCompilationContext.CreateScope(validationManager)) { foreach (Validator validator in validationManager.GetValidators(root.GetType())) { foreach (ValidationError error in validator.Validate(validationManager, root)) { if (!error.UserData.Contains(typeof(Activity))) error.UserData[typeof(Activity)] = root; errors.Add(error); } } } if (errors.HasErrors) throw new WorkflowValidationFailedException(ExecutionStringManager.WorkflowValidationFailure, errors); } public void Dispose() { xomlFragments.Dispose(); workflowTypes.Dispose(); } private Activity LoadRootActivity(Type workflowType, bool createDefinition, bool initForRuntime) { WorkflowLoaderService loader = workflowRuntime.GetService (); Activity root = loader.CreateInstance(workflowType); if (root == null) throw new InvalidOperationException(ExecutionStringManager.CannotCreateRootActivity); if (root.GetType() != workflowType) throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.WorkflowTypeMismatch, workflowType.FullName)); if (createDefinition) ValidateDefinition(root, true, workflowRuntime.GetService ()); if (initForRuntime) ((IDependencyObjectAccessor)root).InitializeDefinitionForRuntime(null); root.SetValue(Activity.WorkflowRuntimeProperty, workflowRuntime); return root; } private Activity LoadRootActivity(string xomlText, string rulesText, byte[] xomlHashCode, bool createDefinition, bool initForRuntime) { Activity root = null; WorkflowLoaderService loader = workflowRuntime.GetService (); using (StringReader xomlTextReader = new StringReader(xomlText)) { using (XmlReader xomlReader = XmlReader.Create(xomlTextReader)) { XmlReader rulesReader = null; StringReader rulesTextReader = null; try { if (!string.IsNullOrEmpty(rulesText)) { rulesTextReader = new StringReader(rulesText); rulesReader = XmlReader.Create(rulesTextReader); } root = loader.CreateInstance(xomlReader, rulesReader); } finally { if (rulesReader != null) rulesReader.Close(); if (rulesTextReader != null) rulesTextReader.Close(); } } } if (root == null) throw new InvalidOperationException(ExecutionStringManager.CannotCreateRootActivity); if (createDefinition) { ITypeProvider typeProvider = workflowRuntime.GetService (); ValidateDefinition(root, false, typeProvider); } if (initForRuntime) ((IDependencyObjectAccessor)root).InitializeDefinitionForRuntime(null); // Save the original markup. root.SetValue(Activity.WorkflowXamlMarkupProperty, xomlText); root.SetValue(Activity.WorkflowRulesMarkupProperty, rulesText); root.SetValue(WorkflowDefinitionHashCodeProperty, xomlHashCode); root.SetValue(Activity.WorkflowRuntimeProperty, workflowRuntime); return root; } private void CacheOutputParameters(Activity rootActivity) { Type workflowType = rootActivity.GetType(); List outputParameters = null; this.parametersLock.AcquireWriterLock(-1); try { if (this.workflowOutParameters.ContainsKey(workflowType)) return; // Cache negative and positive cases! outputParameters = new List (); this.workflowOutParameters.Add(workflowType, outputParameters); PropertyInfo[] properties = workflowType.GetProperties(); foreach (PropertyInfo property in properties) { if (!property.CanRead || property.DeclaringType == typeof(DependencyObject) || property.DeclaringType == typeof(Activity) || property.DeclaringType == typeof(CompositeActivity)) continue; bool ignoreProperty = false; foreach (DependencyProperty dependencyProperty in rootActivity.MetaDependencyProperties) { if (dependencyProperty.Name == property.Name && dependencyProperty.DefaultMetadata.IsMetaProperty) { ignoreProperty = true; break; } } if (!ignoreProperty) outputParameters.Add(property); } } finally { Thread.MemoryBarrier(); this.parametersLock.ReleaseLock(); } } private enum CacheType { Type = 0, Xoml = 1, } private class MruCache : IDisposable { Hashtable hashtable; LinkedList mruList; int size; int capacity; WorkflowDefinitionDispenser dispenser; CacheType type; internal MruCache(int capacity, WorkflowDefinitionDispenser dispenser, CacheType type) { if (type == CacheType.Xoml) { this.hashtable = new Hashtable((IEqualityComparer)new DigestComparerWrapper()); } else { this.hashtable = new Hashtable(); } this.mruList = new LinkedList (); this.capacity = capacity; this.dispenser = dispenser; this.type = type; } private void RemoveFromDictionary(Activity activity) { byte[] key = activity.GetValue(WorkflowDefinitionHashCodeProperty) as byte[]; if (key != null) { this.hashtable.Remove(key); } else { Type type = activity.GetType(); this.hashtable.Remove(type); } } private void AddToDictionary(LinkedListNode node) { byte[] key = node.Value.GetValue(WorkflowDefinitionHashCodeProperty) as byte[]; if (key != null) { this.hashtable.Add(key, node); } else { Type type = node.Value.GetType(); this.hashtable.Add(type, node); } } internal Activity GetDefinition(byte[] md5Codes) { LinkedListNode node; node = this.hashtable[md5Codes] as LinkedListNode ; if (node != null) { return node.Value; } else { return null; } } internal Activity GetOrGenerateDefinition(Type type, string xomlText, string rulesText, byte[] md5Codes, bool initForRuntime, out bool exist) { LinkedListNode node; object key; if (type != null) { key = type; } else { key = md5Codes; } try { exist = false; node = this.hashtable[key] as LinkedListNode ; if (node != null) { lock (this.mruList) { node = this.hashtable[key] as LinkedListNode ; if (node != null) { exist = true; this.mruList.Remove(node); this.mruList.AddFirst(node); } else { exist = false; } } } if (!exist) { lock (this.hashtable) { node = this.hashtable[key] as LinkedListNode ; if (node != null) { exist = true; lock (this.mruList) { this.mruList.Remove(node); this.mruList.AddFirst(node); } } else { exist = false; Activity activity; if (type != null) { activity = this.dispenser.LoadRootActivity(type, true, initForRuntime); } else { activity = this.dispenser.LoadRootActivity(xomlText, rulesText, key as byte[], true, initForRuntime); } lock (this.mruList) { if (this.size < this.capacity) { this.size++; } else { RemoveFromDictionary(this.mruList.Last.Value); this.mruList.RemoveLast(); } node = new LinkedListNode (activity); AddToDictionary(node); this.mruList.AddFirst(node); } } } } } finally { Thread.MemoryBarrier(); } return node.Value; } internal void GetWorkflowDefinitions (out ReadOnlyCollection keys, out ReadOnlyCollection values) { lock (this.hashtable) { if (((typeof(K) == typeof(Type)) && (this.type == CacheType.Type)) || ((typeof(K) == typeof(byte[])) && (this.type == CacheType.Xoml))) { List keyList = new List (); foreach (K key in this.hashtable.Keys) { keyList.Add(key); } keys = new ReadOnlyCollection (keyList); List list = new List (); foreach (LinkedListNode node in this.hashtable.Values) { list.Add(node.Value); } values = new ReadOnlyCollection (list); } else { keys = null; values = null; } } } public void Dispose() { foreach (LinkedListNode node in hashtable.Values) { try { node.Value.Dispose(); } catch (Exception)//ignore any dispose exception. { } } } } private class DigestComparerWrapper : IEqualityComparer { IEqualityComparer comparer = (IEqualityComparer )new DigestComparer(); bool IEqualityComparer.Equals(object object1, object object2) { return comparer.Equals((byte[])object1, (byte[])object2); } int IEqualityComparer.GetHashCode(object obj) { return comparer.GetHashCode((byte[]) obj); } } } internal class WorkflowDefinitionLock : IDisposable { internal static readonly DependencyProperty WorkflowDefinitionLockObjectProperty = DependencyProperty.RegisterAttached("WorkflowDefinitionLockObject", typeof(object), typeof(WorkflowDefinitionLock), new PropertyMetadata(DependencyPropertyOptions.NonSerialized)); internal static object GetWorkflowDefinitionLockObject(DependencyObject dependencyObject) { // The Dependency Properties are kept in a Dictionary<>, which is not thread safe between // "getters" and "setters", so lock around the "getter", too. lock (dependencyObject) { return dependencyObject.GetValue(WorkflowDefinitionLockObjectProperty); } } internal static void SetWorkflowDefinitionLockObject(DependencyObject dependencyObject, object value) { lock (dependencyObject) { if (dependencyObject.GetValue(WorkflowDefinitionLockObjectProperty) == null) { dependencyObject.SetValue(WorkflowDefinitionLockObjectProperty, value); } } } private object _syncObj; public WorkflowDefinitionLock(Activity definition) { this._syncObj = GetWorkflowDefinitionLockObject(definition); Debug.Assert(this._syncObj != null, "Definition's synchronization object was null. This should always be set."); #pragma warning disable 0618 //@ Monitor.Enter(this._syncObj); #pragma warning restore 0618 } #region IDisposable Members public void Dispose() { Monitor.Exit(this._syncObj); } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. #region Imports using System; using System.ComponentModel; using System.ComponentModel.Design; using System.ComponentModel.Design.Serialization; using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Collections.ObjectModel; using System.Configuration; using System.Reflection; using System.Threading; using System.Globalization; using System.IO; using System.Xml; using System.Text; using System.Workflow.Runtime.Hosting; using System.Workflow.Runtime.Configuration; using System.Workflow.ComponentModel; using System.Workflow.Runtime.Tracking; using System.Workflow.ComponentModel.Compiler; using System.Workflow.ComponentModel.Serialization; using System.Security.Cryptography; using System.Workflow.ComponentModel.Design; #endregion namespace System.Workflow.Runtime { internal sealed class WorkflowDefinitionDispenser : IDisposable { private MruCache workflowTypes; private MruCache xomlFragments; private Dictionary > workflowOutParameters; private WorkflowRuntime workflowRuntime; private bool validateOnCreate = true; internal static DependencyProperty WorkflowDefinitionHashCodeProperty = DependencyProperty.RegisterAttached("WorkflowDefinitionHashCode", typeof(byte[]), typeof(WorkflowDefinitionDispenser)); internal event EventHandler WorkflowDefinitionLoaded; private ReaderWriterLock parametersLock; internal WorkflowDefinitionDispenser(WorkflowRuntime runtime, bool validateOnCreate, int capacity) { if (capacity <= 0) { capacity = 2000; } this.workflowRuntime = runtime; this.workflowTypes = new MruCache(capacity, this, CacheType.Type); this.xomlFragments = new MruCache(capacity, this, CacheType.Xoml); this.workflowOutParameters = new Dictionary >(); this.parametersLock = new ReaderWriterLock(); this.validateOnCreate = validateOnCreate; } internal ReadOnlyCollection GetOutputParameters(Activity rootActivity) { Type workflowType = rootActivity.GetType(); this.parametersLock.AcquireReaderLock(-1); try { if (this.workflowOutParameters.ContainsKey(workflowType)) return new ReadOnlyCollection (this.workflowOutParameters[workflowType]); } finally { this.parametersLock.ReleaseLock(); } // We will recurse at most once because CacheOutputParameters() will perform negative caching. CacheOutputParameters(rootActivity); return GetOutputParameters(rootActivity); } internal void GetWorkflowTypes(out ReadOnlyCollection keys, out ReadOnlyCollection values) { this.workflowTypes.GetWorkflowDefinitions (out keys, out values); } internal void GetWorkflowDefinitions(out ReadOnlyCollection keys, out ReadOnlyCollection values) { this.xomlFragments.GetWorkflowDefinitions (out keys, out values); } internal Activity GetWorkflowDefinition(byte[] xomlHashCode) { Activity workflowDefinition = null; if (xomlHashCode == null) throw new ArgumentNullException("xomlHashCode"); workflowDefinition = xomlFragments.GetDefinition(xomlHashCode); if(workflowDefinition == null) throw new ArgumentException("xomlHashCode"); return workflowDefinition; } internal Activity GetWorkflowDefinition(Type workflowType) { if (workflowType == null) throw new ArgumentNullException("workflowType"); return this.GetRootActivity(workflowType, false, true); } internal Activity GetRootActivity(Type workflowType, bool createNew, bool initForRuntime) { Activity root = null; if (createNew) return LoadRootActivity(workflowType, false, initForRuntime); bool exist; root = workflowTypes.GetOrGenerateDefinition(workflowType, null, null, null, initForRuntime, out exist); if (exist) { return root; } // Set the locking object used for cloning the definition // for non-internal use (WorkflowInstance.GetWorkflowDefinition // and WorkflowCompletedEventArgs.WorkflowDefinition) WorkflowDefinitionLock.SetWorkflowDefinitionLockObject(root, new object()); EventHandler localWorkflowDefinitionLoaded = WorkflowDefinitionLoaded; if (localWorkflowDefinitionLoaded != null) localWorkflowDefinitionLoaded(this.workflowRuntime, new WorkflowDefinitionEventArgs(workflowType)); return root; } // This function will create a new root activity definition tree by deserializing the xoml and the rules file. // The last parameter createNew should be true when the caller is asking for a new definition for performing // dynamic updates instead of a cached definition. internal Activity GetRootActivity(string xomlText, string rulesText, bool createNew, bool initForRuntime) { if (string.IsNullOrEmpty(xomlText)) throw new ArgumentNullException("xomlText"); //calculate the "hash". Think 60s! byte[] xomlHashCode = null; MemoryStream xomlBytesStream = new MemoryStream(); using (StreamWriter streamWriter = new StreamWriter(xomlBytesStream)) { streamWriter.Write(xomlText); //consider rules, if they exist if (!string.IsNullOrEmpty(rulesText)) streamWriter.Write(rulesText); streamWriter.Flush(); xomlBytesStream.Position = 0; xomlHashCode = MD5HashHelper.ComputeHash(xomlBytesStream.GetBuffer()); } if (createNew) return LoadRootActivity(xomlText, rulesText, xomlHashCode, false, initForRuntime); bool exist; Activity root = xomlFragments.GetOrGenerateDefinition(null, xomlText, rulesText, xomlHashCode, initForRuntime, out exist); if (exist) { return root; } // Set the locking object used for cloning the definition // for non-internal use (WorkflowInstance.GetWorkflowDefinition // and WorkflowCompletedEventArgs.WorkflowDefinition) WorkflowDefinitionLock.SetWorkflowDefinitionLockObject(root, new object()); EventHandler localWorkflowDefinitionLoaded = WorkflowDefinitionLoaded; if (localWorkflowDefinitionLoaded != null) localWorkflowDefinitionLoaded(this.workflowRuntime, new WorkflowDefinitionEventArgs(xomlHashCode)); return root; } internal void ValidateDefinition(Activity root, bool isNewType, ITypeProvider typeProvider) { if (!this.validateOnCreate) return; ValidationErrorCollection errors = new ValidationErrorCollection(); // For validation purposes, create a type provider in the type case if the // host did not push one. if (typeProvider == null) typeProvider = WorkflowRuntime.CreateTypeProvider(root); // Validate that we are purely XAML. if (!isNewType) { if (!string.IsNullOrEmpty(root.GetValue(WorkflowMarkupSerializer.XClassProperty) as string)) errors.Add(new ValidationError(ExecutionStringManager.XomlWorkflowHasClassName, ErrorNumbers.Error_XomlWorkflowHasClassName)); Queue compositeActivities = new Queue(); compositeActivities.Enqueue(root); while (compositeActivities.Count > 0) { Activity activity = compositeActivities.Dequeue() as Activity; if (activity.GetValue(WorkflowMarkupSerializer.XCodeProperty) != null) errors.Add(new ValidationError(ExecutionStringManager.XomlWorkflowHasCode, ErrorNumbers.Error_XomlWorkflowHasCode)); CompositeActivity compositeActivity = activity as CompositeActivity; if (compositeActivity != null) { foreach (Activity childActivity in compositeActivity.EnabledActivities) compositeActivities.Enqueue(childActivity); } } } ServiceContainer serviceContainer = new ServiceContainer(); serviceContainer.AddService(typeof(ITypeProvider), typeProvider); ValidationManager validationManager = new ValidationManager(serviceContainer); using (WorkflowCompilationContext.CreateScope(validationManager)) { foreach (Validator validator in validationManager.GetValidators(root.GetType())) { foreach (ValidationError error in validator.Validate(validationManager, root)) { if (!error.UserData.Contains(typeof(Activity))) error.UserData[typeof(Activity)] = root; errors.Add(error); } } } if (errors.HasErrors) throw new WorkflowValidationFailedException(ExecutionStringManager.WorkflowValidationFailure, errors); } public void Dispose() { xomlFragments.Dispose(); workflowTypes.Dispose(); } private Activity LoadRootActivity(Type workflowType, bool createDefinition, bool initForRuntime) { WorkflowLoaderService loader = workflowRuntime.GetService (); Activity root = loader.CreateInstance(workflowType); if (root == null) throw new InvalidOperationException(ExecutionStringManager.CannotCreateRootActivity); if (root.GetType() != workflowType) throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.WorkflowTypeMismatch, workflowType.FullName)); if (createDefinition) ValidateDefinition(root, true, workflowRuntime.GetService ()); if (initForRuntime) ((IDependencyObjectAccessor)root).InitializeDefinitionForRuntime(null); root.SetValue(Activity.WorkflowRuntimeProperty, workflowRuntime); return root; } private Activity LoadRootActivity(string xomlText, string rulesText, byte[] xomlHashCode, bool createDefinition, bool initForRuntime) { Activity root = null; WorkflowLoaderService loader = workflowRuntime.GetService (); using (StringReader xomlTextReader = new StringReader(xomlText)) { using (XmlReader xomlReader = XmlReader.Create(xomlTextReader)) { XmlReader rulesReader = null; StringReader rulesTextReader = null; try { if (!string.IsNullOrEmpty(rulesText)) { rulesTextReader = new StringReader(rulesText); rulesReader = XmlReader.Create(rulesTextReader); } root = loader.CreateInstance(xomlReader, rulesReader); } finally { if (rulesReader != null) rulesReader.Close(); if (rulesTextReader != null) rulesTextReader.Close(); } } } if (root == null) throw new InvalidOperationException(ExecutionStringManager.CannotCreateRootActivity); if (createDefinition) { ITypeProvider typeProvider = workflowRuntime.GetService (); ValidateDefinition(root, false, typeProvider); } if (initForRuntime) ((IDependencyObjectAccessor)root).InitializeDefinitionForRuntime(null); // Save the original markup. root.SetValue(Activity.WorkflowXamlMarkupProperty, xomlText); root.SetValue(Activity.WorkflowRulesMarkupProperty, rulesText); root.SetValue(WorkflowDefinitionHashCodeProperty, xomlHashCode); root.SetValue(Activity.WorkflowRuntimeProperty, workflowRuntime); return root; } private void CacheOutputParameters(Activity rootActivity) { Type workflowType = rootActivity.GetType(); List outputParameters = null; this.parametersLock.AcquireWriterLock(-1); try { if (this.workflowOutParameters.ContainsKey(workflowType)) return; // Cache negative and positive cases! outputParameters = new List (); this.workflowOutParameters.Add(workflowType, outputParameters); PropertyInfo[] properties = workflowType.GetProperties(); foreach (PropertyInfo property in properties) { if (!property.CanRead || property.DeclaringType == typeof(DependencyObject) || property.DeclaringType == typeof(Activity) || property.DeclaringType == typeof(CompositeActivity)) continue; bool ignoreProperty = false; foreach (DependencyProperty dependencyProperty in rootActivity.MetaDependencyProperties) { if (dependencyProperty.Name == property.Name && dependencyProperty.DefaultMetadata.IsMetaProperty) { ignoreProperty = true; break; } } if (!ignoreProperty) outputParameters.Add(property); } } finally { Thread.MemoryBarrier(); this.parametersLock.ReleaseLock(); } } private enum CacheType { Type = 0, Xoml = 1, } private class MruCache : IDisposable { Hashtable hashtable; LinkedList mruList; int size; int capacity; WorkflowDefinitionDispenser dispenser; CacheType type; internal MruCache(int capacity, WorkflowDefinitionDispenser dispenser, CacheType type) { if (type == CacheType.Xoml) { this.hashtable = new Hashtable((IEqualityComparer)new DigestComparerWrapper()); } else { this.hashtable = new Hashtable(); } this.mruList = new LinkedList (); this.capacity = capacity; this.dispenser = dispenser; this.type = type; } private void RemoveFromDictionary(Activity activity) { byte[] key = activity.GetValue(WorkflowDefinitionHashCodeProperty) as byte[]; if (key != null) { this.hashtable.Remove(key); } else { Type type = activity.GetType(); this.hashtable.Remove(type); } } private void AddToDictionary(LinkedListNode node) { byte[] key = node.Value.GetValue(WorkflowDefinitionHashCodeProperty) as byte[]; if (key != null) { this.hashtable.Add(key, node); } else { Type type = node.Value.GetType(); this.hashtable.Add(type, node); } } internal Activity GetDefinition(byte[] md5Codes) { LinkedListNode node; node = this.hashtable[md5Codes] as LinkedListNode ; if (node != null) { return node.Value; } else { return null; } } internal Activity GetOrGenerateDefinition(Type type, string xomlText, string rulesText, byte[] md5Codes, bool initForRuntime, out bool exist) { LinkedListNode node; object key; if (type != null) { key = type; } else { key = md5Codes; } try { exist = false; node = this.hashtable[key] as LinkedListNode ; if (node != null) { lock (this.mruList) { node = this.hashtable[key] as LinkedListNode ; if (node != null) { exist = true; this.mruList.Remove(node); this.mruList.AddFirst(node); } else { exist = false; } } } if (!exist) { lock (this.hashtable) { node = this.hashtable[key] as LinkedListNode ; if (node != null) { exist = true; lock (this.mruList) { this.mruList.Remove(node); this.mruList.AddFirst(node); } } else { exist = false; Activity activity; if (type != null) { activity = this.dispenser.LoadRootActivity(type, true, initForRuntime); } else { activity = this.dispenser.LoadRootActivity(xomlText, rulesText, key as byte[], true, initForRuntime); } lock (this.mruList) { if (this.size < this.capacity) { this.size++; } else { RemoveFromDictionary(this.mruList.Last.Value); this.mruList.RemoveLast(); } node = new LinkedListNode (activity); AddToDictionary(node); this.mruList.AddFirst(node); } } } } } finally { Thread.MemoryBarrier(); } return node.Value; } internal void GetWorkflowDefinitions (out ReadOnlyCollection keys, out ReadOnlyCollection values) { lock (this.hashtable) { if (((typeof(K) == typeof(Type)) && (this.type == CacheType.Type)) || ((typeof(K) == typeof(byte[])) && (this.type == CacheType.Xoml))) { List keyList = new List (); foreach (K key in this.hashtable.Keys) { keyList.Add(key); } keys = new ReadOnlyCollection (keyList); List list = new List (); foreach (LinkedListNode node in this.hashtable.Values) { list.Add(node.Value); } values = new ReadOnlyCollection (list); } else { keys = null; values = null; } } } public void Dispose() { foreach (LinkedListNode node in hashtable.Values) { try { node.Value.Dispose(); } catch (Exception)//ignore any dispose exception. { } } } } private class DigestComparerWrapper : IEqualityComparer { IEqualityComparer comparer = (IEqualityComparer )new DigestComparer(); bool IEqualityComparer.Equals(object object1, object object2) { return comparer.Equals((byte[])object1, (byte[])object2); } int IEqualityComparer.GetHashCode(object obj) { return comparer.GetHashCode((byte[]) obj); } } } internal class WorkflowDefinitionLock : IDisposable { internal static readonly DependencyProperty WorkflowDefinitionLockObjectProperty = DependencyProperty.RegisterAttached("WorkflowDefinitionLockObject", typeof(object), typeof(WorkflowDefinitionLock), new PropertyMetadata(DependencyPropertyOptions.NonSerialized)); internal static object GetWorkflowDefinitionLockObject(DependencyObject dependencyObject) { // The Dependency Properties are kept in a Dictionary<>, which is not thread safe between // "getters" and "setters", so lock around the "getter", too. lock (dependencyObject) { return dependencyObject.GetValue(WorkflowDefinitionLockObjectProperty); } } internal static void SetWorkflowDefinitionLockObject(DependencyObject dependencyObject, object value) { lock (dependencyObject) { if (dependencyObject.GetValue(WorkflowDefinitionLockObjectProperty) == null) { dependencyObject.SetValue(WorkflowDefinitionLockObjectProperty, value); } } } private object _syncObj; public WorkflowDefinitionLock(Activity definition) { this._syncObj = GetWorkflowDefinitionLockObject(definition); Debug.Assert(this._syncObj != null, "Definition's synchronization object was null. This should always be set."); #pragma warning disable 0618 //@ Monitor.Enter(this._syncObj); #pragma warning restore 0618 } #region IDisposable Members public void Dispose() { Monitor.Exit(this._syncObj); } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- IgnoreFlushAndCloseStream.cs
- Guid.cs
- Itemizer.cs
- TextParagraphCache.cs
- SystemTcpStatistics.cs
- TextBoxBase.cs
- GridSplitterAutomationPeer.cs
- RowVisual.cs
- XmlValueConverter.cs
- SecurityTokenValidationException.cs
- Keywords.cs
- QilChoice.cs
- XmlSchemaAttributeGroup.cs
- WrapperEqualityComparer.cs
- TimelineGroup.cs
- Geometry.cs
- ResourceDescriptionAttribute.cs
- ComAdminInterfaces.cs
- DataControlLinkButton.cs
- ListViewGroup.cs
- PrintDialog.cs
- EndpointDiscoveryElement.cs
- ErrorTableItemStyle.cs
- AppDomainProtocolHandler.cs
- WebSysDescriptionAttribute.cs
- ScriptReferenceBase.cs
- TreeNodeClickEventArgs.cs
- FeatureManager.cs
- ConnectionManagementSection.cs
- LayoutTable.cs
- _Connection.cs
- ConnectionPoint.cs
- ToolStripDesigner.cs
- UpDownBase.cs
- FunctionMappingTranslator.cs
- SingleStorage.cs
- XmlTextReader.cs
- ToolStripItemTextRenderEventArgs.cs
- TimeEnumHelper.cs
- TypeHelper.cs
- TransactionChannelFaultConverter.cs
- CodeSubDirectoriesCollection.cs
- COM2DataTypeToManagedDataTypeConverter.cs
- OdbcConnectionFactory.cs
- ImageBrush.cs
- Rectangle.cs
- DbConnectionStringBuilder.cs
- CultureMapper.cs
- OrderByExpression.cs
- CachedBitmap.cs
- GeneralTransform3DTo2DTo3D.cs
- ControlParser.cs
- Grant.cs
- FontDriver.cs
- XmlSchemaComplexContent.cs
- WinFormsSecurity.cs
- SecurityManager.cs
- XmlSchemaInclude.cs
- ImageField.cs
- CodeExpressionCollection.cs
- BinaryObjectWriter.cs
- DataGridViewCellStyleConverter.cs
- XmlLanguage.cs
- ProcessHostMapPath.cs
- Operators.cs
- TextHidden.cs
- FixedSOMPage.cs
- Propagator.Evaluator.cs
- XmlElementAttribute.cs
- XMLSchema.cs
- InfoCardRSACryptoProvider.cs
- ErrorHandler.cs
- RectangleF.cs
- MeshGeometry3D.cs
- TreeViewBindingsEditorForm.cs
- EntityCommand.cs
- Simplifier.cs
- ButtonFlatAdapter.cs
- WebHttpEndpoint.cs
- webproxy.cs
- ResourceWriter.cs
- SafeNativeMethodsMilCoreApi.cs
- ZipArchive.cs
- IsolatedStorage.cs
- HtmlShim.cs
- EntityDescriptor.cs
- WindowsUpDown.cs
- ProxyWebPart.cs
- ConnectionPoint.cs
- AspNetSynchronizationContext.cs
- WorkflowMarkupSerializerMapping.cs
- DesignTimeTemplateParser.cs
- ClientConvert.cs
- TypefaceMap.cs
- OperatingSystem.cs
- CorrelationValidator.cs
- XmlSchemaSubstitutionGroup.cs
- EventLogInformation.cs
- ToolboxComponentsCreatedEventArgs.cs
- BlockingCollection.cs