Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@@ -0,0 +1,161 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.Activities.DynamicUpdate
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime;
using System.Runtime.Serialization;
[Serializable]
[DataContract]
public class ActivityBlockingUpdate
{
[NonSerialized]
private Activity activity;
string activityInstanceId;
string originalActivityId;
string updatedActivityId;
string reason;
public ActivityBlockingUpdate(Activity activity, string originalActivityId, string reason)
: this(activity, originalActivityId, reason, null)
{
}
public ActivityBlockingUpdate(Activity activity, string originalActivityId, string reason, string activityInstanceId)
{
this.activity = activity;
this.Reason = reason;
this.OriginalActivityId = originalActivityId;
this.ActivityInstanceId = activityInstanceId;
if (activity != null)
{
this.UpdatedActivityId = activity.Id;
}
}
public ActivityBlockingUpdate(string updatedActivityId, string originalActivityId, string reason)
: this(updatedActivityId, originalActivityId, reason, null)
{
}
public ActivityBlockingUpdate(string updatedActivityId, string originalActivityId, string reason, string activityInstanceId)
{
this.UpdatedActivityId = updatedActivityId;
this.OriginalActivityId = originalActivityId;
this.ActivityInstanceId = activityInstanceId;
this.Reason = reason;
}
public Activity Activity
{
get
{
return this.activity;
}
}
public string ActivityInstanceId
{
get
{
return this.activityInstanceId;
}
private set
{
this.activityInstanceId = value;
}
}
public string OriginalActivityId
{
get
{
return this.originalActivityId;
}
private set
{
this.originalActivityId = value;
}
}
public string UpdatedActivityId
{
get
{
return this.updatedActivityId;
}
private set
{
this.updatedActivityId = value;
}
}
public string Reason
{
get
{
return this.reason;
}
private set
{
this.reason = value;
}
}
[DataMember(EmitDefaultValue = false, Name = "ActivityInstanceId")]
internal string SerializedActivityInstanceId
{
get { return this.ActivityInstanceId; }
set { this.ActivityInstanceId = value; }
}
[DataMember(EmitDefaultValue = false, Name = "OriginalActivityId")]
internal string SerializedOriginalActivityId
{
get { return this.OriginalActivityId; }
set { this.OriginalActivityId = value; }
}
[DataMember(EmitDefaultValue = false, Name = "UpdatedActivityId")]
internal string SerializedUpdatedActivityId
{
get { return this.UpdatedActivityId; }
set { this.UpdatedActivityId = value; }
}
[DataMember(EmitDefaultValue = false, Name = "Reason")]
internal string SerializedReason
{
get { return this.Reason; }
set { this.Reason = value; }
}
internal static void AddBlockingActivity(ref Collection<ActivityBlockingUpdate> blockingActivities, Activity activity, string originalActivityId, string reason, string activityInstanceId)
{
if (blockingActivities == null)
{
blockingActivities = new Collection<ActivityBlockingUpdate>();
}
ActivityBlockingUpdate blockingActivity = new ActivityBlockingUpdate(activity, originalActivityId, reason, activityInstanceId);
blockingActivities.Add(blockingActivity);
}
internal static void AddBlockingActivity(ref Collection<ActivityBlockingUpdate> blockingActivities, string updatedActivityId, string originalActivityId, string reason, string activityInstanceId)
{
if (blockingActivities == null)
{
blockingActivities = new Collection<ActivityBlockingUpdate>();
}
ActivityBlockingUpdate blockingActivity = new ActivityBlockingUpdate(updatedActivityId, originalActivityId, reason, activityInstanceId);
blockingActivities.Add(blockingActivity);
}
}
}

View File

@@ -0,0 +1,331 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.Activities.DynamicUpdate
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime;
using System.Runtime.Serialization;
using System.Text;
[DataContract]
internal class ArgumentInfo
{
// the following two fields are never to be serialized.
private Type type;
private bool HasGetTypeBeenAttempted;
string versionlessAssemblyQualifiedTypeName;
string name;
string fullAssemblyQualifiedTypeName;
ArgumentDirection direction;
public ArgumentInfo(RuntimeArgument argument)
{
this.Name = argument.Name;
Fx.Assert(argument.Type != null, "argument Type must not be null.");
this.Type = argument.Type;
this.HasGetTypeBeenAttempted = true;
this.FullAssemblyQualifiedTypeName = this.Type.AssemblyQualifiedName;
// this versionless assembly-qualified type name causes types of different versions
// to be considered equal for the sake of argument matching.
// Serializing the argument type info in a string format allows
// the map to be loaded into environment in which the types may not be available.
this.versionlessAssemblyQualifiedTypeName = GenerateVersionlessAssemblyQualifiedTypeName(argument.Type);
this.Direction = argument.Direction;
}
private Type Type
{
get
{
if (this.type == null && !this.HasGetTypeBeenAttempted)
{
// For every deserialized ArgumentInfo, we are here only the very first call to the property getter.
this.HasGetTypeBeenAttempted = true;
try
{
this.type = Type.GetType(this.FullAssemblyQualifiedTypeName, false);
}
catch (Exception e)
{
if (e is TypeLoadException || e is FileNotFoundException || e is FileLoadException || e is ArgumentException)
{
this.type = null;
FxTrace.Exception.AsWarning(e);
}
else
{
throw;
}
}
}
return this.type;
}
set
{
this.type = value;
}
}
public string Name
{
get
{
return this.name;
}
private set
{
this.name = value;
}
}
public string FullAssemblyQualifiedTypeName
{
get
{
return this.fullAssemblyQualifiedTypeName;
}
private set
{
this.fullAssemblyQualifiedTypeName = value;
}
}
public ArgumentDirection Direction
{
get
{
return this.direction;
}
private set
{
this.direction = value;
}
}
[DataMember(EmitDefaultValue = false, Name = "VersionlessAssemblyQualifiedTypeName")]
internal string SerializedVersionlessAssemblyQualifiedTypeName
{
get { return this.versionlessAssemblyQualifiedTypeName; }
set { this.versionlessAssemblyQualifiedTypeName = value; }
}
[DataMember(EmitDefaultValue = false, Name = "Name")]
internal string SerializedName
{
get { return this.Name; }
set { this.Name = value; }
}
[DataMember(EmitDefaultValue = false, Name = "FullAssemblyQualifiedTypeName")]
internal string SerializedFullAssemblyQualifiedTypeName
{
get { return this.FullAssemblyQualifiedTypeName; }
set { this.FullAssemblyQualifiedTypeName = value; }
}
[DataMember(EmitDefaultValue = false, Name = "Direction")]
internal ArgumentDirection SerializedDirection
{
get { return this.Direction; }
set { this.Direction = value; }
}
private static bool TypeEquals(ArgumentInfo left, ArgumentInfo right)
{
Fx.Assert(left != null && right != null, "both left and right must not be null.");
if (left.versionlessAssemblyQualifiedTypeName == right.versionlessAssemblyQualifiedTypeName)
{
return true;
}
//
// Try to determine if the two argument types are in fact the same due to one being a TypeForwardedTo type to the other.
// When forwarded types are used, it is expected that all the assemblies involved in type forwarding to be always available,
// whether during map calcuation, during implementation map rollup, or during merging of multiple maps.
//
if (left.Type != null && right.Type != null && left.Type == right.Type)
{
return true;
}
return false;
}
public static bool Equals(ArgumentInfo left, ArgumentInfo right)
{
if (left == null)
{
return right == null;
}
return right != null &&
left.Name == right.Name && TypeEquals(left, right) && left.Direction == right.Direction;
}
public static IList<ArgumentInfo> List(Activity activity)
{
if (activity.RuntimeArguments == null)
{
return new List<ArgumentInfo>();
}
return (from r in activity.RuntimeArguments select new ArgumentInfo(r)).ToList();
}
public override bool Equals(object obj)
{
ArgumentInfo operand = obj as ArgumentInfo;
return Equals(this, operand);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
// generate assembly-qualified type name without assembly's version, culture and public token info
static string GenerateVersionlessAssemblyQualifiedTypeName(Type type)
{
StringBuilder sb = new StringBuilder();
BuildTypeSpec(sb, type);
return sb.ToString();
}
static void BuildTypeSpec(StringBuilder sb, Type type)
{
if (type.IsByRef)
{
BuildReferenceTypeSpec(sb, type);
}
else
{
BuildSimpleTypeSpec(sb, type);
}
}
static void BuildReferenceTypeSpec(StringBuilder sb, Type type)
{
Fx.Assert(type.HasElementType, "This type must have an element type.");
BuildSimpleTypeSpec(sb, type.GetElementType());
sb.Append('&');
}
static void BuildSimpleTypeSpec(StringBuilder sb, Type type)
{
if (type.IsPointer)
{
BuildPointerTypeSpec(sb, type);
}
else if (type.IsArray)
{
BuildArrayTypeSpec(sb, type);
}
else
{
BuildTypeName(sb, type);
}
}
static void BuildPointerTypeSpec(StringBuilder sb, Type type)
{
Fx.Assert(type.HasElementType, "This type must have an element type.");
BuildSimpleTypeSpec(sb, type.GetElementType());
sb.Append('*');
}
static void BuildArrayTypeSpec(StringBuilder sb, Type type)
{
Fx.Assert(type.IsArray, "This type must be an array type.");
Fx.Assert(type.HasElementType, "This type must have an element type.");
BuildSimpleTypeSpec(sb, type.GetElementType());
int arrayRank = type.GetArrayRank();
Fx.Assert(arrayRank > 0, "number of dimentions of this array must be greater than 0.");
sb.Append('[');
for (int i = 1; i < arrayRank; i++)
{
sb.Append(',');
}
sb.Append(']');
}
static void BuildTypeName(StringBuilder sb, Type type)
{
BuildNamespaceTypeName(sb, type);
sb.Append(", ");
BuildAssemblyNameSpec(sb, type);
}
static void BuildNamespaceTypeName(StringBuilder sb, Type type)
{
if (!String.IsNullOrEmpty(type.Namespace))
{
sb.Append(type.Namespace);
sb.Append('.');
}
BuildNestedTypeName(sb, type);
}
static void BuildNestedTypeName(StringBuilder sb, Type type)
{
if (type.IsNested)
{
BuildNestedTypeName(sb, type.DeclaringType);
sb.Append('+');
}
BuildSimpleName(sb, type);
}
static void BuildSimpleName(StringBuilder sb, Type type)
{
sb.Append(type.Name);
if (type.IsGenericType && !type.IsGenericTypeDefinition)
{
sb.Append('[');
Type[] genericArguments = type.GetGenericArguments();
sb.Append('[');
BuildTypeSpec(sb, genericArguments[0]);
sb.Append(']');
for (int i = 1; i < genericArguments.Length; i++)
{
sb.Append(',');
sb.Append('[');
BuildTypeSpec(sb, genericArguments[i]);
sb.Append(']');
}
sb.Append(']');
}
}
static void BuildAssemblyNameSpec(StringBuilder sb, Type type)
{
// only write assembly simple name,
// omit version, culture and public token
AssemblyName tempAssemName = new AssemblyName(type.Assembly.FullName);
sb.Append(tempAssemName.Name);
}
}
}

View File

@@ -0,0 +1,91 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.Activities.DynamicUpdate
{
using System;
using System.Xaml;
public static class DynamicUpdateInfo
{
private static AttachableMemberIdentifier mapItemProperty = new AttachableMemberIdentifier(typeof(DynamicUpdateInfo), "MapItem");
private static AttachableMemberIdentifier originalDefinitionProperty = new AttachableMemberIdentifier(typeof(DynamicUpdateInfo), "OriginalDefinition");
private static AttachableMemberIdentifier originalActivityBuilderProperty = new AttachableMemberIdentifier(typeof(DynamicUpdateInfo), "OriginalActivityBuilder");
public static void SetMapItem(object instance, DynamicUpdateMapItem mapItem)
{
if (mapItem != null)
{
AttachablePropertyServices.SetProperty(instance, mapItemProperty, mapItem);
}
else
{
AttachablePropertyServices.RemoveProperty(instance, mapItemProperty);
}
}
public static DynamicUpdateMapItem GetMapItem(object instance)
{
DynamicUpdateMapItem result;
if (AttachablePropertyServices.TryGetProperty(instance, mapItemProperty, out result))
{
return result;
}
else
{
return null;
}
}
public static void SetOriginalDefinition(object instance, Activity originalDefinition)
{
if (originalDefinition != null)
{
AttachablePropertyServices.SetProperty(instance, originalDefinitionProperty, originalDefinition);
}
else
{
AttachablePropertyServices.RemoveProperty(instance, originalDefinitionProperty);
}
}
public static Activity GetOriginalDefinition(object instance)
{
Activity result;
if (AttachablePropertyServices.TryGetProperty(instance, originalDefinitionProperty, out result))
{
return result;
}
else
{
return null;
}
}
public static void SetOriginalActivityBuilder(object instance, ActivityBuilder originalActivityBuilder)
{
if (originalActivityBuilder != null)
{
AttachablePropertyServices.SetProperty(instance, originalActivityBuilderProperty, originalActivityBuilder);
}
else
{
AttachablePropertyServices.RemoveProperty(instance, originalActivityBuilderProperty);
}
}
public static ActivityBuilder GetOriginalActivityBuilder(object instance)
{
ActivityBuilder result;
if (AttachablePropertyServices.TryGetProperty(instance, originalActivityBuilderProperty, out result))
{
return result;
}
else
{
return null;
}
}
}
}

View File

@@ -0,0 +1,261 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Activities.DynamicUpdate
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime;
using System.Runtime.Serialization;
using System.ComponentModel;
[DataContract(IsReference = true)]
internal class DynamicUpdateMapEntry
{
static DynamicUpdateMapEntry dummyMapEntry = new DynamicUpdateMapEntry(-1, -1);
DynamicUpdateMap implementationUpdateMap;
int oldActivityId;
int newActivityId;
public DynamicUpdateMapEntry(int oldActivityId, int newActivityId)
{
this.OldActivityId = oldActivityId;
this.NewActivityId = newActivityId;
}
// this is a dummy map entry to be used for creating a NativeActivityUpdateContext
// for calling UpdateInstance() on activities without map entries.
// the OldActivityId and NewActivityId of this dummy map entry are invalid,
// and should not be used anywhere except for creating NativeActivityUpdateContext.
internal static DynamicUpdateMapEntry DummyMapEntry
{
get { return dummyMapEntry; }
}
public int OldActivityId
{
get
{
return this.oldActivityId;
}
private set
{
this.oldActivityId = value;
}
}
public int NewActivityId
{
get
{
return this.newActivityId;
}
private set
{
this.newActivityId = value;
}
}
[DataMember(EmitDefaultValue = false)]
public DynamicUpdateMapEntry Parent
{
get;
set;
}
// Only set when IsRemoval == true && IsParentRemovedOrBlock == false
[DataMember(EmitDefaultValue = false)]
public string DisplayName
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public UpdateBlockedReason BlockReason { get; set; }
[DataMember(EmitDefaultValue = false)]
public string BlockReasonMessage { get; set; }
public bool IsRuntimeUpdateBlocked
{
get
{
return BlockReason != UpdateBlockedReason.NotBlocked;
}
}
[DataMember(EmitDefaultValue = false)]
public bool IsUpdateBlockedByUpdateAuthor { get; set; }
public bool IsParentRemovedOrBlocked
{
get
{
for (DynamicUpdateMapEntry parent = this.Parent; parent != null; parent = parent.Parent)
{
if (parent.IsRemoval || parent.IsRuntimeUpdateBlocked || parent.IsUpdateBlockedByUpdateAuthor)
{
return true;
}
}
return false;
}
}
[DataMember(EmitDefaultValue = false)]
public IDictionary<string, object> SavedOriginalValues { get; set; }
[DataMember(EmitDefaultValue = false)]
public object SavedOriginalValueFromParent { get; set; }
[DataMember(EmitDefaultValue = false)]
public EnvironmentUpdateMap EnvironmentUpdateMap
{
get;
set;
}
public DynamicUpdateMap ImplementationUpdateMap
{
get
{
return this.implementationUpdateMap;
}
internal set
{
this.implementationUpdateMap = value;
}
}
[DataMember(EmitDefaultValue = false, Name = "implementationUpdateMap")]
internal DynamicUpdateMap SerializedImplementationUpdateMap
{
get { return this.implementationUpdateMap; }
set { this.implementationUpdateMap = value; }
}
[DataMember(EmitDefaultValue = false, Name = "OldActivityId")]
internal int SerializedOldActivityId
{
get { return this.OldActivityId; }
set { this.OldActivityId = value; }
}
[DataMember(EmitDefaultValue = false, Name = "NewActivityId")]
internal int SerializedNewActivityId
{
get { return this.NewActivityId; }
set { this.NewActivityId = value; }
}
internal bool IsIdChange
{
get
{
return this.NewActivityId > 0 && this.OldActivityId > 0 && this.NewActivityId != this.OldActivityId;
}
}
internal bool IsRemoval
{
get
{
return this.NewActivityId <= 0 && this.OldActivityId > 0;
}
}
internal bool HasEnvironmentUpdates
{
get
{
return this.EnvironmentUpdateMap != null;
}
}
internal static DynamicUpdateMapEntry Merge(DynamicUpdateMapEntry first, DynamicUpdateMapEntry second,
DynamicUpdateMapEntry newParent, DynamicUpdateMap.MergeErrorContext errorContext)
{
Fx.Assert(first.NewActivityId == second.OldActivityId, "Merging mismatched entries");
Fx.Assert((first.Parent == null && second.Parent == null) || (first.Parent.NewActivityId == second.Parent.OldActivityId), "Merging mismatched parents");
DynamicUpdateMapEntry result = new DynamicUpdateMapEntry(first.OldActivityId, second.NewActivityId)
{
Parent = newParent
};
if (second.IsRemoval)
{
if (!result.IsParentRemovedOrBlocked)
{
result.DisplayName = second.DisplayName;
}
}
else
{
result.SavedOriginalValues = Merge(first.SavedOriginalValues, second.SavedOriginalValues);
result.SavedOriginalValueFromParent = first.SavedOriginalValueFromParent ?? second.SavedOriginalValueFromParent;
if (first.BlockReason == UpdateBlockedReason.NotBlocked)
{
result.BlockReason = second.BlockReason;
result.BlockReasonMessage = second.BlockReasonMessage;
}
else
{
result.BlockReason = first.BlockReason;
result.BlockReasonMessage = second.BlockReasonMessage;
}
result.IsUpdateBlockedByUpdateAuthor = first.IsUpdateBlockedByUpdateAuthor || second.IsUpdateBlockedByUpdateAuthor;
errorContext.PushIdSpace(result.NewActivityId);
result.EnvironmentUpdateMap = EnvironmentUpdateMap.Merge(first.EnvironmentUpdateMap, second.EnvironmentUpdateMap, errorContext);
if (!result.IsRuntimeUpdateBlocked && !result.IsUpdateBlockedByUpdateAuthor && !result.IsParentRemovedOrBlocked)
{
result.ImplementationUpdateMap = DynamicUpdateMap.Merge(first.ImplementationUpdateMap, second.ImplementationUpdateMap, errorContext);
}
errorContext.PopIdSpace();
};
return result;
}
internal static IDictionary<string, object> Merge(IDictionary<string, object> first, IDictionary<string, object> second)
{
if (first == null || second == null)
{
return first ?? second;
}
Dictionary<string, object> result = new Dictionary<string, object>(first);
foreach (KeyValuePair<string, object> pair in second)
{
if (!result.ContainsKey(pair.Key))
{
result.Add(pair.Key, pair.Value);
}
}
return result;
}
internal DynamicUpdateMapEntry Clone(DynamicUpdateMapEntry newParent)
{
return new DynamicUpdateMapEntry(this.OldActivityId, this.NewActivityId)
{
DisplayName = this.DisplayName,
EnvironmentUpdateMap = this.EnvironmentUpdateMap,
ImplementationUpdateMap = this.ImplementationUpdateMap,
BlockReason = this.BlockReason,
BlockReasonMessage = this.BlockReasonMessage,
IsUpdateBlockedByUpdateAuthor = this.IsUpdateBlockedByUpdateAuthor,
Parent = newParent,
SavedOriginalValues = this.SavedOriginalValues,
SavedOriginalValueFromParent = this.SavedOriginalValueFromParent
};
}
}
}

View File

@@ -0,0 +1,50 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.Activities.DynamicUpdate
{
using System;
using System.Activities.XamlIntegration;
using System.ComponentModel;
using System.Runtime.Serialization;
[TypeConverter(typeof(DynamicUpdateMapItemConverter))]
[DataContract]
public class DynamicUpdateMapItem
{
internal DynamicUpdateMapItem(int originalId)
{
this.OriginalId = originalId;
}
internal DynamicUpdateMapItem(int originalVariableOwnerId, int originalVariableId)
{
this.OriginalVariableOwnerId = originalVariableOwnerId;
this.OriginalId = originalVariableId;
}
[DataMember]
internal int OriginalId
{
get;
set;
}
[DataMember]
internal int OriginalVariableOwnerId
{
get;
set;
}
internal bool IsVariableMapItem
{
get
{
return this.OriginalVariableOwnerId > 0;
}
}
}
}

View File

@@ -0,0 +1,277 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.Activities.DynamicUpdate
{
using System;
using System.Activities.DynamicUpdate;
using System.Activities.XamlIntegration;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Runtime;
using System.Runtime.Serialization;
public class DynamicUpdateMapQuery
{
private DynamicUpdateMap map;
private Activity updatedWorkflowDefinition;
private Activity originalWorkflowDefinition;
internal DynamicUpdateMapQuery(DynamicUpdateMap map, Activity updatedWorkflowDefinition, Activity originalWorkflowDefinition)
{
Fx.Assert(updatedWorkflowDefinition == updatedWorkflowDefinition.RootActivity, "This parameter must be root of workflow");
Fx.Assert(originalWorkflowDefinition == originalWorkflowDefinition.RootActivity, "This parameter must be root of workflow");
this.map = map;
this.updatedWorkflowDefinition = updatedWorkflowDefinition;
this.originalWorkflowDefinition = originalWorkflowDefinition;
}
public Activity FindMatch(Activity activity)
{
if (activity == null)
{
throw FxTrace.Exception.ArgumentNull("activity");
}
if (IsInNewDefinition(activity))
{
return this.MatchNewToOld(activity);
}
else
{
return this.MatchOldToNew(activity);
}
}
public Variable FindMatch(Variable variable)
{
if (variable == null)
{
throw FxTrace.Exception.ArgumentNull("variable");
}
if (IsInNewDefinition(variable))
{
return this.MatchNewToOld(variable);
}
else
{
return this.MatchOldToNew(variable);
}
}
public bool CanApplyUpdateWhileRunning(Activity activity)
{
if (activity == null)
{
throw FxTrace.Exception.ArgumentNull("activity");
}
return this.CanApplyUpdateWhileRunning(activity, IsInNewDefinition(activity));
}
private Activity MatchNewToOld(Activity newActivity)
{
DynamicUpdateMapEntry entry;
return this.MatchNewToOld(newActivity, out entry);
}
private Activity MatchNewToOld(Activity newActivity, out DynamicUpdateMapEntry entry)
{
entry = null;
if (this.map.TryGetUpdateEntryByNewId(newActivity.InternalId, out entry))
{
IdSpace rootIdSpace;
if (this.map.IsForImplementation)
{
rootIdSpace = this.originalWorkflowDefinition.ParentOf;
}
else
{
rootIdSpace = this.originalWorkflowDefinition.MemberOf;
}
if (rootIdSpace != null)
{
return rootIdSpace[entry.OldActivityId];
}
}
return null;
}
private Variable MatchNewToOld(Variable newVariable)
{
if (!newVariable.IsPublic)
{
return null;
}
DynamicUpdateMapEntry entry;
Activity oldOwner = this.MatchNewToOld(newVariable.Owner, out entry);
if (oldOwner == null)
{
return null;
}
int newIndex = newVariable.Owner.RuntimeVariables.IndexOf(newVariable);
int? oldIndex = entry.HasEnvironmentUpdates ?
entry.EnvironmentUpdateMap.GetOldVariableIndex(newIndex) :
newIndex;
return oldIndex.HasValue ? oldOwner.RuntimeVariables[oldIndex.Value] : null;
}
private Activity MatchOldToNew(Activity oldActivity)
{
DynamicUpdateMapEntry entry;
return this.MatchOldToNew(oldActivity, out entry);
}
private Activity MatchOldToNew(Activity oldActivity, out DynamicUpdateMapEntry entry)
{
entry = null;
if (this.map.TryGetUpdateEntry(oldActivity.InternalId, out entry) && entry.NewActivityId > 0)
{
IdSpace rootIdSpace;
if (this.map.IsForImplementation)
{
rootIdSpace = this.updatedWorkflowDefinition.ParentOf;
}
else
{
rootIdSpace = this.updatedWorkflowDefinition.MemberOf;
}
if (rootIdSpace != null)
{
return rootIdSpace[entry.NewActivityId];
}
}
return null;
}
private Variable MatchOldToNew(Variable oldVariable)
{
if (!oldVariable.IsPublic)
{
return null;
}
DynamicUpdateMapEntry entry;
Activity newOwner = this.MatchOldToNew(oldVariable.Owner, out entry);
if (newOwner == null)
{
return null;
}
int oldIndex = oldVariable.Owner.RuntimeVariables.IndexOf(oldVariable);
int? newIndex = entry.HasEnvironmentUpdates ?
entry.EnvironmentUpdateMap.GetNewVariableIndex(oldIndex) :
oldIndex;
return newIndex.HasValue ? newOwner.RuntimeVariables[newIndex.Value] : null;
}
private bool CanApplyUpdateWhileRunning(Activity activity, bool isInNewDefinition)
{
Activity currentActivity = activity;
IdSpace rootIdSpace = activity.MemberOf;
do
{
DynamicUpdateMapEntry entry = null;
if (isInNewDefinition)
{
this.map.TryGetUpdateEntryByNewId(currentActivity.InternalId, out entry);
}
else if (currentActivity.MemberOf == rootIdSpace)
{
this.map.TryGetUpdateEntry(currentActivity.InternalId, out entry);
}
if (entry != null &&
(entry.NewActivityId < 1 ||
entry.IsRuntimeUpdateBlocked ||
entry.IsUpdateBlockedByUpdateAuthor))
{
return false;
}
currentActivity = currentActivity.Parent;
}
while (currentActivity != null && currentActivity.MemberOf == rootIdSpace);
return true;
}
private bool IsInNewDefinition(Activity activity, bool isVariableOwner = false)
{
bool result = false;
if (activity.RootActivity == this.updatedWorkflowDefinition)
{
result = true;
}
else if (activity.RootActivity == this.originalWorkflowDefinition)
{
result = false;
}
else
{
ThrowNotInDefinition(isVariableOwner,
SR.QueryVariableIsNotInDefinition,
SR.QueryActivityIsNotInDefinition);
}
// We only support either the public or the implementation IdSpace at the root of the workflow.
// The user does not have visibility into nested IdSpaces so should not be querying into them.
if (this.map.IsForImplementation)
{
if (activity.MemberOf.Owner != activity.RootActivity)
{
ThrowNotInDefinition(isVariableOwner,
SR.QueryVariableIsPublic(activity.RootActivity),
SR.QueryActivityIsPublic(activity.RootActivity));
}
}
else if (activity.MemberOf != activity.RootActivity.MemberOf)
{
ThrowNotInDefinition(isVariableOwner,
SR.QueryVariableIsInImplementation(activity.MemberOf.Owner),
SR.QueryActivityIsInImplementation(activity.MemberOf.Owner));
}
return result;
}
private bool IsInNewDefinition(Variable variable)
{
if (variable.Owner == null)
{
throw FxTrace.Exception.Argument("variable", SR.QueryVariableIsNotInDefinition);
}
if (!variable.IsPublic)
{
throw FxTrace.Exception.Argument("variable", SR.QueryVariableIsNotPublic);
}
return IsInNewDefinition(variable.Owner, true);
}
private void ThrowNotInDefinition(bool isVariableOwner, string variableMessage, string activityMessage)
{
if (isVariableOwner)
{
throw FxTrace.Exception.Argument("variable", variableMessage);
}
else
{
throw FxTrace.Exception.Argument("activity", activityMessage);
}
}
}
}

View File

@@ -0,0 +1,270 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Activities.DynamicUpdate
{
using System;
using System.IO;
using System.Activities;
using System.Activities.Expressions;
using System.Activities.DynamicUpdate;
using System.Activities.Hosting;
using System.Activities.Runtime;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Xaml;
using System.Activities.Validation;
using Microsoft.VisualBasic.Activities;
public static class DynamicUpdateServices
{
private static Func<Activity, Exception> onInvalidActivityToBlockUpdate =
new Func<Activity, Exception>(OnInvalidActivityToBlockUpdate);
private static Func<Activity, Exception> onInvalidImplementationMapAssociation =
new Func<Activity, Exception>(OnInvalidImplementationMapAssociation);
private static AttachableMemberIdentifier implementationMapProperty = new AttachableMemberIdentifier(typeof(DynamicUpdateServices), "ImplementationMap");
public static void PrepareForUpdate(Activity workflowDefinitionToBeUpdated)
{
if (workflowDefinitionToBeUpdated == null)
{
throw FxTrace.Exception.ArgumentNull("workflowDefinitionToBeUpdated");
}
InternalPrepareForUpdate(workflowDefinitionToBeUpdated, false);
}
public static void PrepareForUpdate(ActivityBuilder activityDefinitionToBeUpdated)
{
if (activityDefinitionToBeUpdated == null)
{
throw FxTrace.Exception.ArgumentNull("activityDefinitionToBeUpdated");
}
InternalPrepareForUpdate(activityDefinitionToBeUpdated, true);
}
private static void InternalPrepareForUpdate(object definitionToBeUpdated, bool forImplementation)
{
// Clone the definition
object clone;
using (XamlObjectReader reader = new XamlObjectReader(definitionToBeUpdated))
{
using (XamlObjectWriter writer = new XamlObjectWriter(reader.SchemaContext))
{
XamlServices.Transform(reader, writer);
clone = writer.Result;
}
}
// Calculate the match info
// Set the match info as attached properties so it is serializable,
// and available when the user calls CreateUpdateMap
IDictionary<object, DynamicUpdateMapItem> mapItems;
if (!forImplementation)
{
DynamicUpdateInfo.SetOriginalDefinition(definitionToBeUpdated, (Activity)clone);
mapItems = DynamicUpdateMap.CalculateMapItems((Activity)definitionToBeUpdated);
}
else
{
DynamicUpdateInfo.SetOriginalActivityBuilder(definitionToBeUpdated, (ActivityBuilder)clone);
mapItems = DynamicUpdateMap.CalculateImplementationMapItems(GetDynamicActivity((ActivityBuilder)definitionToBeUpdated));
}
foreach (KeyValuePair<object, DynamicUpdateMapItem> objectInfo in mapItems)
{
DynamicUpdateInfo.SetMapItem(objectInfo.Key, objectInfo.Value);
}
}
public static DynamicUpdateMap CreateUpdateMap(Activity updatedWorkflowDefinition)
{
return CreateUpdateMap(updatedWorkflowDefinition, null);
}
public static DynamicUpdateMap CreateUpdateMap(Activity updatedWorkflowDefinition, IEnumerable<Activity> disallowUpdateInsideActivities)
{
IList<ActivityBlockingUpdate> activitiesBlockingUpdate;
return CreateUpdateMap(updatedWorkflowDefinition, disallowUpdateInsideActivities, out activitiesBlockingUpdate);
}
[SuppressMessage(FxCop.Category.Design, FxCop.Rule.AvoidOutParameters, Justification = "Approved Design. Need to return the map and the block list.")]
public static DynamicUpdateMap CreateUpdateMap(Activity updatedWorkflowDefinition, IEnumerable<Activity> disallowUpdateInsideActivities, out IList<ActivityBlockingUpdate> activitiesBlockingUpdate)
{
if (updatedWorkflowDefinition == null)
{
throw FxTrace.Exception.ArgumentNull("updatedWorkflowDefinition");
}
Activity originalDefinition = DynamicUpdateInfo.GetOriginalDefinition(updatedWorkflowDefinition);
if (originalDefinition == null)
{
throw FxTrace.Exception.Argument("updatedWorkflowDefinition", SR.MustCallPrepareBeforeFinalize);
}
DynamicUpdateMap result = InternalTryCreateUpdateMap(updatedWorkflowDefinition, originalDefinition, disallowUpdateInsideActivities, false, out activitiesBlockingUpdate);
// Remove the DynamicUpdateMapItems now that the update is finalized
// Calling CalculateMapItems is actually an unnecessary perf hit since it calls CacheMetadata
// again; but we do it so that Finalize is implemented purely in terms of other public APIs.
DynamicUpdateInfo.SetOriginalDefinition(updatedWorkflowDefinition, null);
IDictionary<object, DynamicUpdateMapItem> mapItems = DynamicUpdateMap.CalculateMapItems(updatedWorkflowDefinition);
foreach (object matchObject in mapItems.Keys)
{
DynamicUpdateInfo.SetMapItem(matchObject, null);
}
return result;
}
public static DynamicUpdateMap CreateUpdateMap(ActivityBuilder updatedActivityDefinition)
{
return CreateUpdateMap(updatedActivityDefinition, null);
}
public static DynamicUpdateMap CreateUpdateMap(ActivityBuilder updatedActivityDefinition, IEnumerable<Activity> disallowUpdateInsideActivities)
{
IList<ActivityBlockingUpdate> activitiesBlockingUpdate;
return CreateUpdateMap(updatedActivityDefinition, disallowUpdateInsideActivities, out activitiesBlockingUpdate);
}
[SuppressMessage(FxCop.Category.Design, FxCop.Rule.AvoidOutParameters, Justification = "Approved Design. Need to return the map and the block list.")]
public static DynamicUpdateMap CreateUpdateMap(ActivityBuilder updatedActivityDefinition, IEnumerable<Activity> disallowUpdateInsideActivities, out IList<ActivityBlockingUpdate> activitiesBlockingUpdate)
{
if (updatedActivityDefinition == null)
{
throw FxTrace.Exception.ArgumentNull("updatedActivityDefinition");
}
ActivityBuilder originalActivityDefinition = DynamicUpdateInfo.GetOriginalActivityBuilder(updatedActivityDefinition);
if (originalActivityDefinition == null)
{
throw FxTrace.Exception.Argument("updatedActivityDefinition", SR.MustCallPrepareBeforeFinalize);
}
Activity originalBuiltRoot = GetDynamicActivity(originalActivityDefinition);
Activity updatedBuiltRoot = GetDynamicActivity(updatedActivityDefinition);
DynamicUpdateMap result = InternalTryCreateUpdateMap(updatedBuiltRoot, originalBuiltRoot, disallowUpdateInsideActivities, true, out activitiesBlockingUpdate);
// Remove the DynamicUpdateMapItems now that the update is finalized
// Calling CalculateMapItems is actually an unnecessary perf hit since it calls CacheMetadata
// again; but we do it so that Finalize is implemented purely in terms of other public APIs.
DynamicUpdateInfo.SetOriginalActivityBuilder(updatedActivityDefinition, null);
IDictionary<object, DynamicUpdateMapItem> mapItems = DynamicUpdateMap.CalculateImplementationMapItems(updatedBuiltRoot);
foreach (object matchObject in mapItems.Keys)
{
DynamicUpdateInfo.SetMapItem(matchObject, null);
}
return result;
}
private static DynamicUpdateMap InternalTryCreateUpdateMap(Activity updatedDefinition, Activity originalDefinition, IEnumerable<Activity> disallowUpdateInsideActivities, bool forImplementation, out IList<ActivityBlockingUpdate> activitiesBlockingUpdate)
{
DynamicUpdateMapBuilder builder = new DynamicUpdateMapBuilder
{
ForImplementation = forImplementation,
LookupMapItem = DynamicUpdateInfo.GetMapItem,
LookupImplementationMap = GetImplementationMap,
UpdatedWorkflowDefinition = updatedDefinition,
OriginalWorkflowDefinition = originalDefinition,
OnInvalidActivityToBlockUpdate = onInvalidActivityToBlockUpdate,
OnInvalidImplementationMapAssociation = onInvalidImplementationMapAssociation,
};
if (disallowUpdateInsideActivities != null)
{
foreach (Activity activity in disallowUpdateInsideActivities)
{
builder.DisallowUpdateInside.Add(activity);
}
}
return builder.CreateMap(out activitiesBlockingUpdate);
}
public static DynamicUpdateMap GetImplementationMap(Activity targetActivity)
{
DynamicUpdateMap result;
if (AttachablePropertyServices.TryGetProperty(targetActivity, implementationMapProperty, out result))
{
return result;
}
else
{
return null;
}
}
public static void SetImplementationMap(Activity targetActivity, DynamicUpdateMap implementationMap)
{
if (implementationMap != null)
{
AttachablePropertyServices.SetProperty(targetActivity, implementationMapProperty, implementationMap);
}
else
{
AttachablePropertyServices.RemoveProperty(targetActivity, implementationMapProperty);
}
}
static DynamicActivity GetDynamicActivity(ActivityBuilder activityDefinition)
{
DynamicActivity result = new DynamicActivity
{
Name = activityDefinition.Name
};
foreach (DynamicActivityProperty property in activityDefinition.Properties)
{
result.Properties.Add(property);
}
foreach (Attribute attrib in activityDefinition.Attributes)
{
result.Attributes.Add(attrib);
}
foreach (Constraint constraint in activityDefinition.Constraints)
{
result.Constraints.Add(constraint);
}
result.Implementation = () => activityDefinition.Implementation;
VisualBasicSettings vbsettings = VisualBasic.GetSettings(activityDefinition);
if (vbsettings != null)
{
VisualBasic.SetSettings(result, vbsettings);
}
IList<string> namespacesForImplementation = TextExpression.GetNamespacesForImplementation(activityDefinition);
if (namespacesForImplementation.Count > 0)
{
TextExpression.SetNamespacesForImplementation(result, namespacesForImplementation);
}
IList<AssemblyReference> referencesForImplementation = TextExpression.GetReferencesForImplementation(activityDefinition);
if (referencesForImplementation.Count > 0)
{
TextExpression.SetReferencesForImplementation(result, referencesForImplementation);
}
return result;
}
static Exception OnInvalidActivityToBlockUpdate(Activity activity)
{
return new ArgumentException(SR.InvalidActivityToBlockUpdateServices(activity), "disallowUpdateInsideActivities");
}
static Exception OnInvalidImplementationMapAssociation(Activity activity)
{
return new InvalidOperationException(SR.InvalidImplementationMapAssociationServices(activity));
}
}
}

View File

@@ -0,0 +1,299 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Activities.DynamicUpdate
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime;
using System.Runtime.Serialization;
using System.ComponentModel;
[DataContract]
internal class EnvironmentUpdateMap
{
IList<EnvironmentUpdateMapEntry> variableEntries;
IList<EnvironmentUpdateMapEntry> privateVariableEntries;
IList<EnvironmentUpdateMapEntry> argumentEntries;
public EnvironmentUpdateMap()
{
}
[DataMember(EmitDefaultValue = false)]
public int NewArgumentCount
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public int OldArgumentCount
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public int NewVariableCount
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public int OldVariableCount
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public int NewPrivateVariableCount
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public int OldPrivateVariableCount
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public int RuntimeDelegateArgumentCount
{
get;
set;
}
[DataMember(EmitDefaultValue = false, Name = "variableEntries")]
internal IList<EnvironmentUpdateMapEntry> SerializedVariableEntries
{
get { return this.variableEntries; }
set { this.variableEntries = value; }
}
[DataMember(EmitDefaultValue = false, Name = "privateVariableEntries")]
internal IList<EnvironmentUpdateMapEntry> SerializedPrivateVariableEntries
{
get { return this.privateVariableEntries; }
set { this.privateVariableEntries = value; }
}
[DataMember(EmitDefaultValue = false, Name = "argumentEntries")]
internal IList<EnvironmentUpdateMapEntry> SerializedArgumentEntries
{
get { return this.argumentEntries; }
set { this.argumentEntries = value; }
}
internal bool IsAdditionToNoSymbols
{
get
{
return (this.OldArgumentCount + this.OldVariableCount + this.OldPrivateVariableCount + this.RuntimeDelegateArgumentCount) == 0 &&
(this.NewArgumentCount + this.NewVariableCount + this.NewPrivateVariableCount + this.RuntimeDelegateArgumentCount) > 0;
}
}
internal bool HasVariableEntries
{
get
{
return this.variableEntries != null && this.variableEntries.Count > 0;
}
}
internal bool HasPrivateVariableEntries
{
get
{
return this.privateVariableEntries != null && this.privateVariableEntries.Count > 0;
}
}
internal bool HasArgumentEntries
{
get
{
return this.argumentEntries != null && this.argumentEntries.Count > 0;
}
}
public IList<EnvironmentUpdateMapEntry> VariableEntries
{
get
{
if (this.variableEntries == null)
{
this.variableEntries = new List<EnvironmentUpdateMapEntry>();
}
return this.variableEntries;
}
}
public IList<EnvironmentUpdateMapEntry> PrivateVariableEntries
{
get
{
if (this.privateVariableEntries == null)
{
this.privateVariableEntries = new List<EnvironmentUpdateMapEntry>();
}
return this.privateVariableEntries;
}
}
public IList<EnvironmentUpdateMapEntry> ArgumentEntries
{
get
{
if (this.argumentEntries == null)
{
this.argumentEntries = new List<EnvironmentUpdateMapEntry>();
}
return this.argumentEntries;
}
}
internal static EnvironmentUpdateMap Merge(EnvironmentUpdateMap first, EnvironmentUpdateMap second,
DynamicUpdateMap.MergeErrorContext errorContext)
{
if (first == null || second == null)
{
return first ?? second;
}
ThrowIfMapsIncompatible(first, second, errorContext);
EnvironmentUpdateMap result = new EnvironmentUpdateMap
{
OldArgumentCount = first.OldArgumentCount,
NewArgumentCount = second.NewArgumentCount,
OldVariableCount = first.OldVariableCount,
NewVariableCount = second.NewVariableCount,
OldPrivateVariableCount = first.OldPrivateVariableCount,
NewPrivateVariableCount = second.NewPrivateVariableCount,
};
result.variableEntries = Merge(result.NewVariableCount, first.VariableEntries, second.VariableEntries);
result.privateVariableEntries = Merge(result.NewPrivateVariableCount, first.PrivateVariableEntries, second.PrivateVariableEntries);
result.argumentEntries = Merge(result.NewArgumentCount, first.ArgumentEntries, second.ArgumentEntries);
if (result.OldArgumentCount != result.NewArgumentCount ||
result.OldVariableCount != result.NewVariableCount ||
result.OldPrivateVariableCount != result.NewPrivateVariableCount ||
result.HasArgumentEntries || result.HasVariableEntries || result.HasPrivateVariableEntries)
{
return result;
}
else
{
return null;
}
}
internal int? GetOldVariableIndex(int newIndex)
{
EnvironmentUpdateMapEntry environmentEntry = FindByNewIndex(this.VariableEntries, newIndex);
if (environmentEntry != null)
{
return environmentEntry.IsAddition ? (int?)null : environmentEntry.OldOffset;
}
return null;
}
internal int? GetNewVariableIndex(int oldIndex)
{
foreach (EnvironmentUpdateMapEntry environmentEntry in this.VariableEntries)
{
if (environmentEntry.OldOffset == oldIndex)
{
return environmentEntry.NewOffset;
}
}
return null;
}
internal int? GetNewPrivateVariableIndex(int oldIndex)
{
foreach (EnvironmentUpdateMapEntry environmentEntry in this.PrivateVariableEntries)
{
if (environmentEntry.OldOffset == oldIndex)
{
return environmentEntry.NewOffset;
}
}
return null;
}
static void ThrowIfMapsIncompatible(EnvironmentUpdateMap first, EnvironmentUpdateMap second,
DynamicUpdateMap.MergeErrorContext errorContext)
{
if (first.NewArgumentCount != second.OldArgumentCount ||
first.NewVariableCount != second.OldVariableCount ||
first.NewPrivateVariableCount != second.OldPrivateVariableCount)
{
errorContext.Throw(SR.InvalidMergeMapEnvironmentCount(
first.NewArgumentCount, first.NewVariableCount, first.NewPrivateVariableCount,
second.OldArgumentCount, second.OldVariableCount, second.OldPrivateVariableCount));
}
}
static IList<EnvironmentUpdateMapEntry> Merge(int finalCount, IList<EnvironmentUpdateMapEntry> first,
IList<EnvironmentUpdateMapEntry> second)
{
List<EnvironmentUpdateMapEntry> result = new List<EnvironmentUpdateMapEntry>();
for (int i = 0; i < finalCount; i++)
{
EnvironmentUpdateMapEntry resultEntry = MergeEntry(i, first, second);
if (resultEntry != null)
{
result.Add(resultEntry);
}
}
return result.Count > 0 ? result : null;
}
static EnvironmentUpdateMapEntry MergeEntry(int finalIndex, IList<EnvironmentUpdateMapEntry> first,
IList<EnvironmentUpdateMapEntry> second)
{
EnvironmentUpdateMapEntry secondEntry = FindByNewIndex(second, finalIndex);
EnvironmentUpdateMapEntry firstEntry;
if (secondEntry != null)
{
firstEntry = secondEntry.IsAddition ? null : FindByNewIndex(first, secondEntry.OldOffset);
}
else
{
firstEntry = FindByNewIndex(first, finalIndex);
}
return EnvironmentUpdateMapEntry.Merge(firstEntry, secondEntry);
}
static EnvironmentUpdateMapEntry FindByNewIndex(IList<EnvironmentUpdateMapEntry> entries, int newIndex)
{
foreach (EnvironmentUpdateMapEntry environmentEntry in entries)
{
if (environmentEntry.NewOffset == newIndex)
{
return environmentEntry;
}
}
return null;
}
}
}

View File

@@ -0,0 +1,73 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Activities.DynamicUpdate
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime;
using System.Runtime.Serialization;
using System.ComponentModel;
[DataContract]
internal class EnvironmentUpdateMapEntry
{
internal const int NonExistent = -1;
public EnvironmentUpdateMapEntry()
{
}
[DataMember(EmitDefaultValue = false)]
public int OldOffset
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public int NewOffset
{
get;
set;
}
[DataMember(EmitDefaultValue = false)]
public bool IsNewHandle
{
get;
set;
}
internal bool IsAddition
{
get
{
return this.OldOffset == EnvironmentUpdateMapEntry.NonExistent;
}
}
internal static EnvironmentUpdateMapEntry Merge(EnvironmentUpdateMapEntry first, EnvironmentUpdateMapEntry second)
{
if (first == null || second == null)
{
return first ?? second;
}
Fx.Assert(first.NewOffset == second.OldOffset && !second.IsAddition, "Merging mismatched entries");
if (first.OldOffset == second.NewOffset)
{
return null;
}
return new EnvironmentUpdateMapEntry
{
OldOffset = first.OldOffset,
NewOffset = second.NewOffset,
IsNewHandle = first.IsNewHandle
};
}
}
}

View File

@@ -0,0 +1,11 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.Activities.DynamicUpdate
{
internal interface IInstanceUpdatable
{
void InternalUpdateInstance(NativeActivityUpdateContext updateContext);
}
}

View File

@@ -0,0 +1,116 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Activities.DynamicUpdate
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Text;
using System.Security;
using System.Runtime;
[Serializable]
public class InstanceUpdateException : Exception
{
private ReadOnlyCollection<ActivityBlockingUpdate> blockingActivities;
public InstanceUpdateException()
: base()
{
}
public InstanceUpdateException(string message)
: base(message)
{
}
public InstanceUpdateException(string message, Exception innerException)
: base(message, innerException)
{
}
public InstanceUpdateException(IList<ActivityBlockingUpdate> blockingActivities)
: this(BuildMessage(blockingActivities), blockingActivities)
{
}
public InstanceUpdateException(string message, IList<ActivityBlockingUpdate> blockingActivities)
: base(message)
{
if (blockingActivities != null)
{
this.blockingActivities = new ReadOnlyCollection<ActivityBlockingUpdate>(blockingActivities);
}
}
public InstanceUpdateException(string message, IList<ActivityBlockingUpdate> blockingActivities, Exception innerException)
: base(message, innerException)
{
if (blockingActivities != null)
{
this.blockingActivities = new ReadOnlyCollection<ActivityBlockingUpdate>(blockingActivities);
}
}
protected InstanceUpdateException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
this.blockingActivities = (ReadOnlyCollection<ActivityBlockingUpdate>)info.GetValue(
"blockingActivities", typeof(ReadOnlyCollection<ActivityBlockingUpdate>));
}
public IList<ActivityBlockingUpdate> BlockingActivities
{
get
{
if (this.blockingActivities == null)
{
this.blockingActivities = new ReadOnlyCollection<ActivityBlockingUpdate>(new ActivityBlockingUpdate[0]);
}
return this.blockingActivities;
}
}
[Fx.Tag.SecurityNote(Critical = "Critical because we are overriding a critical method in the base class.")]
[SecurityCritical]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("blockingActivities", this.blockingActivities);
}
private static string BuildMessage(IList<ActivityBlockingUpdate> blockingActivities)
{
if (blockingActivities != null && blockingActivities.Count > 0)
{
StringBuilder errorMsgs = new StringBuilder();
for (int i = 0; i < blockingActivities.Count - 1; i++)
{
errorMsgs.AppendLine(GetMessage(blockingActivities[i]));
}
errorMsgs.Append(GetMessage(blockingActivities[blockingActivities.Count - 1]));
return errorMsgs.ToString();
}
return null;
}
private static string GetMessage(ActivityBlockingUpdate blockingActivity)
{
object activity = (object)blockingActivity.Activity ?? blockingActivity.UpdatedActivityId;
if (activity != null)
{
return SR.ActivityBlockingUpdate(activity, blockingActivity.Reason);
}
else
{
return blockingActivity.Reason;
}
}
}
}

View File

@@ -0,0 +1,89 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.Activities.DynamicUpdate
{
using System;
using System.Activities.Validation;
using System.Collections.Generic;
using System.Linq;
public class NativeActivityUpdateMapMetadata : UpdateMapMetadata
{
internal NativeActivityUpdateMapMetadata(DynamicUpdateMapBuilder.Finalizer finalizer,
DynamicUpdateMapBuilder.IDefinitionMatcher matcher, Activity targetActivity)
: base(finalizer, matcher, targetActivity)
{
}
public void SaveOriginalValue(Activity updatedChildActivity, object originalValue)
{
this.ThrowIfDisposed();
bool isReferencedChild;
ValidateOriginalValueAccess(this.TargetActivity, updatedChildActivity, "updatedChildActivity", out isReferencedChild);
if (GetMatch(updatedChildActivity) == null)
{
throw FxTrace.Exception.Argument("updatedChildActivity", SR.CannotSaveOriginalValueForNewActivity(updatedChildActivity));
}
this.Finalizer.SetOriginalValue(updatedChildActivity, originalValue, isReferencedChild);
}
public void SaveOriginalValue(string propertyName, object originalValue)
{
this.ThrowIfDisposed();
if (propertyName == null)
{
throw FxTrace.Exception.ArgumentNull("propertyName");
}
if (this.Finalizer.SavedOriginalValuesForCurrentActivity == null)
{
this.Finalizer.SavedOriginalValuesForCurrentActivity = new Dictionary<string, object>();
}
this.Finalizer.SavedOriginalValuesForCurrentActivity[propertyName] = originalValue;
}
internal static void ValidateOriginalValueAccess(Activity parent, Activity child, string paramName, out bool isReferencedChild)
{
if (child == null)
{
throw FxTrace.Exception.ArgumentNull(paramName);
}
if (!IsPublicOrImportedDelegateOrChild(parent, child, out isReferencedChild))
{
throw FxTrace.Exception.Argument(paramName, SR.CannotSaveOriginalValueForActivity);
}
}
static bool IsPublicOrImportedDelegateOrChild(Activity parent, Activity child, out bool isReferencedChild)
{
isReferencedChild = false;
if (child.Parent == parent)
{
if (child.HandlerOf == null)
{
return child.RelationshipToParent == Activity.RelationshipType.Child ||
child.RelationshipToParent == Activity.RelationshipType.ImportedChild;
}
else
{
return child.HandlerOf.ParentCollectionType == ActivityCollectionType.Public ||
child.HandlerOf.ParentCollectionType == ActivityCollectionType.Imports;
}
}
else if (parent.MemberOf != child.MemberOf)
{
isReferencedChild = true;
bool isImport;
return IsChild(parent, child, out isImport);
}
else
{
return false;
}
}
}
}

View File

@@ -0,0 +1,66 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.Activities.DynamicUpdate
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime;
using System.Text;
enum UpdateBlockedReason
{
NotBlocked = 0,
Custom = 1,
TypeChange,
PublicChildrenChange,
InvalidImplementationMap,
PrivateMembersHaveChanged,
ChangeMatchesInImplementation,
GeneratedAndProvidedMapConflict,
SavedOriginalValuesForReferencedChildren,
AddedIdleExpression,
DelegateArgumentChange,
DynamicArguments,
NewHandle
}
static class UpdateBlockedReasonMessages
{
public static string Get(UpdateBlockedReason reason)
{
switch (reason)
{
case UpdateBlockedReason.Custom:
return SR.BlockedUpdateInsideActivityUpdateError;
case UpdateBlockedReason.TypeChange:
return SR.DUActivityTypeMismatchRuntime;
case UpdateBlockedReason.PublicChildrenChange:
return SR.PublicChildrenChangeBlockDU;
case UpdateBlockedReason.InvalidImplementationMap:
return SR.InvalidImplementationMapRuntime;
case UpdateBlockedReason.PrivateMembersHaveChanged:
return SR.PrivateMembersHaveChanged;
case UpdateBlockedReason.ChangeMatchesInImplementation:
return SR.CannotChangeMatchesInImplementation;
case UpdateBlockedReason.GeneratedAndProvidedMapConflict:
return SR.GeneratedAndProvidedMapConflictRuntime;
case UpdateBlockedReason.SavedOriginalValuesForReferencedChildren:
return SR.CannotSaveOriginalValuesForReferencedChildren;
case UpdateBlockedReason.AddedIdleExpression:
return SR.AddedIdleExpressionBlockDU;
case UpdateBlockedReason.DelegateArgumentChange:
return SR.DelegateArgumentChangeBlockDU;
case UpdateBlockedReason.DynamicArguments:
return SR.NoDynamicArgumentsInActivityDefinitionChangeRuntime;
case UpdateBlockedReason.NewHandle:
return SR.CannotAddHandlesUpdateError;
default:
Fx.Assert("Every block reason should have a corresponding message");
return null;
}
}
}
}

View File

@@ -0,0 +1,212 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.Activities.DynamicUpdate
{
using System;
using System.Activities.Validation;
using System.Collections.Generic;
using System.Linq;
public class UpdateMapMetadata
{
private DynamicUpdateMapBuilder.Finalizer finalizer;
DynamicUpdateMapBuilder.IDefinitionMatcher matcher;
private Activity targetActivity;
private bool isDisposed;
internal UpdateMapMetadata(DynamicUpdateMapBuilder.Finalizer finalizer,
DynamicUpdateMapBuilder.IDefinitionMatcher matcher, Activity targetActivity)
{
this.finalizer = finalizer;
this.matcher = matcher;
this.targetActivity = targetActivity;
this.isDisposed = false;
}
public void AllowUpdateInsideThisActivity()
{
this.ThrowIfDisposed();
this.finalizer.AllowUpdateInsideCurrentActivity = true;
this.finalizer.UpdateDisallowedReason = null;
}
public void DisallowUpdateInsideThisActivity(string reason)
{
this.ThrowIfDisposed();
this.finalizer.AllowUpdateInsideCurrentActivity = false;
this.finalizer.UpdateDisallowedReason = reason;
}
public void AddMatch(Activity updatedChild, Activity originalChild)
{
this.ThrowIfDisposed();
if (updatedChild != null && originalChild != null)
{
this.matcher.AddMatch(updatedChild, originalChild, this.targetActivity);
}
}
public void AddMatch(Variable updatedVariable, Variable originalVariable)
{
this.ThrowIfDisposed();
if (updatedVariable != null && originalVariable != null)
{
this.matcher.AddMatch(updatedVariable, originalVariable, this.targetActivity);
}
}
public Activity GetMatch(Activity updatedChild)
{
this.ThrowIfDisposed();
if (updatedChild != null)
{
Activity result = this.matcher.GetMatch(updatedChild);
if (updatedChild.MemberOf == this.targetActivity.MemberOf)
{
return result;
}
else if (result != null)
{
// GetMatch checks that the activities have the same relationship to declaring parent.
// But for referenced children, we also need to check whether they have the same relationship
// to referencing parent.
// In case of multiple references from the same parent, we'll compare the first one we find.
bool updatedIsImport;
bool updatedIsReferenced = IsChild(this.TargetActivity, updatedChild, out updatedIsImport);
bool updatedIsDelegate = updatedChild.HandlerOf != null;
bool originalIsImport;
bool originalIsReferenced = IsChild(GetMatch(this.TargetActivity), result, out originalIsImport);
bool originalIsDelegate = result.HandlerOf != null;
if (updatedIsReferenced && originalIsReferenced && updatedIsImport == originalIsImport && updatedIsDelegate == originalIsDelegate)
{
return result;
}
}
}
return null;
}
public Variable GetMatch(Variable updatedVariable)
{
this.ThrowIfDisposed();
if (updatedVariable != null && updatedVariable.Owner == this.TargetActivity)
{
Variable result = this.matcher.GetMatch(updatedVariable);
return result;
}
return null;
}
public bool IsReferenceToImportedChild(Activity childActivity)
{
this.ThrowIfDisposed();
if (childActivity == null)
{
return false;
}
Activity parent = (childActivity.RootActivity == this.TargetActivity.RootActivity) ? this.TargetActivity : GetMatch(this.TargetActivity);
return IsReferenceToImportedChild(parent, childActivity);
}
internal bool IsUpdateExplicitlyAllowedOrDisallowed
{
get
{
return this.finalizer.AllowUpdateInsideCurrentActivity.HasValue;
}
}
internal void Dispose()
{
this.isDisposed = true;
}
internal bool AreMatch(Activity updatedActivity, Activity originalActivity)
{
return this.matcher.GetMatch(updatedActivity) == originalActivity;
}
internal bool AreMatch(ActivityDelegate updatedDelegate, ActivityDelegate originalDelegate)
{
if (updatedDelegate.Handler != null && originalDelegate.Handler != null)
{
return this.matcher.GetMatch(updatedDelegate.Handler) == originalDelegate.Handler;
}
else
{
return updatedDelegate.Handler == null && originalDelegate.Handler == null;
}
}
internal DynamicUpdateMapBuilder.Finalizer Finalizer
{
get
{
return this.finalizer;
}
}
internal Activity TargetActivity
{
get
{
return this.targetActivity;
}
}
internal void ThrowIfDisposed()
{
if (this.isDisposed)
{
throw FxTrace.Exception.AsError(new ObjectDisposedException(ToString()));
}
}
internal static bool IsChild(Activity parent, Activity child, out bool isImport)
{
if (child.HandlerOf == null)
{
isImport = parent.ImportedChildren.Contains(child);
return isImport || parent.Children.Contains(child);
}
else
{
isImport = parent.ImportedDelegates.Contains(child.HandlerOf);
return isImport || parent.Delegates.Contains(child.HandlerOf);
}
}
static bool IsReferenceToImportedChild(Activity parent, Activity child)
{
if (child != null && child.MemberOf != parent.MemberOf)
{
IdSpace idSpace = parent.MemberOf.Parent;
while (idSpace != null)
{
if (idSpace == child.MemberOf)
{
return true;
}
else
{
idSpace = idSpace.Parent;
}
}
}
return false;
}
}
}