643 lines
33 KiB
C#
643 lines
33 KiB
C#
|
//-----------------------------------------------------------------------------
|
|||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
namespace System.ServiceModel.Activities
|
|||
|
{
|
|||
|
using System.Activities;
|
|||
|
using System.Activities.Validation;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Runtime;
|
|||
|
using System.ServiceModel.Description;
|
|||
|
using System.Xml;
|
|||
|
using System.Xml.Linq;
|
|||
|
using System.Xml.Serialization;
|
|||
|
using SR2 = System.ServiceModel.Activities.SR;
|
|||
|
|
|||
|
static class ContractValidationHelper
|
|||
|
{
|
|||
|
public static void ValidateReceiveWithReceive(Receive receive1, Receive receive2)
|
|||
|
{
|
|||
|
Fx.Assert(receive1 != null && receive2 != null, "Validation argument cannot be null!");
|
|||
|
Fx.Assert(receive1.OperationName != null, "OperationName cannot be null in Receive");
|
|||
|
string receiveOperationName = receive1.OperationName;
|
|||
|
|
|||
|
if (receive1.Action != receive2.Action)
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentAction(receiveOperationName)));
|
|||
|
}
|
|||
|
|
|||
|
if (receive1.InternalContent is ReceiveMessageContent && receive2.InternalContent is ReceiveMessageContent)
|
|||
|
{
|
|||
|
ReceiveMessageContent receiveMessage1 = receive1.InternalContent as ReceiveMessageContent;
|
|||
|
ReceiveMessageContent receiveMessage2 = receive2.InternalContent as ReceiveMessageContent;
|
|||
|
|
|||
|
ValidateReceiveWithReceive(receiveMessage1, receiveMessage2, receiveOperationName);
|
|||
|
}
|
|||
|
else if (receive1.InternalContent is ReceiveParametersContent && receive2.InternalContent is ReceiveParametersContent)
|
|||
|
{
|
|||
|
ReceiveParametersContent receiveParameters1 = receive1.InternalContent as ReceiveParametersContent;
|
|||
|
ReceiveParametersContent receiveParameters2 = receive2.InternalContent as ReceiveParametersContent;
|
|||
|
|
|||
|
ValidateReceiveParametersWithReceiveParameters(receiveParameters1, receiveParameters2, receiveOperationName);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.ReceiveAndReceiveParametersHaveSameName(receiveOperationName)));
|
|||
|
}
|
|||
|
|
|||
|
if (receive1.HasReply && receive2.HasReply)
|
|||
|
{
|
|||
|
ValidateSendReplyWithSendReply(receive1.FollowingReplies[0], receive2.FollowingReplies[0]);
|
|||
|
}
|
|||
|
else if ((receive1.HasReply || receive1.HasFault) != (receive2.HasReply || receive2.HasFault))
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentIsOneWay(receiveOperationName)));
|
|||
|
}
|
|||
|
|
|||
|
if ((receive1.InternalReceive.AdditionalData.IsInsideTransactedReceiveScope != receive2.InternalReceive.AdditionalData.IsInsideTransactedReceiveScope) ||
|
|||
|
(receive1.InternalReceive.AdditionalData.IsFirstReceiveOfTransactedReceiveScopeTree != receive2.InternalReceive.AdditionalData.IsFirstReceiveOfTransactedReceiveScopeTree))
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentTxProperties(receiveOperationName)));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void ValidateReceiveWithReceive(ReceiveMessageContent receive1, ReceiveMessageContent receive2, string receiveOperationName)
|
|||
|
{
|
|||
|
Fx.Assert(receive1 != null && receive2 != null, "Validation argument cannot be null!");
|
|||
|
|
|||
|
if (receive1.InternalDeclaredMessageType != receive2.InternalDeclaredMessageType)
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceivesWithSameNameButDifferentValueType(receiveOperationName)));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void ValidateReceiveParametersWithReceiveParameters(ReceiveParametersContent receiveParameters1, ReceiveParametersContent receiveParameters2, string receiveOperationName)
|
|||
|
{
|
|||
|
Fx.Assert(receiveParameters1 != null && receiveParameters2 != null, "Validation argument cannot be null!");
|
|||
|
|
|||
|
int count = receiveParameters1.ArgumentNames.Length;
|
|||
|
if (count != receiveParameters2.ArgumentNames.Length)
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceiveParametersWithSameNameButDifferentParameterCount(receiveOperationName)));
|
|||
|
}
|
|||
|
for (int i = 0; i < count; i++)
|
|||
|
{
|
|||
|
if (receiveParameters1.ArgumentNames[i] != receiveParameters2.ArgumentNames[i])
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceiveParametersWithSameNameButDifferentParameterName(receiveOperationName)));
|
|||
|
}
|
|||
|
if (receiveParameters1.ArgumentTypes[i] != receiveParameters2.ArgumentTypes[i])
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoReceiveParametersWithSameNameButDifferentParameterType(receiveOperationName)));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void ValidateSendReplyWithSendReply(SendReply sendReply1, SendReply sendReply2)
|
|||
|
{
|
|||
|
Fx.Assert(sendReply1 != null && sendReply2 != null, "Validation argument cannot be null!");
|
|||
|
Fx.Assert(sendReply1.Request != null, "Request cannot be null in SendReply");
|
|||
|
string operationName = sendReply1.Request.OperationName;
|
|||
|
|
|||
|
if (sendReply1.Action != sendReply2.Action)
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendRepliesWithSameNameButDifferentAction(operationName)));
|
|||
|
}
|
|||
|
|
|||
|
if (sendReply1.InternalContent is SendMessageContent && sendReply2.InternalContent is SendMessageContent)
|
|||
|
{
|
|||
|
SendMessageContent sendMessage1 = sendReply1.InternalContent as SendMessageContent;
|
|||
|
SendMessageContent sendMessage2 = sendReply2.InternalContent as SendMessageContent;
|
|||
|
|
|||
|
if (sendMessage1.InternalDeclaredMessageType != sendMessage2.InternalDeclaredMessageType)
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendRepliesWithSameNameButDifferentValueType(operationName)));
|
|||
|
}
|
|||
|
}
|
|||
|
else if (sendReply1.InternalContent is SendParametersContent && sendReply2.InternalContent is SendParametersContent)
|
|||
|
{
|
|||
|
SendParametersContent sendReplyParameters1 = sendReply1.InternalContent as SendParametersContent;
|
|||
|
SendParametersContent sendReplyParameters2 = sendReply2.InternalContent as SendParametersContent;
|
|||
|
|
|||
|
int count = sendReplyParameters1.ArgumentNames.Length;
|
|||
|
if (count != sendReplyParameters2.ArgumentNames.Length)
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendReplyParametersWithSameNameButDifferentParameterCount(operationName)));
|
|||
|
}
|
|||
|
for (int i = 0; i < count; i++)
|
|||
|
{
|
|||
|
if (sendReplyParameters1.ArgumentNames[i] != sendReplyParameters2.ArgumentNames[i])
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendReplyParametersWithSameNameButDifferentParameterName(operationName)));
|
|||
|
}
|
|||
|
if (sendReplyParameters1.ArgumentTypes[i] != sendReplyParameters2.ArgumentTypes[i])
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.TwoSendReplyParametersWithSameNameButDifferentParameterType(operationName)));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
throw FxTrace.Exception.AsError(new ValidationException(SR2.ReceivePairedWithSendReplyAndSendReplyParameters(operationName)));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void ValidateFault(NativeActivityContext context, OperationDescription targetOperation, string overridingAction, Type faultType)
|
|||
|
{
|
|||
|
bool faultTypeExistOnContract = false;
|
|||
|
|
|||
|
for (int index = 0; index < targetOperation.Faults.Count; index++)
|
|||
|
{
|
|||
|
FaultDescription targetFault = targetOperation.Faults[index];
|
|||
|
|
|||
|
if (targetFault.DetailType == faultType)
|
|||
|
{
|
|||
|
string name = NamingHelper.TypeName(faultType) + TypeLoader.FaultSuffix;
|
|||
|
string action = overridingAction ?? NamingHelper.GetMessageAction(targetOperation, false) + name;
|
|||
|
|
|||
|
if (targetFault.Action != action)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(action, "Fault Action", targetFault.Action, targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
if (targetFault.Name != NamingHelper.XmlName(name))
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(NamingHelper.XmlName(name), "Fault Name", targetFault.Name, targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
if (targetFault.Namespace != targetOperation.DeclaringContract.Namespace)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(targetOperation.DeclaringContract.Namespace, "Fault Namespace", targetFault.Namespace, targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
if (targetFault.HasProtectionLevel)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ProtectionLevelNotSupported(targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
|
|||
|
// TypeLoader guarantees that fault types are unique in the Faults collection.
|
|||
|
faultTypeExistOnContract = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// It is OK to have fewer fault types than defined on the contract.
|
|||
|
// But we do not allow workflow to define more fault types than specified on the contract.
|
|||
|
if (!faultTypeExistOnContract)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.FaultTypeMismatch(faultType.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void ValidateAction(NativeActivityContext context, MessageDescription targetMessage, string overridingAction,
|
|||
|
OperationDescription targetOperation, bool isResponse)
|
|||
|
{
|
|||
|
if (overridingAction == null && targetMessage.Action != NamingHelper.GetMessageAction(targetOperation, isResponse)
|
|||
|
|| overridingAction != null && overridingAction != targetMessage.Action)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(overridingAction, "Action", targetMessage.Action, targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void ValidateMessageContent(NativeActivityContext context, MessageDescription targetMessage, Type declaredMessageType,
|
|||
|
SerializerOption serializerOption, OperationDescription operation, bool isResponse)
|
|||
|
{
|
|||
|
// MessageContract is allowed only if the WCF contract interface specifies the same message contract type.
|
|||
|
if (MessageBuilder.IsMessageContract(declaredMessageType))
|
|||
|
{
|
|||
|
// if it is a typed message contract, we just validate the type of the message matches
|
|||
|
if (targetMessage.MessageType != null )
|
|||
|
{
|
|||
|
if (declaredMessageType != targetMessage.MessageType)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(declaredMessageType.ToString(), "type", targetMessage.MessageType.ToString(), operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(declaredMessageType.ToString(), "type", "null", operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
else if (declaredMessageType != null && declaredMessageType.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
|
|||
|
{
|
|||
|
//This is an untyped message contract
|
|||
|
if (targetMessage.Body == null)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.BodyCannotBeNull));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (isResponse)
|
|||
|
{
|
|||
|
if (targetMessage.Body.ReturnValue == null)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ExtraReturnValue));
|
|||
|
}
|
|||
|
else if (!targetMessage.Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.FirstParameterDoesnotMatchTheReturnValue(declaredMessageType.FullName, targetMessage.Body.ReturnValue.Type.Name, operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (targetMessage.Body.Parts.Count == 0)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ParameterNumberMismatch(declaredMessageType.FullName, operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
else if (targetMessage.Body.Parts.Count > 1)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.MessageContentCannotHaveMoreThanOneParameter(operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!targetMessage.Body.Parts[0].Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.MessageTypeMismatch(targetMessage.Body.Parts[0].Type.FullName, operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// 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
|
|||
|
Fx.Assert(targetMessage.Body != null, "MessageDescription.Body is never null!");
|
|||
|
|
|||
|
// MessageDescription: Headers, Properties, ProtectionLevel
|
|||
|
// MessageBodyDescription: ReturnValue, WrapperName, WrapperNamespace
|
|||
|
// MessagePartDescription: Name, Namespace, Type, ProtectionLevel, Multiple, Index
|
|||
|
if (targetMessage.Headers.Count > 0)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.MessageHeaderNotSupported(operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
if (targetMessage.Properties.Count > 0)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.MessagePropertyIsNotSupported(operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
if (targetMessage.HasProtectionLevel)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ProtectionLevelIsNotSupported(operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
|
|||
|
if (declaredMessageType == null || declaredMessageType == TypeHelper.VoidType)
|
|||
|
{
|
|||
|
if (!targetMessage.IsVoid)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.MessageCannotBeEmpty(operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
string partName;
|
|||
|
string partNamespace;
|
|||
|
|
|||
|
if (serializerOption == SerializerOption.DataContractSerializer)
|
|||
|
{
|
|||
|
XmlQualifiedName xmlQualifiedName = MessageBuilder.XsdDataContractExporter.GetRootElementName(declaredMessageType);
|
|||
|
if (xmlQualifiedName == null)
|
|||
|
{
|
|||
|
xmlQualifiedName = MessageBuilder.XsdDataContractExporter.GetSchemaTypeName(declaredMessageType);
|
|||
|
}
|
|||
|
|
|||
|
if (!xmlQualifiedName.IsEmpty)
|
|||
|
{
|
|||
|
partName = xmlQualifiedName.Name;
|
|||
|
partNamespace = xmlQualifiedName.Namespace;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// For anonymous type, we assign CLR type name and contract namespace to MessagePartDescription
|
|||
|
partName = declaredMessageType.Name;
|
|||
|
partNamespace = operation.DeclaringContract.Namespace;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
XmlTypeMapping xmlTypeMapping = MessageBuilder.XmlReflectionImporter.ImportTypeMapping(declaredMessageType);
|
|||
|
partName = xmlTypeMapping.ElementName;
|
|||
|
partNamespace = xmlTypeMapping.Namespace;
|
|||
|
}
|
|||
|
|
|||
|
MessagePartDescription targetPart = null;
|
|||
|
|
|||
|
if (isResponse && targetMessage.Body.ReturnValue != null && targetMessage.Body.ReturnValue.Type != TypeHelper.VoidType)
|
|||
|
{
|
|||
|
if (targetMessage.Body.Parts.Count > 0)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.NotSupportMoreThanOneParametersInMessageContract(operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
targetPart = targetMessage.Body.ReturnValue;
|
|||
|
}
|
|||
|
else if (!isResponse)
|
|||
|
{
|
|||
|
if (targetMessage.Body.WrapperName != null && targetMessage.Body.WrapperName != String.Empty)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.WrapperNotSupportedInMessageContract(operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
|
|||
|
if (targetMessage.Body.WrapperNamespace != null && targetMessage.Body.WrapperNamespace != String.Empty)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.WrapperNotSupportedInMessageContract(operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
|
|||
|
if (targetMessage.Body.Parts.Count == 0)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ParameterNumberMismatch(declaredMessageType.FullName, operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
else if (targetMessage.Body.Parts.Count > 1)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.MessageContentCannotHaveMoreThanOneParameter(operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
targetPart = targetMessage.Body.Parts[0];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (targetPart != null)
|
|||
|
{
|
|||
|
if (partName != targetPart.Name)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(partName, "parameter name", targetPart.Name, operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
if (partNamespace != targetPart.Namespace)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.PropertyMismatch(partNamespace, "parameter namespace", targetPart.Namespace, operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
if (declaredMessageType != targetPart.Type)
|
|||
|
{
|
|||
|
if (declaredMessageType != null)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ParameterTypeMismatch(declaredMessageType.FullName, targetPart.Type.FullName, operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ParameterTypeMismatch(TypeHelper.VoidType.FullName, targetPart.Type.FullName, operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
}
|
|||
|
if (targetPart.HasProtectionLevel)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ProtectionLevelIsNotSupported(operation.Name, operation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
|
|||
|
// Multiple and Index do not need to be validate because there is only one part in the message.
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void ValidateParametersContent(NativeActivityContext context, MessageDescription targetMessage, IDictionary parameters,
|
|||
|
OperationDescription targetOperation, bool isResponse)
|
|||
|
{
|
|||
|
// The following properties can only be set via message contract. Therefore, we do not need to validate them here.
|
|||
|
// MessageDescription: Headers, Properties, ProtectionLevel
|
|||
|
// MessagePartDescription: Namespace, ProtectionLevel, Multiple, Index
|
|||
|
MessageBodyDescription targetMessageBody = targetMessage.Body;
|
|||
|
Fx.Assert(targetMessageBody != null, "MessageDescription.Body is never null!");
|
|||
|
|
|||
|
if (targetMessageBody.WrapperName == null)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.UnwrappedMessageNotSupported(targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
if (targetMessageBody.WrapperNamespace == null)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.UnwrappedMessageNotSupported(targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
|
|||
|
IDictionaryEnumerator iterator = parameters.GetEnumerator();
|
|||
|
int benchmarkIndex = 0;
|
|||
|
int hitCount = 0;
|
|||
|
|
|||
|
// Return value needs to be treated specially since ReceiveParametersContent does not have return value on the OM.
|
|||
|
bool targetHasReturnValue = isResponse && targetMessageBody.ReturnValue != null && targetMessageBody.ReturnValue.Type != TypeHelper.VoidType;
|
|||
|
if (targetHasReturnValue)
|
|||
|
{
|
|||
|
if (iterator.MoveNext() && (string)iterator.Key == targetMessageBody.ReturnValue.Name)
|
|||
|
{
|
|||
|
Argument argument = (Argument)iterator.Value;
|
|||
|
if (argument != null && argument.ArgumentType != targetMessageBody.ReturnValue.Type)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.FirstParameterDoesnotMatchTheReturnValue(argument.ArgumentType.FullName, targetMessageBody.ReturnValue.Type.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
hitCount++;
|
|||
|
}
|
|||
|
else if (parameters.Contains(targetMessageBody.ReturnValue.Name))
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ParameterPositionMismatch(targetMessageBody.ReturnValue.Name, targetOperation.Name, targetOperation.DeclaringContract.Name, "0")));
|
|||
|
hitCount++;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ReturnValueMissing(targetMessageBody.ReturnValue.Type.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
|
|||
|
benchmarkIndex++;
|
|||
|
}
|
|||
|
|
|||
|
foreach (MessagePartDescription targetPart in targetMessageBody.Parts)
|
|||
|
{
|
|||
|
if (iterator.MoveNext() && (string)iterator.Key == targetPart.Name)
|
|||
|
{
|
|||
|
Argument argument = (Argument)iterator.Value;
|
|||
|
if (argument != null && argument.ArgumentType != targetPart.Type)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ParameterTypeMismatch(targetPart.Name, targetPart.Type.FullName, targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
hitCount++;
|
|||
|
}
|
|||
|
else if (parameters.Contains(targetPart.Name))
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ParameterPositionMismatch(targetPart.Name, targetOperation.Name, targetOperation.DeclaringContract.Name, benchmarkIndex)));
|
|||
|
hitCount++;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.MissingParameter(targetPart.Name, targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
|
|||
|
benchmarkIndex++;
|
|||
|
}
|
|||
|
|
|||
|
if (hitCount != parameters.Count)
|
|||
|
{
|
|||
|
foreach (string name in parameters.Keys)
|
|||
|
{
|
|||
|
XmlQualifiedName qName = new XmlQualifiedName(name, targetOperation.DeclaringContract.Namespace);
|
|||
|
if (!targetMessageBody.Parts.Contains(qName))
|
|||
|
{
|
|||
|
if (!targetHasReturnValue || targetHasReturnValue && name != targetMessageBody.ReturnValue.Name)
|
|||
|
{
|
|||
|
Constraint.AddValidationError(context, new ValidationError(SR2.ExtraParameter(name, targetOperation.Name, targetOperation.DeclaringContract.Name)));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// This method trying to validate if the receive message from the operation description should be Parameter content or Message Content
|
|||
|
public static bool IsReceiveParameterContent(OperationDescription operation)
|
|||
|
{
|
|||
|
Fx.Assert(operation != null, "OperationDescription should not be null");
|
|||
|
MessageDescription message;
|
|||
|
bool contentIsParameter = false;
|
|||
|
bool noReceiveMessageContent = false;
|
|||
|
|
|||
|
message = operation.Messages[0];
|
|||
|
|
|||
|
// MessageType is null indicating it is not typed message contract
|
|||
|
if (message.MessageType == null)
|
|||
|
{
|
|||
|
if (message.Body.Parts != null)
|
|||
|
{
|
|||
|
if (message.Body.Parts.Count != 0)
|
|||
|
{
|
|||
|
foreach (MessagePartDescription messagePart in message.Body.Parts)
|
|||
|
{
|
|||
|
if (messagePart.Index > 0)
|
|||
|
{
|
|||
|
contentIsParameter = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
// Indicating it is a untyped message contract
|
|||
|
if (!messagePart.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
|
|||
|
{
|
|||
|
contentIsParameter = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
noReceiveMessageContent = true;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
noReceiveMessageContent = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (noReceiveMessageContent)
|
|||
|
{
|
|||
|
if ((message.Body.ReturnValue != null && message.Body.ReturnValue.Type.IsDefined(typeof(MessageContractAttribute), false))
|
|||
|
|| (message.Body.ReturnValue != null && message.Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message))))
|
|||
|
{
|
|||
|
contentIsParameter = false;
|
|||
|
}
|
|||
|
else if (operation.Messages.Count > 1)
|
|||
|
{
|
|||
|
if (operation.Messages[1].MessageType != null || operation.Messages[1].Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
|
|||
|
{
|
|||
|
contentIsParameter = false;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
contentIsParameter = true;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
contentIsParameter = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return contentIsParameter;
|
|||
|
}
|
|||
|
|
|||
|
public static bool IsSendParameterContent(OperationDescription operation)
|
|||
|
{
|
|||
|
Fx.Assert(operation != null, "OperationDescription should not be null");
|
|||
|
if (operation.IsOneWay)
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
bool contentIsParameter = false;
|
|||
|
bool isSendContentEmpty = false;
|
|||
|
MessageDescription message;
|
|||
|
|
|||
|
if (operation.Messages.Count > 1)
|
|||
|
{
|
|||
|
message = operation.Messages[1];
|
|||
|
contentIsParameter = false;
|
|||
|
|
|||
|
if (message.MessageType == null)
|
|||
|
{
|
|||
|
if (message.Body.ReturnValue != null && message.Body.ReturnValue.Type != typeof(void))
|
|||
|
{
|
|||
|
if (!message.Body.ReturnValue.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
|
|||
|
{
|
|||
|
contentIsParameter = true;
|
|||
|
}
|
|||
|
|
|||
|
isSendContentEmpty = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (message.MessageType == null)
|
|||
|
{
|
|||
|
if (message.Body.Parts != null)
|
|||
|
{
|
|||
|
if (message.Body.Parts.Count > 0)
|
|||
|
{
|
|||
|
MessagePartDescriptionCollection parts = message.Body.Parts;
|
|||
|
foreach (MessagePartDescription messagePart in parts)
|
|||
|
{
|
|||
|
if (messagePart.Index >= 0)
|
|||
|
{
|
|||
|
contentIsParameter = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
if (!messagePart.Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
|
|||
|
{
|
|||
|
contentIsParameter = true;
|
|||
|
}
|
|||
|
}
|
|||
|
isSendContentEmpty = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!isSendContentEmpty)
|
|||
|
{
|
|||
|
if (message.MessageType != null && message.MessageType.IsDefined(typeof(MessageContractAttribute), false))
|
|||
|
{
|
|||
|
contentIsParameter = false;
|
|||
|
}
|
|||
|
else if (operation.Messages[0].MessageType != null)
|
|||
|
{
|
|||
|
contentIsParameter = false;
|
|||
|
}
|
|||
|
else if (operation.Messages[0].Body.Parts != null
|
|||
|
&& operation.Messages[0].Body.Parts.Count == 1
|
|||
|
&& operation.Messages[0].Body.Parts[0].Type.IsAssignableFrom(typeof(System.ServiceModel.Channels.Message)))
|
|||
|
{
|
|||
|
contentIsParameter = false;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
contentIsParameter = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return contentIsParameter;
|
|||
|
}
|
|||
|
|
|||
|
public static string GetErrorMessageEndpointName(string endpointName)
|
|||
|
{
|
|||
|
return !string.IsNullOrEmpty(endpointName) ? endpointName : SR.NotSpecified;
|
|||
|
}
|
|||
|
|
|||
|
public static string GetErrorMessageEndpointServiceContractName(XName serviceContractName)
|
|||
|
{
|
|||
|
return serviceContractName != null ? serviceContractName.LocalName : SR.NotSpecified;
|
|||
|
}
|
|||
|
|
|||
|
public static string GetErrorMessageOperationName(string operationName)
|
|||
|
{
|
|||
|
return !string.IsNullOrEmpty(operationName) ? operationName : SR.NotSpecified;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|