File: System\Workflow\Activities\ValidationHelper.cs
Project: ndp\cdf\src\NetFx35\System.WorkflowServices\System.WorkflowServices.csproj (System.WorkflowServices)
//------------------------------------------------------------
// 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<string, string> implementedTypedContracts = new Dictionary<string, string>();
            Dictionary<string, string> implementedInferredContracts = new Dictionary<string, string>();
 
            foreach (ReceiveActivity receiveActivity in GetActivities<ReceiveActivity>(rootActivity))
            {
                if (receiveActivity.ServiceOperationInfo == null)
                {
                    continue;
                }
 
                TypedOperationInfo typedServiceOperation =
                    receiveActivity.ServiceOperationInfo as TypedOperationInfo;
                OperationInfo inferredServiceOperation =
                    receiveActivity.ServiceOperationInfo as OperationInfo;
 
                string typeName = string.Empty;
 
                Dictionary<string, string> toAddTo = implementedInferredContracts;
                Dictionary<string, string> 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<Type, Hashtable> implementedServiceOperations = new Dictionary<Type, Hashtable>();
            foreach (ReceiveActivity receiveActivity in GetActivities<ReceiveActivity>(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<Type, bool> checkedContracts = new Dictionary<Type, bool>();
            Dictionary<Type, Hashtable> notImplementedServiceOperations = new Dictionary<Type, Hashtable>();
 
            foreach (Type contractType in implementedServiceOperations.Keys)
            {
                Queue<Type> interfacesQueue = new Queue<Type>();
                List<Type> contractList = new List<Type>();
 
                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<int> parameterIndexs = new List<int>();
                List<string> parameterNames = new List<string>();
 
                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<int> parameterIndexs = new List<int>();
                    List<string> parameterNames = new List<string>();
 
                    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<ValidationError> 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<ValidationError> 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<T>(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<T>(activity))
                        {
                            yield return requestedType;
                        }
                    }
                }
            }
            else
            {
                if (rootActivity.GetType() == typeof(T))
                {
                    yield return rootActivity;
                }
            }
            yield break;
        }
 
        private static List<ParameterInfo> GetParameterInfo(MethodInfo methodInfo)
        {
            List<ParameterInfo> parametersInfo = new List<ParameterInfo>();
            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;
        }
    }
}