1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 
5 namespace System.ServiceModel.Activities
6 {
7     using System.Activities;
8     using System.Activities.Validation;
9     using System.Collections;
10     using System.Collections.Generic;
11     using System.Runtime;
12     using System.ServiceModel.Description;
13     using System.Xml;
14     using System.Xml.Linq;
15     using System.Xml.Serialization;
16     using SR2 = System.ServiceModel.Activities.SR;
17 
18     static class ContractValidationHelper
19     {
ValidateReceiveWithReceive(Receive receive1, Receive receive2)20         public static void ValidateReceiveWithReceive(Receive receive1, Receive receive2)
21         {
22             Fx.Assert(receive1 != null && receive2 != null, "Validation argument cannot be null!");
23             Fx.Assert(receive1.OperationName != null, "OperationName cannot be null in Receive");
24             string receiveOperationName = receive1.OperationName;
25 
26             if (receive1.Action != receive2.Action)
27             {
28                 throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentAction(receiveOperationName)));
29             }
30 
31             if (receive1.InternalContent is ReceiveMessageContent && receive2.InternalContent is ReceiveMessageContent)
32             {
33                 ReceiveMessageContent receiveMessage1 = receive1.InternalContent as ReceiveMessageContent;
34                 ReceiveMessageContent receiveMessage2 = receive2.InternalContent as ReceiveMessageContent;
35 
36                 ValidateReceiveWithReceive(receiveMessage1, receiveMessage2, receiveOperationName);
37             }
38             else if (receive1.InternalContent is ReceiveParametersContent && receive2.InternalContent is ReceiveParametersContent)
39             {
40                 ReceiveParametersContent receiveParameters1 = receive1.InternalContent as ReceiveParametersContent;
41                 ReceiveParametersContent receiveParameters2 = receive2.InternalContent as ReceiveParametersContent;
42 
43                 ValidateReceiveParametersWithReceiveParameters(receiveParameters1, receiveParameters2, receiveOperationName);
44             }
45             else
46             {
47                 throw FxTrace.Exception.AsError(new ValidationException(SR2.ReceiveAndReceiveParametersHaveSameName(receiveOperationName)));
48             }
49 
50             if (receive1.HasReply && receive2.HasReply)
51             {
52                 ValidateSendReplyWithSendReply(receive1.FollowingReplies[0], receive2.FollowingReplies[0]);
53             }
54             else if ((receive1.HasReply || receive1.HasFault) != (receive2.HasReply || receive2.HasFault))
55             {
56                 throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentIsOneWay(receiveOperationName)));
57             }
58 
59             if ((receive1.InternalReceive.AdditionalData.IsInsideTransactedReceiveScope != receive2.InternalReceive.AdditionalData.IsInsideTransactedReceiveScope) ||
60                 (receive1.InternalReceive.AdditionalData.IsFirstReceiveOfTransactedReceiveScopeTree != receive2.InternalReceive.AdditionalData.IsFirstReceiveOfTransactedReceiveScopeTree))
61             {
62                 throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentTxProperties(receiveOperationName)));
63             }
64         }
65 
ValidateReceiveWithReceive(ReceiveMessageContent receive1, ReceiveMessageContent receive2, string receiveOperationName)66         static void ValidateReceiveWithReceive(ReceiveMessageContent receive1, ReceiveMessageContent receive2, string receiveOperationName)
67         {
68             Fx.Assert(receive1 != null && receive2 != null, "Validation argument cannot be null!");
69 
70             if (receive1.InternalDeclaredMessageType != receive2.InternalDeclaredMessageType)
71             {
72                 throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentValueType(receiveOperationName)));
73             }
74         }
75 
ValidateReceiveParametersWithReceiveParameters(ReceiveParametersContent receiveParameters1, ReceiveParametersContent receiveParameters2, string receiveOperationName)76         static void ValidateReceiveParametersWithReceiveParameters(ReceiveParametersContent receiveParameters1, ReceiveParametersContent receiveParameters2, string receiveOperationName)
77         {
78             Fx.Assert(receiveParameters1 != null && receiveParameters2 != null, "Validation argument cannot be null!");
79 
80             int count = receiveParameters1.ArgumentNames.Length;
81             if (count != receiveParameters2.ArgumentNames.Length)
82             {
83                 throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceiveParametersWithSameNameButDifferentParameterCount(receiveOperationName)));
84             }
85             for (int i = 0; i < count; i++)
86             {
87                 if (receiveParameters1.ArgumentNames[i] != receiveParameters2.ArgumentNames[i])
88                 {
89                     throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceiveParametersWithSameNameButDifferentParameterName(receiveOperationName)));
90                 }
91                 if (receiveParameters1.ArgumentTypes[i] != receiveParameters2.ArgumentTypes[i])
92                 {
93                     throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceiveParametersWithSameNameButDifferentParameterType(receiveOperationName)));
94                 }
95             }
96         }
97 
ValidateSendReplyWithSendReply(SendReply sendReply1, SendReply sendReply2)98         public static void ValidateSendReplyWithSendReply(SendReply sendReply1, SendReply sendReply2)
99         {
100             Fx.Assert(sendReply1 != null && sendReply2 != null, "Validation argument cannot be null!");
101             Fx.Assert(sendReply1.Request != null, "Request cannot be null in SendReply");
102             string operationName = sendReply1.Request.OperationName;
103 
104             if (sendReply1.Action != sendReply2.Action)
105             {
106                 throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendRepliesWithSameNameButDifferentAction(operationName)));
107             }
108 
109             if (sendReply1.InternalContent is SendMessageContent && sendReply2.InternalContent is SendMessageContent)
110             {
111                 SendMessageContent sendMessage1 = sendReply1.InternalContent as SendMessageContent;
112                 SendMessageContent sendMessage2 = sendReply2.InternalContent as SendMessageContent;
113 
114                 if (sendMessage1.InternalDeclaredMessageType != sendMessage2.InternalDeclaredMessageType)
115                 {
116                     throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendRepliesWithSameNameButDifferentValueType(operationName)));
117                 }
118             }
119             else if (sendReply1.InternalContent is SendParametersContent && sendReply2.InternalContent is SendParametersContent)
120             {
121                 SendParametersContent sendReplyParameters1 = sendReply1.InternalContent as SendParametersContent;
122                 SendParametersContent sendReplyParameters2 = sendReply2.InternalContent as SendParametersContent;
123 
124                 int count = sendReplyParameters1.ArgumentNames.Length;
125                 if (count != sendReplyParameters2.ArgumentNames.Length)
126                 {
127                     throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendReplyParametersWithSameNameButDifferentParameterCount(operationName)));
128                 }
129                 for (int i = 0; i < count; i++)
130                 {
131                     if (sendReplyParameters1.ArgumentNames[i] != sendReplyParameters2.ArgumentNames[i])
132                     {
133                         throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendReplyParametersWithSameNameButDifferentParameterName(operationName)));
134                     }
135                     if (sendReplyParameters1.ArgumentTypes[i] != sendReplyParameters2.ArgumentTypes[i])
136                     {
137                         throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendReplyParametersWithSameNameButDifferentParameterType(operationName)));
138                     }
139                 }
140             }
141             else
142             {
143                 throw FxTrace.Exception.AsError(new ValidationException(SR2.ReceivePairedWithSendReplyAndSendReplyParameters(operationName)));
144             }
145         }
146 
ValidateFault(NativeActivityContext context, OperationDescription targetOperation, string overridingAction, Type faultType)147         public static void ValidateFault(NativeActivityContext context, OperationDescription targetOperation, string overridingAction, Type faultType)
148         {
149             bool faultTypeExistOnContract = false;
150 
151             for (int index = 0; index < targetOperation.Faults.Count; index++)
152             {
153                 FaultDescription targetFault = targetOperation.Faults[index];
154 
155                 if (targetFault.DetailType == faultType)
156                 {
157                     string name = NamingHelper.TypeName(faultType) + TypeLoader.FaultSuffix;
158                     string action = overridingAction ?? NamingHelper.GetMessageAction(targetOperation, false) + name;
159 
160                     if (targetFault.Action != action)
161                     {
162                         Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(action, "Fault Action", targetFault.Action, targetOperation.Name, targetOperation.DeclaringContract.Name)));
163                     }
164                     if (targetFault.Name != NamingHelper.XmlName(name))
165                     {
166                         Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(NamingHelper.XmlName(name), "Fault Name", targetFault.Name, targetOperation.Name, targetOperation.DeclaringContract.Name)));
167                     }
168                     if (targetFault.Namespace != targetOperation.DeclaringContract.Namespace)
169                     {
170                         Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(targetOperation.DeclaringContract.Namespace, "Fault Namespace", targetFault.Namespace, targetOperation.Name, targetOperation.DeclaringContract.Name)));
171                     }
172                     if (targetFault.HasProtectionLevel)
173                     {
174                         Constraint.AddValidationError(context, new ValidationError(SR2.ProtectionLevelNotSupported(targetOperation.Name, targetOperation.DeclaringContract.Name)));
175                     }
176 
177                     // TypeLoader guarantees that fault types are unique in the Faults collection.
178                     faultTypeExistOnContract = true;
179                     break;
180                 }
181             }
182 
183             // It is OK to have fewer fault types than defined on the contract.
184             // But we do not allow workflow to define more fault types than specified on the contract.
185             if (!faultTypeExistOnContract)
186             {
187                 Constraint.AddValidationError(context, new ValidationError(SR2.FaultTypeMismatch(faultType.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
188             }
189         }
190 
ValidateAction(NativeActivityContext context, MessageDescription targetMessage, string overridingAction, OperationDescription targetOperation, bool isResponse)191         public static void ValidateAction(NativeActivityContext context, MessageDescription targetMessage, string overridingAction,
192             OperationDescription targetOperation, bool isResponse)
193         {
194             if (overridingAction == null && targetMessage.Action != NamingHelper.GetMessageAction(targetOperation, isResponse)
195                 || overridingAction != null && overridingAction != targetMessage.Action)
196             {
197                 Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(overridingAction, "Action", targetMessage.Action, targetOperation.Name, targetOperation.DeclaringContract.Name)));
198             }
199         }
200 
ValidateMessageContent(NativeActivityContext context, MessageDescription targetMessage, Type declaredMessageType, SerializerOption serializerOption, OperationDescription operation, bool isResponse)201         public static void ValidateMessageContent(NativeActivityContext context, MessageDescription targetMessage, Type declaredMessageType,
202             SerializerOption serializerOption, OperationDescription operation, bool isResponse)
203         {
204             // MessageContract is allowed only if the WCF contract interface specifies the same message contract type.
205             if (MessageBuilder.IsMessageContract(declaredMessageType))
206             {
207                 // if it is a typed message contract, we just validate the type of the message matches
208                 if (targetMessage.MessageType != null )
209                 {
210                     if (declaredMessageType != targetMessage.MessageType)
211                     {
212                         Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(declaredMessageType.ToString(), "type", targetMessage.MessageType.ToString(), operation.Name, operation.DeclaringContract.Name)));
213                     }
214                 }
215                 else
216                 {
217                     Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(declaredMessageType.ToString(), "type", "null", operation.Name, operation.DeclaringContract.Name)));
218                 }
219                 return;
220             }
221             else if (declaredMessageType != null && declaredMessageType.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
222             {
223                 //This is an untyped message contract
224                 if (targetMessage.Body == null)
225                 {
226                     Constraint.AddValidationError(context, new ValidationError(SR2.BodyCannotBeNull));
227                 }
228                 else
229                 {
230                     if (isResponse)
231                     {
232                         if (targetMessage.Body.ReturnValue == null)
233                         {
234                             Constraint.AddValidationError(context, new ValidationError(SR2.ExtraReturnValue));
235                         }
236                         else if (!targetMessage.Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
237                         {
238                             Constraint.AddValidationError(context, new ValidationError(SR2.FirstParameterDoesnotMatchTheReturnValue(declaredMessageType.FullName, targetMessage.Body.ReturnValue.Type.Name, operation.Name, operation.DeclaringContract.Name)));
239                         }
240                     }
241                     else
242                     {
243                         if (targetMessage.Body.Parts.Count == 0)
244                         {
245                             Constraint.AddValidationError(context, new ValidationError(SR2.ParameterNumberMismatch(declaredMessageType.FullName, operation.Name, operation.DeclaringContract.Name)));
246                         }
247                         else if (targetMessage.Body.Parts.Count > 1)
248                         {
249                             Constraint.AddValidationError(context, new ValidationError(SR2.MessageContentCannotHaveMoreThanOneParameter(operation.Name, operation.DeclaringContract.Name)));
250                         }
251                         else
252                         {
253                             if (!targetMessage.Body.Parts[0].Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
254                             {
255                                 Constraint.AddValidationError(context, new ValidationError(SR2.MessageTypeMismatch(targetMessage.Body.Parts[0].Type.FullName, operation.Name, operation.DeclaringContract.Name)));
256                             }
257                         }
258                     }
259                 }
260 
261                 return;
262             }
263 
264             // In case the WCF contract is a typed message, and the Receive activity also uses ReceiveMessageContent to infer a typed message, the contract needs to be matched
265             Fx.Assert(targetMessage.Body != null, "MessageDescription.Body is never null!");
266 
267             // MessageDescription: Headers, Properties, ProtectionLevel
268             // MessageBodyDescription: ReturnValue, WrapperName, WrapperNamespace
269             // MessagePartDescription: Name, Namespace, Type, ProtectionLevel, Multiple, Index
270             if (targetMessage.Headers.Count > 0)
271             {
272                 Constraint.AddValidationError(context, new ValidationError(SR2.MessageHeaderNotSupported(operation.Name, operation.DeclaringContract.Name)));
273             }
274             if (targetMessage.Properties.Count > 0)
275             {
276                 Constraint.AddValidationError(context, new ValidationError(SR2.MessagePropertyIsNotSupported(operation.Name, operation.DeclaringContract.Name)));
277             }
278             if (targetMessage.HasProtectionLevel)
279             {
280                 Constraint.AddValidationError(context, new ValidationError(SR2.ProtectionLevelIsNotSupported(operation.Name, operation.DeclaringContract.Name)));
281             }
282 
283             if (declaredMessageType == null || declaredMessageType == TypeHelper.VoidType)
284             {
285                 if (!targetMessage.IsVoid)
286                 {
287                     Constraint.AddValidationError(context, new ValidationError(SR2.MessageCannotBeEmpty(operation.Name, operation.DeclaringContract.Name)));
288                 }
289             }
290             else
291             {
292                 string partName;
293                 string partNamespace;
294 
295                 if (serializerOption == SerializerOption.DataContractSerializer)
296                 {
297                     XmlQualifiedName xmlQualifiedName = MessageBuilder.XsdDataContractExporter.GetRootElementName(declaredMessageType);
298                     if (xmlQualifiedName == null)
299                     {
300                         xmlQualifiedName = MessageBuilder.XsdDataContractExporter.GetSchemaTypeName(declaredMessageType);
301                     }
302 
303                     if (!xmlQualifiedName.IsEmpty)
304                     {
305                         partName = xmlQualifiedName.Name;
306                         partNamespace = xmlQualifiedName.Namespace;
307                     }
308                     else
309                     {
310                         // For anonymous type, we assign CLR type name and contract namespace to MessagePartDescription
311                         partName = declaredMessageType.Name;
312                         partNamespace = operation.DeclaringContract.Namespace;
313                     }
314                 }
315                 else
316                 {
317                     XmlTypeMapping xmlTypeMapping = MessageBuilder.XmlReflectionImporter.ImportTypeMapping(declaredMessageType);
318                     partName = xmlTypeMapping.ElementName;
319                     partNamespace = xmlTypeMapping.Namespace;
320                 }
321 
322                 MessagePartDescription targetPart = null;
323 
324                 if (isResponse && targetMessage.Body.ReturnValue != null && targetMessage.Body.ReturnValue.Type != TypeHelper.VoidType)
325                 {
326                     if (targetMessage.Body.Parts.Count > 0)
327                     {
328                         Constraint.AddValidationError(context, new ValidationError(SR2.NotSupportMoreThanOneParametersInMessageContract(operation.Name, operation.DeclaringContract.Name)));
329                     }
330                     targetPart = targetMessage.Body.ReturnValue;
331                 }
332                 else if (!isResponse)
333                 {
334                     if (targetMessage.Body.WrapperName != null && targetMessage.Body.WrapperName != String.Empty)
335                     {
336                         Constraint.AddValidationError(context, new ValidationError(SR2.WrapperNotSupportedInMessageContract(operation.Name, operation.DeclaringContract.Name)));
337                     }
338 
339                     if (targetMessage.Body.WrapperNamespace != null && targetMessage.Body.WrapperNamespace != String.Empty)
340                     {
341                         Constraint.AddValidationError(context, new ValidationError(SR2.WrapperNotSupportedInMessageContract(operation.Name, operation.DeclaringContract.Name)));
342                     }
343 
344                     if (targetMessage.Body.Parts.Count == 0)
345                     {
346                         Constraint.AddValidationError(context, new ValidationError(SR2.ParameterNumberMismatch(declaredMessageType.FullName, operation.Name, operation.DeclaringContract.Name)));
347                     }
348                     else if (targetMessage.Body.Parts.Count > 1)
349                     {
350                         Constraint.AddValidationError(context, new ValidationError(SR2.MessageContentCannotHaveMoreThanOneParameter(operation.Name, operation.DeclaringContract.Name)));
351                     }
352                     else
353                     {
354                         targetPart = targetMessage.Body.Parts[0];
355                     }
356                 }
357 
358                 if (targetPart != null)
359                 {
360                     if (partName != targetPart.Name)
361                     {
362                         Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(partName, "parameter name", targetPart.Name, operation.Name, operation.DeclaringContract.Name)));
363                     }
364                     if (partNamespace != targetPart.Namespace)
365                     {
366                         Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(partNamespace, "parameter namespace", targetPart.Namespace, operation.Name, operation.DeclaringContract.Name)));
367                     }
368                     if (declaredMessageType != targetPart.Type)
369                     {
370                         if (declaredMessageType != null)
371                         {
372                             Constraint.AddValidationError(context, new ValidationError(SR2.ParameterTypeMismatch(declaredMessageType.FullName, targetPart.Type.FullName, operation.Name, operation.DeclaringContract.Name)));
373                         }
374                         else
375                         {
376                             Constraint.AddValidationError(context, new ValidationError(SR2.ParameterTypeMismatch(TypeHelper.VoidType.FullName, targetPart.Type.FullName, operation.Name, operation.DeclaringContract.Name)));
377                         }
378                     }
379                     if (targetPart.HasProtectionLevel)
380                     {
381                         Constraint.AddValidationError(context, new ValidationError(SR2.ProtectionLevelIsNotSupported(operation.Name, operation.DeclaringContract.Name)));
382                     }
383 
384                     // Multiple and Index do not need to be validate because there is only one part in the message.
385                 }
386             }
387         }
388 
ValidateParametersContent(NativeActivityContext context, MessageDescription targetMessage, IDictionary parameters, OperationDescription targetOperation, bool isResponse)389         public static void ValidateParametersContent(NativeActivityContext context, MessageDescription targetMessage, IDictionary parameters,
390             OperationDescription targetOperation, bool isResponse)
391         {
392             // The following properties can only be set via message contract. Therefore, we do not need to validate them here.
393             // MessageDescription: Headers, Properties, ProtectionLevel
394             // MessagePartDescription: Namespace, ProtectionLevel, Multiple, Index
395             MessageBodyDescription targetMessageBody = targetMessage.Body;
396             Fx.Assert(targetMessageBody != null, "MessageDescription.Body is never null!");
397 
398             if (targetMessageBody.WrapperName == null)
399             {
400                 Constraint.AddValidationError(context, new ValidationError(SR2.UnwrappedMessageNotSupported(targetOperation.Name, targetOperation.DeclaringContract.Name)));
401             }
402             if (targetMessageBody.WrapperNamespace == null)
403             {
404                 Constraint.AddValidationError(context, new ValidationError(SR2.UnwrappedMessageNotSupported(targetOperation.Name, targetOperation.DeclaringContract.Name)));
405             }
406 
407             IDictionaryEnumerator iterator = parameters.GetEnumerator();
408             int benchmarkIndex = 0;
409             int hitCount = 0;
410 
411             // Return value needs to be treated specially since ReceiveParametersContent does not have return value on the OM.
412             bool targetHasReturnValue = isResponse && targetMessageBody.ReturnValue != null && targetMessageBody.ReturnValue.Type != TypeHelper.VoidType;
413             if (targetHasReturnValue)
414             {
415                 if (iterator.MoveNext() && (string)iterator.Key == targetMessageBody.ReturnValue.Name)
416                 {
417                     Argument argument = (Argument)iterator.Value;
418                     if (argument != null && argument.ArgumentType != targetMessageBody.ReturnValue.Type)
419                     {
420                         Constraint.AddValidationError(context, new ValidationError(SR2.FirstParameterDoesnotMatchTheReturnValue(argument.ArgumentType.FullName, targetMessageBody.ReturnValue.Type.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
421                     }
422                     hitCount++;
423                 }
424                 else if (parameters.Contains(targetMessageBody.ReturnValue.Name))
425                 {
426                     Constraint.AddValidationError(context, new ValidationError(SR2.ParameterPositionMismatch(targetMessageBody.ReturnValue.Name, targetOperation.Name, targetOperation.DeclaringContract.Name, "0")));
427                     hitCount++;
428                 }
429                 else
430                 {
431                     Constraint.AddValidationError(context, new ValidationError(SR2.ReturnValueMissing(targetMessageBody.ReturnValue.Type.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
432                 }
433 
434                 benchmarkIndex++;
435             }
436 
437             foreach (MessagePartDescription targetPart in targetMessageBody.Parts)
438             {
439                 if (iterator.MoveNext() && (string)iterator.Key == targetPart.Name)
440                 {
441                     Argument argument = (Argument)iterator.Value;
442                     if (argument != null && argument.ArgumentType != targetPart.Type)
443                     {
444                         Constraint.AddValidationError(context, new ValidationError(SR2.ParameterTypeMismatch(targetPart.Name, targetPart.Type.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
445                     }
446                     hitCount++;
447                 }
448                 else if (parameters.Contains(targetPart.Name))
449                 {
450                     Constraint.AddValidationError(context, new ValidationError(SR2.ParameterPositionMismatch(targetPart.Name, targetOperation.Name, targetOperation.DeclaringContract.Name, benchmarkIndex)));
451                     hitCount++;
452                 }
453                 else
454                 {
455                     Constraint.AddValidationError(context, new ValidationError(SR2.MissingParameter(targetPart.Name, targetOperation.Name, targetOperation.DeclaringContract.Name)));
456                 }
457 
458                 benchmarkIndex++;
459             }
460 
461             if (hitCount != parameters.Count)
462             {
463                 foreach (string name in parameters.Keys)
464                 {
465                     XmlQualifiedName qName = new XmlQualifiedName(name, targetOperation.DeclaringContract.Namespace);
466                     if (!targetMessageBody.Parts.Contains(qName))
467                     {
468                         if (!targetHasReturnValue || targetHasReturnValue && name != targetMessageBody.ReturnValue.Name)
469                         {
470                             Constraint.AddValidationError(context, new ValidationError(SR2.ExtraParameter(name, targetOperation.Name, targetOperation.DeclaringContract.Name)));
471                         }
472                     }
473                 }
474             }
475         }
476 
477         // This method trying to validate if the receive message from the operation description should be Parameter content or Message Content
IsReceiveParameterContent(OperationDescription operation)478         public static bool IsReceiveParameterContent(OperationDescription operation)
479         {
480             Fx.Assert(operation != null, "OperationDescription should not be null");
481             MessageDescription message;
482             bool contentIsParameter = false;
483             bool noReceiveMessageContent = false;
484 
485             message = operation.Messages[0];
486 
487             // MessageType is null indicating it is not typed message contract
488             if (message.MessageType == null)
489             {
490                 if (message.Body.Parts != null)
491                 {
492                     if (message.Body.Parts.Count != 0)
493                     {
494                         foreach (MessagePartDescription messagePart in message.Body.Parts)
495                         {
496                             if (messagePart.Index > 0)
497                             {
498                                 contentIsParameter = true;
499                                 break;
500                             }
501                             // Indicating it is a untyped message contract
502                             if (!messagePart.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
503                             {
504                                 contentIsParameter = true;
505                                 break;
506                             }
507                         }
508                     }
509                     else
510                     {
511                         noReceiveMessageContent = true;
512                     }
513                 }
514                 else
515                 {
516                     noReceiveMessageContent = true;
517                 }
518             }
519 
520             if (noReceiveMessageContent)
521             {
522                 if ((message.Body.ReturnValue != null && message.Body.ReturnValue.Type.IsDefined(typeof(MessageContractAttribute), false))
523                     || (message.Body.ReturnValue != null && message.Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message))))
524                 {
525                     contentIsParameter = false;
526                 }
527                 else if (operation.Messages.Count > 1)
528                 {
529                     if (operation.Messages[1].MessageType != null || operation.Messages[1].Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
530                     {
531                         contentIsParameter = false;
532                     }
533                     else
534                     {
535                         contentIsParameter = true;
536                     }
537                 }
538                 else
539                 {
540                     contentIsParameter = true;
541                 }
542             }
543 
544             return contentIsParameter;
545         }
546 
IsSendParameterContent(OperationDescription operation)547         public static bool IsSendParameterContent(OperationDescription operation)
548         {
549             Fx.Assert(operation != null, "OperationDescription should not be null");
550             if (operation.IsOneWay)
551             {
552                 return false;
553             }
554 
555             bool contentIsParameter = false;
556             bool isSendContentEmpty = false;
557             MessageDescription message;
558 
559             if (operation.Messages.Count > 1)
560             {
561                 message = operation.Messages[1];
562                 contentIsParameter = false;
563 
564                 if (message.MessageType == null)
565                 {
566                     if (message.Body.ReturnValue != null && message.Body.ReturnValue.Type != typeof(void))
567                     {
568                         if (!message.Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
569                         {
570                             contentIsParameter = true;
571                         }
572 
573                         isSendContentEmpty = true;
574                     }
575                 }
576 
577                 if (message.MessageType == null)
578                 {
579                     if (message.Body.Parts != null)
580                     {
581                         if (message.Body.Parts.Count > 0)
582                         {
583                             MessagePartDescriptionCollection parts = message.Body.Parts;
584                             foreach (MessagePartDescription messagePart in parts)
585                             {
586                                 if (messagePart.Index >= 0)
587                                 {
588                                     contentIsParameter = true;
589                                     break;
590                                 }
591                                 if (!messagePart.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
592                                 {
593                                     contentIsParameter = true;
594                                 }
595                             }
596                             isSendContentEmpty = true;
597                         }
598                     }
599                 }
600 
601                 if (!isSendContentEmpty)
602                 {
603                     if (message.MessageType != null && message.MessageType.IsDefined(typeof(MessageContractAttribute), false))
604                     {
605                         contentIsParameter = false;
606                     }
607                     else if (operation.Messages[0].MessageType != null)
608                     {
609                         contentIsParameter = false;
610                     }
611                     else if (operation.Messages[0].Body.Parts != null
612                         && operation.Messages[0].Body.Parts.Count == 1
613                         && operation.Messages[0].Body.Parts[0].Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
614                     {
615                         contentIsParameter = false;
616                     }
617                     else
618                     {
619                         contentIsParameter = true;
620                     }
621                 }
622             }
623 
624             return contentIsParameter;
625         }
626 
GetErrorMessageEndpointName(string endpointName)627         public static string GetErrorMessageEndpointName(string endpointName)
628         {
629             return !string.IsNullOrEmpty(endpointName) ? endpointName : SR.NotSpecified;
630         }
631 
GetErrorMessageEndpointServiceContractName(XName serviceContractName)632         public static string GetErrorMessageEndpointServiceContractName(XName serviceContractName)
633         {
634             return serviceContractName != null ? serviceContractName.LocalName : SR.NotSpecified;
635         }
636 
GetErrorMessageOperationName(string operationName)637         public static string GetErrorMessageOperationName(string operationName)
638         {
639             return !string.IsNullOrEmpty(operationName) ? operationName : SR.NotSpecified;
640         }
641     }
642 }
643