//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.Workflow.Activities { using System.Collections; using System.Collections.Generic; using System.Reflection; using System.ServiceModel; using System.ServiceModel.Description; using System.Workflow.ComponentModel; using System.Workflow.ComponentModel.Compiler; using System.Workflow.ComponentModel.Design; using System.Globalization; static class ValidationHelper { internal static bool IsValidTypeNameOrIdentifier(string value, bool isTypeName) { bool nextMustBeStartChar = true; bool previousWasNamespaceSeparatorChar = false; if (value.Length == 0) { return false; } // each char must be Lu, Ll, Lt, Lm, Lo, Nd, Mn, Mc, Pc // for (int i = 0; i < value.Length; i++) { char ch = value[i]; UnicodeCategory uc = Char.GetUnicodeCategory(ch); switch (uc) { case UnicodeCategory.UppercaseLetter: // Lu case UnicodeCategory.LowercaseLetter: // Ll case UnicodeCategory.TitlecaseLetter: // Lt case UnicodeCategory.ModifierLetter: // Lm case UnicodeCategory.LetterNumber: // Lm case UnicodeCategory.OtherLetter: // Lo { nextMustBeStartChar = false; previousWasNamespaceSeparatorChar = false; break; } case UnicodeCategory.NonSpacingMark: // Mn case UnicodeCategory.SpacingCombiningMark: // Mc case UnicodeCategory.ConnectorPunctuation: // Pc case UnicodeCategory.DecimalDigitNumber: // Nd { // Underscore is a valid starting character, even though it is a ConnectorPunctuation. if (nextMustBeStartChar && ch != '_') { return false; } nextMustBeStartChar = false; previousWasNamespaceSeparatorChar = false; break; } default: { // We only check the special Type chars for type names. if (isTypeName && !nextMustBeStartChar && !previousWasNamespaceSeparatorChar && IsNamespaceSeparatorChar(ch, ref nextMustBeStartChar)) { previousWasNamespaceSeparatorChar = true; break; } return false; } } } if (isTypeName && previousWasNamespaceSeparatorChar && nextMustBeStartChar) { return false; } return true; } internal static ValidationErrorCollection ValidateAllServiceOperationsImplemented( ValidationManager manager, Activity rootActivity) { if (manager == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("manager"); } if (rootActivity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("rootActivity"); } ValidationErrorCollection validationErrors = new ValidationErrorCollection(); WorkflowServiceAttributes serviceAttributes = (WorkflowServiceAttributes) ReceiveActivity.GetWorkflowServiceAttributes(rootActivity); if (serviceAttributes != null) { if (serviceAttributes.MaxItemsInObjectGraph < 0) { validationErrors.Add(new ValidationError( SR2.GetString( SR2.Error_Validation_InvalidMaxItemsInObjectGraph), WorkflowServicesErrorNumbers.Error_InvalidMaxItemsInObjectGraph, false, "WorkflowServiceAttributes")); } } // verifying that we do not have two contract with the same full name // one contract first // one workflow first // Dictionary implementedTypedContracts = new Dictionary(); Dictionary implementedInferredContracts = new Dictionary(); foreach (ReceiveActivity receiveActivity in GetActivities(rootActivity)) { if (receiveActivity.ServiceOperationInfo == null) { continue; } TypedOperationInfo typedServiceOperation = receiveActivity.ServiceOperationInfo as TypedOperationInfo; OperationInfo inferredServiceOperation = receiveActivity.ServiceOperationInfo as OperationInfo; string typeName = string.Empty; Dictionary toAddTo = implementedInferredContracts; Dictionary toVerify = implementedTypedContracts; if (typedServiceOperation != null) { if (typedServiceOperation.ContractType != null) { typeName = typedServiceOperation.ContractType.FullName; toAddTo = implementedTypedContracts; toVerify = implementedInferredContracts; } } else { typeName = inferredServiceOperation.ContractName; } if (string.IsNullOrEmpty(typeName)) { continue; } if (toVerify.ContainsKey(typeName) && !toAddTo.ContainsKey(typeName)) { validationErrors.Add(new ValidationError( SR2.GetString(SR2.Error_Validation_ContractNameDuplicate, typeName), WorkflowServicesErrorNumbers.Error_ContractNameDuplicate, false)); } if (!toAddTo.ContainsKey(typeName)) { toAddTo.Add(typeName, typeName); } } // collect operations that are implemented // Dictionary implementedServiceOperations = new Dictionary(); foreach (ReceiveActivity receiveActivity in GetActivities(rootActivity)) { OperationInfoBase serviceOperation = receiveActivity.ServiceOperationInfo; if (serviceOperation != null) { Type contractType = serviceOperation.GetContractType(manager); if (contractType == null) { continue; } if (!implementedServiceOperations.ContainsKey(contractType)) { Hashtable serviceOperationHashTable = new Hashtable(); implementedServiceOperations.Add(contractType, serviceOperationHashTable); } MethodInfo methodInfo = serviceOperation.GetMethodInfo(manager); if (methodInfo == null) { continue; } contractType = methodInfo.DeclaringType; if (!implementedServiceOperations.ContainsKey(contractType)) { Hashtable serviceOperationHashTable = new Hashtable(); serviceOperationHashTable.Add(serviceOperation.Name, methodInfo); implementedServiceOperations.Add(contractType, serviceOperationHashTable); } else { if (!implementedServiceOperations[contractType].ContainsKey(serviceOperation.Name)) { implementedServiceOperations[contractType].Add( serviceOperation.Name, methodInfo); } } } } // verifying that we do not have one two methods defining the same operation // verify which operatinos are not implemented and give warnings for each // Dictionary checkedContracts = new Dictionary(); Dictionary notImplementedServiceOperations = new Dictionary(); foreach (Type contractType in implementedServiceOperations.Keys) { Queue interfacesQueue = new Queue(); List contractList = new List(); interfacesQueue.Enqueue(contractType); while (interfacesQueue.Count > 0) { Type currentInterfaceType = interfacesQueue.Dequeue(); if (!contractList.Contains(currentInterfaceType) && currentInterfaceType.IsDefined(typeof(ServiceContractAttribute), false)) { contractList.Add(currentInterfaceType); } foreach (Type baseInteface in currentInterfaceType.GetInterfaces()) { if (!contractList.Contains(baseInteface)) { interfacesQueue.Enqueue(baseInteface); } } } foreach (Type currentContractType in contractList) { if (checkedContracts.ContainsKey(currentContractType)) { continue; } foreach (MethodInfo methodInfo in currentContractType.GetMethods()) { if (methodInfo.DeclaringType != currentContractType) { continue; } if (!ServiceOperationHelpers.IsValidServiceOperation(methodInfo)) { continue; } string operationName = ServiceOperationHelpers.GetOperationName(manager, methodInfo); if (!implementedServiceOperations.ContainsKey(currentContractType)) { validationErrors.Add(new ValidationError( SR2.GetString( SR2.Error_OperationNotImplemented, operationName, currentContractType.FullName), WorkflowServicesErrorNumbers.Error_OperationNotImplemented, true)); if (!notImplementedServiceOperations.ContainsKey(currentContractType)) { Hashtable serviceOperationHashTable = new Hashtable(); serviceOperationHashTable.Add(operationName, methodInfo); notImplementedServiceOperations.Add(currentContractType, serviceOperationHashTable); } else if (notImplementedServiceOperations[currentContractType].ContainsKey(operationName)) { validationErrors.Add(new ValidationError( SR2.GetString( SR2.Error_DuplicatedOperationName, methodInfo.Name, ((MethodInfo) notImplementedServiceOperations[currentContractType][operationName]).Name, currentContractType.FullName), WorkflowServicesErrorNumbers.Error_DuplicatedOperationName, false)); } else { notImplementedServiceOperations[currentContractType].Add( operationName, methodInfo); } } else if (!implementedServiceOperations[currentContractType].ContainsKey(operationName)) { validationErrors.Add(new ValidationError( SR2.GetString( SR2.Error_OperationNotImplemented, operationName, currentContractType.FullName), WorkflowServicesErrorNumbers.Error_OperationNotImplemented, true)); if (!notImplementedServiceOperations.ContainsKey(currentContractType)) { Hashtable serviceOperationHashTable = new Hashtable(); serviceOperationHashTable.Add(operationName, methodInfo); notImplementedServiceOperations.Add(currentContractType, serviceOperationHashTable); } else if (notImplementedServiceOperations[currentContractType].ContainsKey(operationName)) { validationErrors.Add(new ValidationError( SR2.GetString( SR2.Error_DuplicatedOperationName, methodInfo.Name, ((MethodInfo) notImplementedServiceOperations[currentContractType][operationName]).Name, currentContractType.FullName), WorkflowServicesErrorNumbers.Error_DuplicatedOperationName, false)); } else { notImplementedServiceOperations[currentContractType].Add( operationName, methodInfo); } } else if (implementedServiceOperations[currentContractType][operationName] != (object)methodInfo) { validationErrors.Add(new ValidationError( SR2.GetString( SR2.Error_DuplicatedOperationName, methodInfo.Name, ((MethodInfo) implementedServiceOperations[currentContractType][operationName]).Name, currentContractType.FullName), WorkflowServicesErrorNumbers.Error_DuplicatedOperationName, false)); } } checkedContracts.Add(currentContractType, true); } if (validationErrors.Count != 0) { break; } } if (manager.Context[typeof(ServiceOperationsImplementedValidationMarker)] == null) { manager.Context.Append(new ServiceOperationsImplementedValidationMarker()); } return validationErrors; } internal static ValidationErrorCollection ValidateChannelToken( SendActivity activity, ValidationManager manager) { if (activity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("activity"); } if (manager == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("manager"); } ValidationErrorCollection validationErrors = new ValidationErrorCollection(); // validation rules: // // endpoint cannot be null // // Name: !(null ||empty) // OwnerActivityName: any // ConfigurationName: !(null ||empty) || bound // ChannelToken endpoint = activity.ChannelToken; if (endpoint == null) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_ChannelTokenNotSpecified, activity.Name), WorkflowServicesErrorNumbers.Error_ChannelTokenNotSpecified, false, "ChannelToken")); } else { if (string.IsNullOrEmpty(endpoint.Name)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_ChannelTokenNameNotSpecified, activity.Name), WorkflowServicesErrorNumbers.Error_ChannelTokenNameNotSpecified, false, "ChannelToken")); } if (string.IsNullOrEmpty(endpoint.EndpointName) && !endpoint.IsBindingSet(ChannelToken.EndpointNameProperty)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_ChannelTokenConfigurationNameNotSpecified, activity.Name), WorkflowServicesErrorNumbers.Error_ChannelTokenConfigurationNameNotSpecified, false, "ChannelToken")); } if (!string.IsNullOrEmpty(endpoint.OwnerActivityName)) { string qualifiedOwnerName = null; Activity sourceActivity = activity.GetActivityByName(endpoint.OwnerActivityName); if (sourceActivity == null) { sourceActivity = Helpers.ParseActivityForBind(activity, endpoint.OwnerActivityName); } if (sourceActivity != null) { qualifiedOwnerName = sourceActivity.QualifiedName; } Activity replicatorParent = null; Activity parent = activity; bool ownerIsParentOrItself = false; while (parent != null) { // We hardcode Replicator here, not MultiInstance | Concurrent. if (parent is ReplicatorActivity && replicatorParent == null) { replicatorParent = parent; } if (qualifiedOwnerName == parent.QualifiedName) { ownerIsParentOrItself = true; } parent = parent.Parent; } if (!ownerIsParentOrItself) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OwnerActivityNameNotFound, endpoint.OwnerActivityName, activity.Name), WorkflowServicesErrorNumbers.Error_OwnerActivityNameNotFound, false, "ChannelToken")); } } } return validationErrors; } internal static ValidationErrorCollection ValidateContextToken( Activity activity, ContextToken contextToken, ValidationManager manager) { if (activity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("activity"); } if (manager == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("manager"); } ValidationErrorCollection validationErrors = new ValidationErrorCollection(); // having no context token is valid // this means "use RootContext" which is the implicit one. // if (contextToken == null) { return validationErrors; } // validation rules: // // root context: // Name: (RootContext) // OwnerActivityName: null || emtpy // // non root context: // Name: !(RootContext) && !(null ||empty) // OwnerActivityName: any // if (string.IsNullOrEmpty(contextToken.Name)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_ContextTokenNameNotSpecified, activity.Name), WorkflowServicesErrorNumbers.Error_ContextTokenNameNotSpecified, false, "ContextToken")); } if (string.Compare(contextToken.Name, ContextToken.RootContextName, StringComparison.Ordinal) == 0) { if (!string.IsNullOrEmpty(contextToken.OwnerActivityName)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_RootContextScope, activity.Name), WorkflowServicesErrorNumbers.Error_RootContextScope, false, "ContextToken")); } } else if (!string.IsNullOrEmpty(contextToken.OwnerActivityName)) { string qualifiedOwnerName = null; Activity sourceActivity = activity.GetActivityByName(contextToken.OwnerActivityName); if (sourceActivity == null) { sourceActivity = Helpers.ParseActivityForBind(activity, contextToken.OwnerActivityName); } if (sourceActivity != null) { qualifiedOwnerName = sourceActivity.QualifiedName; } Activity replicatorParent = null; Activity parent = activity; bool ownerIsParent = false; while (parent != null) { // We hardcode Replicator here, not MultiInstance | Concurrent. if (parent is ReplicatorActivity && replicatorParent == null) { replicatorParent = parent; } if (qualifiedOwnerName == parent.QualifiedName) { ownerIsParent = true; } parent = parent.Parent; } if (!ownerIsParent) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OwnerActivityNameNotFound, contextToken.OwnerActivityName, activity.Name), WorkflowServicesErrorNumbers.Error_OwnerActivityNameNotFound, false, "ContextToken")); } } return validationErrors; } internal static ValidationErrorCollection ValidateOperationInfo( Activity activity, OperationInfoBase operationInfo, ValidationManager manager) { if (activity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("activity"); } if (operationInfo == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operationInfo"); } if (manager == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("manager"); } ITypeProvider typeProvider = manager.GetService(typeof(ITypeProvider)) as ITypeProvider; if (typeProvider == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException(SR2.GetString(SR2.General_MissingService, typeof(ITypeProvider).Name))); } ValidationErrorCollection validationErrors = new ValidationErrorCollection(); if (string.IsNullOrEmpty(operationInfo.Name)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationNameNotSpecified, activity.Name), WorkflowServicesErrorNumbers.Error_OperationNameNotSpecified, false, "ServiceOperationInfo")); } if (operationInfo is OperationInfo) { OperationInfo currentOperationInfo = operationInfo as OperationInfo; if (!string.IsNullOrEmpty(currentOperationInfo.Name) && !IsValidTypeNameOrIdentifier(currentOperationInfo.Name, false)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationNameInvalid, activity.Name), WorkflowServicesErrorNumbers.Error_OperationNameInvalid, false, "ServiceOperationInfo")); } if (string.IsNullOrEmpty(currentOperationInfo.ContractName)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_ContractNameNotSpecified, activity.Name), WorkflowServicesErrorNumbers.Error_ContractNameNotSpecified, false, "ServiceOperationInfo")); } else if (!IsValidTypeNameOrIdentifier(currentOperationInfo.ContractName, true)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_ContractNameInvalid, activity.Name), WorkflowServicesErrorNumbers.Error_ContractNameInvalid, false, "ServiceOperationInfo")); } bool hasReturnValue = false; foreach (OperationParameterInfo operationParameterInfo in currentOperationInfo.Parameters) { if (operationParameterInfo.Position == -1) { hasReturnValue = true; break; } } int maxPosition = currentOperationInfo.Parameters.Count - (hasReturnValue ? 2 : 1); List parameterIndexs = new List(); List parameterNames = new List(); foreach (OperationParameterInfo operationParameterInfo in currentOperationInfo.Parameters) { if (operationParameterInfo.Position != -1 && operationParameterInfo.Position > maxPosition) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationParameterPosition, operationParameterInfo.Name, currentOperationInfo.Name, currentOperationInfo.ContractName), WorkflowServicesErrorNumbers.Error_OperationParameterPosition, false, "ServiceOperationInfo")); } if (parameterIndexs.Contains(operationParameterInfo.Position)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationParameterPositionDuplicate, operationParameterInfo.Name, currentOperationInfo.Name, currentOperationInfo.ContractName), WorkflowServicesErrorNumbers.Error_OperationParameterPositionDuplicate, false, "ServiceOperationInfo")); } else { parameterIndexs.Add(operationParameterInfo.Position); } if (operationParameterInfo.Position != -1 && !IsValidTypeNameOrIdentifier(operationParameterInfo.Name, false)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationParameterNameInvalid, operationParameterInfo.Name, currentOperationInfo.Name, currentOperationInfo.ContractName), WorkflowServicesErrorNumbers.Error_OperationParameterNameInvalid, false, "ServiceOperationInfo")); } if (parameterNames.Contains(operationParameterInfo.Name)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationParameterNameDuplicate, operationParameterInfo.Name, currentOperationInfo.Name, currentOperationInfo.ContractName), WorkflowServicesErrorNumbers.Error_OperationParameterNameDuplicate, false, "ServiceOperationInfo")); } else { parameterNames.Add(operationParameterInfo.Name); } if (operationParameterInfo.Position != -1 && operationParameterInfo.ParameterType == typeof(void)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationParameterType, operationParameterInfo.Name, currentOperationInfo.Name, currentOperationInfo.ContractName), WorkflowServicesErrorNumbers.Error_OperationParameterType, false, "ServiceOperationInfo")); } } } else { TypedOperationInfo currentOperationInfo = operationInfo as TypedOperationInfo; if (currentOperationInfo.ContractType == null) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_ContractTypeNotSpecified, activity.Name), WorkflowServicesErrorNumbers.Error_ContractTypeNotSpecified, false, "ServiceOperationInfo")); } } // no point validating further as we will not be able to get to the contract type or operation // if (validationErrors.Count > 0) { return validationErrors; } Type contractType = operationInfo.GetContractType(manager); if (contractType == null) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_ContractTypeNotFound, activity.Name), WorkflowServicesErrorNumbers.Error_ContractTypeNotFound, false, "ServiceOperationInfo")); } else if (!contractType.IsInterface) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_ContractTypeNotInterface, contractType.FullName, activity.Name), WorkflowServicesErrorNumbers.Error_ContractTypeNotInterface, false, "ServiceOperationInfo")); } else if (!ServiceOperationHelpers.IsValidServiceContract(contractType)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_ServiceContractAttributeMissing, contractType.FullName), WorkflowServicesErrorNumbers.Error_ServiceContractAttributeMissing, false, "ServiceOperationInfo")); } else { MethodInfo methodInfo = operationInfo.GetMethodInfo(manager); if (methodInfo == null) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationNotInContract, operationInfo.Name, contractType.FullName), WorkflowServicesErrorNumbers.Error_OperationNotInContract, false, "ServiceOperationInfo")); } else if (ServiceOperationHelpers.IsAsyncOperation(manager, methodInfo)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_AsyncPatternOperationNotSupported, operationInfo.Name), WorkflowServicesErrorNumbers.Error_AsyncPatternOperationNotSupported, false, "ServiceOperationInfo")); } else { List parameterIndexs = new List(); List parameterNames = new List(); bool isOneWay = operationInfo.GetIsOneWay(manager); if (isOneWay && methodInfo.ReturnType != typeof(void)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_ReturnTypeInOneWayOperation, operationInfo.Name, contractType.FullName), WorkflowServicesErrorNumbers.Error_ReturnTypeInOneWayOperation, false, "ServiceOperationInfo")); } foreach (ParameterInfo parameter in methodInfo.GetParameters()) { if (parameter.Position >= methodInfo.GetParameters().Length || parameter.Position < 0) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationParameterPosition, parameter.Name, operationInfo.Name, contractType.FullName), WorkflowServicesErrorNumbers.Error_OperationParameterPosition, false, "ServiceOperationInfo")); } if (parameterIndexs.Contains(parameter.Position)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationParameterPositionDuplicate, parameter.Name, operationInfo.Name, contractType.FullName), WorkflowServicesErrorNumbers.Error_OperationParameterPositionDuplicate, false, "ServiceOperationInfo")); } if (!IsValidTypeNameOrIdentifier(parameter.Name, false)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationParameterNameInvalid, parameter.Name, operationInfo.Name, contractType.FullName), WorkflowServicesErrorNumbers.Error_OperationParameterNameInvalid, false, "ServiceOperationInfo")); } if (parameterNames.Contains(parameter.Name)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationParameterNameDuplicate, parameter.Name, operationInfo.Name, contractType.FullName), WorkflowServicesErrorNumbers.Error_OperationParameterNameDuplicate, false, "ServiceOperationInfo")); } if (isOneWay && ((parameter.Attributes & ParameterAttributes.Out) > 0 || parameter.ParameterType.IsByRef)) { validationErrors.Add( new ValidationError(SR2.GetString(SR2.Error_Validation_OperationParameterDirectionInOneWayOperation, parameter.Name, operationInfo.Name, contractType.FullName), WorkflowServicesErrorNumbers.Error_OperationParameterDirectionInOneWayOperation, false, "ServiceOperationInfo")); } parameterIndexs.Add(parameter.Position); parameterNames.Add(parameter.Name); } validationErrors.AddRange( ValidationHelper.ValidateServiceModelAttributes(activity, contractType, methodInfo, manager)); } } return validationErrors; } internal static IEnumerable ValidateParameterBindings( Activity ownerActivity, OperationInfoBase operationInfo, WorkflowParameterBindingCollection parameterBindings, ValidationManager manager) { ValidationErrorCollection validationErrors = new ValidationErrorCollection(); if (ownerActivity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ownerActivity"); } if (operationInfo == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operationInfo"); } if (parameterBindings == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parameterBindings"); } if (manager == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("manager"); } MethodInfo methodInfo = operationInfo.GetMethodInfo(manager); if (methodInfo == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("operationInfo", SR2.GetString(SR2.Error_MethodInfoNotAvailable, ownerActivity.Name)); } bool isOneWayOperation = operationInfo.GetIsOneWay(manager); foreach (ParameterInfo parameter in GetParameterInfo(methodInfo)) { if (!(parameter.IsOut || parameter.Position == -1) || !isOneWayOperation) { string parameterName = (parameter.Position == -1) ? "(ReturnValue)" : parameter.Name; object parameterValue = null; if (parameterBindings.Contains(parameterName)) { if (parameterBindings[parameterName].IsBindingSet(WorkflowParameterBinding.ValueProperty)) { parameterValue = parameterBindings[parameterName].GetBinding( WorkflowParameterBinding.ValueProperty); } else { parameterValue = parameterBindings[parameterName].GetValue( WorkflowParameterBinding.ValueProperty); } if (parameterValue != null) { // Check for access type of the binding. AccessTypes requiredAccess = AccessTypes.Read; if (parameter.IsOut || parameter.ParameterType.IsByRef || parameter.Position == -1) { requiredAccess |= AccessTypes.Write; } PropertyValidationContext propertyValidationContext = new PropertyValidationContext(parameterBindings[parameterName], null, parameterName); BindValidationContext bindValidationContext = new BindValidationContext( parameter.ParameterType.IsByRef ? parameter.ParameterType.GetElementType() : parameter.ParameterType, requiredAccess); validationErrors.AddRange(ValidationHelpers.ValidateProperty( manager, ownerActivity, parameterValue, propertyValidationContext, bindValidationContext)); } } if (!parameterBindings.Contains(parameterName) || parameterValue == null) { if (ownerActivity is SendActivity) { if (parameter.Position != -1) { validationErrors.Add(new ValidationError(SR2.GetString( SR2.Warning_SendActivityParameterBindingMissing, parameterName), WorkflowServicesErrorNumbers.Warning_SendActivityParameterBindingMissing, true, parameterName)); } } else if (ownerActivity is ReceiveActivity) { if (parameter.Position == -1) { validationErrors.Add(new ValidationError(SR2.GetString( SR2.Warning_ReceiveActivityReturnValueBindingMissing, parameterName), WorkflowServicesErrorNumbers.Warning_ReceiveActivityReturnValueBindingMissing, true, parameterName)); } else { validationErrors.Add(new ValidationError(SR2.GetString( SR2.Warning_ReceiveActivityParameterBindingMissing, parameterName), WorkflowServicesErrorNumbers.Warning_ReceiveActivityParameterBindingMissing, true, parameterName)); } } } } } return validationErrors; } internal static IEnumerable ValidateServiceModelAttributes( Activity activity, Type contractType, MethodInfo methodInfo, ValidationManager manager) { if (activity == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("activity"); } if (contractType == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contractType"); } if (methodInfo == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("methodInfo"); } if (manager == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("manager"); } ValidationErrorCollection validationErrors = new ValidationErrorCollection(); object[] serviceContractAttributes = contractType.GetCustomAttributes(typeof(ServiceContractAttribute), true); if (serviceContractAttributes == null || serviceContractAttributes.Length == 0) { validationErrors.Add(new ValidationError(SR2.GetString(SR2.Error_ServiceContractAttributeMissing, contractType.FullName), WorkflowServicesErrorNumbers.Error_ServiceContractAttributeMissing, false, "ServiceOperationInfo")); } else { if (!methodInfo.ReflectedType.IsAssignableFrom(contractType)) { validationErrors.Add(new ValidationError(SR2.GetString(SR2.Error_OperationNotInContract, methodInfo.Name, contractType.FullName), WorkflowServicesErrorNumbers.Error_OperationNotInContract, false, "ServiceOperationInfo")); } else { object[] operationContractAttrributes = methodInfo.GetCustomAttributes(typeof(OperationContractAttribute), true); if (operationContractAttrributes == null || operationContractAttrributes.Length == 0) { validationErrors.Add(new ValidationError(SR2.GetString(SR2.Error_OperationContractAttributeMissing, methodInfo.Name), WorkflowServicesErrorNumbers.Error_OperationContractAttributeMissing, false, "ServiceOperationInfo")); } else if (activity is ReceiveActivity) { ReceiveActivity receiveActivity = activity as ReceiveActivity; SessionMode contractSessionMode = SessionMode.Allowed; if (serviceContractAttributes[0] is ServiceContractAttribute) { contractSessionMode = ((ServiceContractAttribute) serviceContractAttributes[0]).SessionMode; } else if (serviceContractAttributes[0] is AttributeInfoAttribute) { AttributeInfoAttribute attribInfoAttrib = serviceContractAttributes[0] as AttributeInfoAttribute; if (typeof(ServiceContractAttribute).IsAssignableFrom(attribInfoAttrib.AttributeInfo.AttributeType)) { contractSessionMode = ServiceOperationHelpers.GetContractSessionMode(manager, attribInfoAttrib.AttributeInfo); } } if (receiveActivity.CanCreateInstance == true && receiveActivity.ServiceOperationInfo.GetIsOneWay(manager) && contractSessionMode != SessionMode.NotAllowed) { validationErrors.Add(new ValidationError(SR2.GetString(SR2.Error_Validation_OperationIsOneWay, methodInfo.Name), WorkflowServicesErrorNumbers.Error_OperationIsOneWay, false, "CanCreateInstance")); } if (receiveActivity.CanCreateInstance == true && !ServiceOperationHelpers.IsInitiatingOperation(manager, methodInfo)) { validationErrors.Add(new ValidationError(SR2.GetString(SR2.Error_OperationNotInitiating, methodInfo.Name), WorkflowServicesErrorNumbers.Error_OperationNotInitiating, false, "CanCreateInstance")); } } } } return validationErrors; } private static IEnumerable GetActivities(Activity rootActivity) { if (rootActivity == null || !rootActivity.Enabled) { yield break; } if (rootActivity is CompositeActivity) { foreach (Activity activity in ((CompositeActivity) rootActivity).Activities) { if (!activity.Enabled) { continue; } if (activity.GetType() == typeof(T)) { yield return activity; } if (activity is CompositeActivity) { foreach (T requestedType in GetActivities(activity)) { yield return requestedType; } } } } else { if (rootActivity.GetType() == typeof(T)) { yield return rootActivity; } } yield break; } private static List GetParameterInfo(MethodInfo methodInfo) { List parametersInfo = new List(); parametersInfo.AddRange(methodInfo.GetParameters()); if (methodInfo.ReturnParameter != null && methodInfo.ReturnType != typeof(void)) { parametersInfo.Add(methodInfo.ReturnParameter); } return parametersInfo; } private static bool IsNamespaceSeparatorChar(char ch, ref bool nextMustBeStartChar) { switch (ch) { case '.': nextMustBeStartChar = true; return true; } return false; } } }