1 //---------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //---------------------------------------------------------------- 4 5 namespace System.ServiceModel.Activities 6 { 7 using System; 8 using System.Activities; 9 using System.Activities.Expressions; 10 using System.Collections.Generic; 11 using System.Collections.ObjectModel; 12 using System.Runtime; 13 using System.Runtime.DurableInstancing; 14 using System.ServiceModel; 15 using System.ServiceModel.Activities.Dispatcher; 16 using System.ServiceModel.Channels; 17 using System.Xaml; 18 using Microsoft.VisualBasic.Activities; 19 using SR2 = System.ServiceModel.Activities.SR; 20 21 static class MessagingActivityHelper 22 { 23 static Type faultExceptionType = typeof(FaultException); 24 static Type faultExceptionGenericType = typeof(FaultException<>); 25 26 public const string ActivityInstanceId = "ActivityInstanceId"; 27 public const string ActivityName = "ActivityName"; 28 public const string ActivityType = "ActivityType"; 29 public const string ActivityTypeExecuteUserCode = "ExecuteUserCode"; 30 public const string MessagingActivityTypeActivityExecution = "MessagingActivityExecution"; 31 public const string E2EActivityId = "E2EActivityId"; 32 public const string MessageId = "MessageId"; 33 public const string ActivityNameWorkflowOperationInvoke = "WorkflowOperationInvoke"; 34 public const string MessageCorrelationReceiveRecord = "MessageCorrelationReceiveRecord"; 35 public const string MessageCorrelationSendRecord = "MessageCorrelationSendRecord"; 36 FixMessageArgument(Argument messageArgument, ArgumentDirection direction, ActivityMetadata metadata)37 public static void FixMessageArgument(Argument messageArgument, ArgumentDirection direction, ActivityMetadata metadata) 38 { 39 Type messageType = (messageArgument == null) ? TypeHelper.ObjectType : messageArgument.ArgumentType; 40 AddRuntimeArgument(messageArgument, "Message", messageType, direction, metadata); 41 } 42 AddRuntimeArgument(Argument messageArgument, string runtimeArgumentName, Type runtimeArgumentType, ArgumentDirection runtimeArgumentDirection, ActivityMetadata metadata)43 public static void AddRuntimeArgument(Argument messageArgument, string runtimeArgumentName, Type runtimeArgumentType, 44 ArgumentDirection runtimeArgumentDirection, ActivityMetadata metadata) 45 { 46 RuntimeArgument argument = new RuntimeArgument(runtimeArgumentName, runtimeArgumentType, runtimeArgumentDirection); 47 metadata.Bind(messageArgument, argument); 48 metadata.AddArgument(argument); 49 } 50 51 // 52 public static IList<T> GetCallbacks<T>(ExecutionProperties executionProperties) 53 where T : class 54 { 55 List<T> list = null; 56 57 if (!executionProperties.IsEmpty) 58 { 59 T temp; 60 foreach (KeyValuePair<string, object> item in executionProperties) 61 { 62 temp = item.Value as T; 63 64 if (temp != null) 65 { 66 if (list == null) 67 { 68 list = new List<T>(); 69 } 70 list.Add(temp); 71 } 72 } 73 } 74 75 return list; 76 } 77 InitializeCorrelationHandles(NativeActivityContext context, CorrelationHandle selectHandle, CorrelationHandle ambientHandle, Collection<CorrelationInitializer> additionalCorrelations, CorrelationKeyCalculator keyCalculator, Message message)78 public static Message InitializeCorrelationHandles(NativeActivityContext context, 79 CorrelationHandle selectHandle, CorrelationHandle ambientHandle, Collection<CorrelationInitializer> additionalCorrelations, 80 CorrelationKeyCalculator keyCalculator, Message message) 81 { 82 InstanceKey instanceKey; 83 ICollection<InstanceKey> additionalKeys; 84 85 // 86 MessageBuffer buffer = message.CreateBufferedCopy(int.MaxValue); 87 if (keyCalculator.CalculateKeys(buffer, message, out instanceKey, out additionalKeys)) 88 { 89 InitializeCorrelationHandles(context, selectHandle, ambientHandle, additionalCorrelations, instanceKey, additionalKeys); 90 } 91 return buffer.CreateMessage(); 92 } 93 InitializeCorrelationHandles(NativeActivityContext context, CorrelationHandle selectHandle, CorrelationHandle ambientHandle, Collection<CorrelationInitializer> additionalCorrelations, MessageProperties messageProperties)94 public static void InitializeCorrelationHandles(NativeActivityContext context, 95 CorrelationHandle selectHandle, CorrelationHandle ambientHandle, Collection<CorrelationInitializer> additionalCorrelations, 96 MessageProperties messageProperties) 97 { 98 CorrelationMessageProperty correlationMessageProperty; 99 if (CorrelationMessageProperty.TryGet(messageProperties, out correlationMessageProperty)) 100 { 101 InitializeCorrelationHandles(context, selectHandle, ambientHandle, additionalCorrelations, 102 correlationMessageProperty.CorrelationKey, correlationMessageProperty.AdditionalKeys); 103 } 104 } 105 106 107 // both receive and send initialize correlations using this method 108 // if selectHandle is not null, we first try to initalize instanceKey with it , else we try to initalize the ambient handle 109 // if ambient handle is not used for initializing instance key , we might use it for initalizing queryCorrelationsInitalizer. 110 111 // SelectHandle usage: 112 // Receive: selectHandle is the correlatesWith handle 113 // SendReply: in case of context based correlation, this is the context handle 114 // Send: in case of context based correlation, this will be the callback handle 115 // ReceiveReply: selectHandle will be always null 116 // Note that only Receive can initialize a content based correlation with a selectHandle (parallel convoy) InitializeCorrelationHandles(NativeActivityContext context, CorrelationHandle selectHandle, CorrelationHandle ambientHandle, Collection<CorrelationInitializer> additionalCorrelations, InstanceKey instanceKey, ICollection<InstanceKey> additionalKeys)117 internal static void InitializeCorrelationHandles(NativeActivityContext context, 118 CorrelationHandle selectHandle, CorrelationHandle ambientHandle, Collection<CorrelationInitializer> additionalCorrelations, 119 InstanceKey instanceKey, ICollection<InstanceKey> additionalKeys) 120 { 121 bool isAmbientHandleUsed = false; 122 if (instanceKey != null && instanceKey.IsValid) 123 { 124 if (selectHandle != null) 125 { 126 selectHandle.InitializeBookmarkScope(context, instanceKey); 127 } 128 else if (ambientHandle != null) 129 { 130 ambientHandle.InitializeBookmarkScope(context, instanceKey); 131 isAmbientHandleUsed = true; 132 } 133 else if (context.DefaultBookmarkScope.IsInitialized) 134 { 135 if (context.DefaultBookmarkScope.Id != instanceKey.Value) 136 { 137 throw FxTrace.Exception.AsError( 138 new InvalidOperationException(SR2.CorrelationHandleInUse(context.DefaultBookmarkScope.Id, instanceKey.Value))); 139 } 140 } 141 else 142 { 143 context.DefaultBookmarkScope.Initialize(context, instanceKey.Value); 144 } 145 } 146 147 if (additionalKeys != null && additionalCorrelations != null) 148 { 149 // The ordering of items in SelectAdditional and additional correlations are the same 150 // Therefore, we assign keys iteratively 151 152 IEnumerator<CorrelationInitializer> enumerator = additionalCorrelations.GetEnumerator(); 153 154 foreach (InstanceKey key in additionalKeys) 155 { 156 Fx.Assert(key != null && key.IsValid, "only valid keys should be passed into InitializeCorrelationHandles"); 157 158 while (enumerator.MoveNext()) 159 { 160 QueryCorrelationInitializer queryCorrelation = enumerator.Current as QueryCorrelationInitializer; 161 if (queryCorrelation != null) 162 { 163 CorrelationHandle handle = (queryCorrelation.CorrelationHandle != null ? queryCorrelation.CorrelationHandle.Get(context) : null); 164 if (handle == null) 165 { 166 if (ambientHandle != null && !isAmbientHandleUsed) 167 { 168 handle = ambientHandle; 169 isAmbientHandleUsed = true; 170 } 171 else 172 { 173 throw FxTrace.Exception.AsError( 174 new InvalidOperationException(SR2.QueryCorrelationInitializerCannotBeInitialized)); 175 } 176 } 177 handle.InitializeBookmarkScope(context, key); 178 break; 179 } 180 } 181 } 182 } 183 } 184 CreateCorrelationCallbackContext(MessageProperties messageProperties)185 public static CorrelationCallbackContext CreateCorrelationCallbackContext(MessageProperties messageProperties) 186 { 187 CallbackContextMessageProperty callbackMessageContextProperty; 188 if (CallbackContextMessageProperty.TryGet(messageProperties, out callbackMessageContextProperty)) 189 { 190 EndpointAddress listenAddress; 191 IDictionary<string, string> context; 192 callbackMessageContextProperty.GetListenAddressAndContext(out listenAddress, out context); 193 194 return new CorrelationCallbackContext 195 { 196 ListenAddress = EndpointAddress10.FromEndpointAddress(listenAddress), 197 Context = context 198 }; 199 } 200 return null; 201 } 202 CreateCorrelationContext(MessageProperties messageProperties)203 public static CorrelationContext CreateCorrelationContext(MessageProperties messageProperties) 204 { 205 ContextMessageProperty contextMessageProperty; 206 if (ContextMessageProperty.TryGet(messageProperties, out contextMessageProperty)) 207 { 208 IDictionary<string, string> context; 209 context = contextMessageProperty.Context; 210 return new CorrelationContext 211 { 212 Context = context 213 }; 214 } 215 return null; 216 } 217 CompareContextEquality(IDictionary<string, string> context1, IDictionary<string, string> context2)218 public static bool CompareContextEquality(IDictionary<string, string> context1, IDictionary<string, string> context2) 219 { 220 if (context1 != context2) 221 { 222 if (context1 == null || 223 context2 == null || 224 context1.Count != context2.Count) 225 { 226 return false; 227 } 228 foreach (KeyValuePair<string, string> pair in context1) 229 { 230 if (!context2.Contains(pair)) 231 { 232 return false; 233 } 234 } 235 } 236 return true; 237 } 238 CreateReplyCorrelatesWith(InArgument<CorrelationHandle> requestCorrelatesWith)239 public static InArgument<CorrelationHandle> CreateReplyCorrelatesWith(InArgument<CorrelationHandle> requestCorrelatesWith) 240 { 241 Fx.Assert(requestCorrelatesWith != null, "Argument cannot be null!"); 242 243 VariableValue<CorrelationHandle> variableValue = requestCorrelatesWith.Expression as VariableValue<CorrelationHandle>; 244 if (variableValue != null) 245 { 246 return new InArgument<CorrelationHandle>(variableValue.Variable); 247 } 248 249 VisualBasicValue<CorrelationHandle> vbvalue = requestCorrelatesWith.Expression as VisualBasicValue<CorrelationHandle>; 250 if (vbvalue != null) 251 { 252 return new InArgument<CorrelationHandle>(new VisualBasicValue<CorrelationHandle>(vbvalue.ExpressionText)); 253 } 254 255 // We use XAML roundtrip to clone expression 256 string xamlStr = XamlServices.Save(requestCorrelatesWith.Expression); 257 object obj = XamlServices.Parse(xamlStr); 258 259 Activity<CorrelationHandle> expression = obj as Activity<CorrelationHandle>; 260 Fx.Assert(expression != null, "Failed to clone CorrelationHandle using XAML roundtrip!"); 261 262 return new InArgument<CorrelationHandle>(expression); 263 264 } 265 ValidateCorrelationInitializer(ActivityMetadata metadata, Collection<CorrelationInitializer> correlationInitializers, bool isReply, string displayName, string operationName)266 public static void ValidateCorrelationInitializer(ActivityMetadata metadata, Collection<CorrelationInitializer> correlationInitializers, bool isReply, string displayName, string operationName) 267 { 268 Fx.Assert(metadata != null, "cannot be null"); 269 270 if (correlationInitializers != null && correlationInitializers.Count > 0) 271 { 272 bool queryInitializerWithEmptyHandle = false; 273 foreach (CorrelationInitializer correlation in correlationInitializers) 274 { 275 if (correlation is RequestReplyCorrelationInitializer && isReply) 276 { 277 // This is a reply, so additional correlations should not have a request reply handle 278 metadata.AddValidationError(SR.ReplyShouldNotIncludeRequestReplyHandle(displayName, operationName)); 279 } 280 281 QueryCorrelationInitializer queryCorrelation = correlation as QueryCorrelationInitializer; 282 if (queryCorrelation != null) 283 { 284 if (queryCorrelation.MessageQuerySet.Count == 0) 285 { 286 metadata.AddValidationError(SR.QueryCorrelationInitializerWithEmptyMessageQuerySet(displayName, operationName)); 287 } 288 } 289 290 if (correlation.CorrelationHandle == null) 291 { 292 if (correlation is QueryCorrelationInitializer) 293 { 294 if (!queryInitializerWithEmptyHandle) 295 { 296 queryInitializerWithEmptyHandle = true; 297 } 298 else 299 { 300 // more than one queryInitializer present, in this case we don't permit null handle 301 metadata.AddValidationError(SR.NullCorrelationHandleInMultipleQueryCorrelation); 302 } 303 } 304 else 305 { 306 metadata.AddValidationError(SR.NullCorrelationHandleInInitializeCorrelation(correlation.GetType().Name)); 307 } 308 } 309 } 310 } 311 } 312 } 313 } 314