public override AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            UIHintAttribute uiHintAttribute = (UIHintAttribute)attribute;

            // We override this build method only to deal with the control parameters
            // which cannot be generated by the standard builder.  If there are no
            // control parameters, let the standard builder do the work.
            IDictionary <string, object> controlParams = uiHintAttribute.ControlParameters;

            if (controlParams == null || controlParams.Count == 0)
            {
                return(base.GetAttributeDeclaration(attribute));
            }

            AttributeDeclaration attributeDeclaration = new AttributeDeclaration(typeof(UIHintAttribute));

            // UIHint[("uiHint", "presentationLayer")]
            attributeDeclaration.ConstructorArguments.Add(uiHintAttribute.UIHint);
            attributeDeclaration.ConstructorArguments.Add(uiHintAttribute.PresentationLayer);

            // UIHint[("uiHint", "presentationLayer", ...)] -- fill in all the optional params from control parameters
            foreach (KeyValuePair <string, object> item in controlParams)
            {
                attributeDeclaration.ConstructorArguments.Add(item.Key);
                attributeDeclaration.ConstructorArguments.Add(item.Value);
            }

            return(attributeDeclaration);
        }
        public override AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            UIHintAttribute uiHintAttribute = (UIHintAttribute)attribute;

            // We override this build method only to deal with the control parameters
            // which cannot be generated by the standard builder.  If there are no
            // control parameters, let the standard builder do the work.
            IDictionary<string, object> controlParams = uiHintAttribute.ControlParameters;
            if (controlParams == null || controlParams.Count == 0)
            {
                return base.GetAttributeDeclaration(attribute);
            }

            AttributeDeclaration attributeDeclaration = new AttributeDeclaration(typeof(UIHintAttribute));

            // UIHint[("uiHint", "presentationLayer")]
            attributeDeclaration.ConstructorArguments.Add(uiHintAttribute.UIHint);
            attributeDeclaration.ConstructorArguments.Add(uiHintAttribute.PresentationLayer);

            // UIHint[("uiHint", "presentationLayer", ...)] -- fill in all the optional params from control parameters
            foreach (KeyValuePair<string, object> item in controlParams)
            {
                attributeDeclaration.ConstructorArguments.Add(item.Key);
                attributeDeclaration.ConstructorArguments.Add(item.Value);
            }

            return attributeDeclaration;
        }
예제 #3
0
        /// <summary>
        /// Returns a representative <see cref="AttributeDeclaration"/> for a given <see cref="Attribute"/> instance.
        /// </summary>
        /// <param name="attribute">An attribute instance to create a <see cref="AttributeDeclaration"/> for.</param>
        /// <returns>A <see cref="AttributeDeclaration"/> representing the <paramref name="attribute"/>.</returns>
        public override AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            ValidationAttribute  validationAttribute  = (ValidationAttribute)attribute;
            AttributeDeclaration attributeDeclaration = base.GetAttributeDeclaration(attribute);

            RegisterSharedResources(validationAttribute, attributeDeclaration);

            return(attributeDeclaration);
        }
        /// <summary>
        /// Registers any resource type used by the given <see cref="ValidationAttribute"/> that must be shared and 
        /// have a named resource property available.
        /// </summary>
        /// <param name="validationAttribute">The <see cref="ValidationAttribute"/> instance to check.</param>
        /// <param name="attributeDeclaration">The <see cref="AttributeDeclaration"/> used to describe <paramref name="validationAttribute"/>.</param>
        protected static void RegisterSharedResources(ValidationAttribute validationAttribute, AttributeDeclaration attributeDeclaration)
        {
            string resourceName = validationAttribute.ErrorMessageResourceName;
            Type resourceType = validationAttribute.ErrorMessageResourceType;

            bool isEmptyResourceName = string.IsNullOrEmpty(resourceName);
            Type validateionAttributeType = validationAttribute.GetType();

            // At least one is non-null.  If the other is null, we have a problem.  We need both to
            // localize properly, or neither to signal we use the static string version
            if ((resourceType != null && isEmptyResourceName) || (resourceType == null && !isEmptyResourceName))
            {
                string resourceTypeMessage = resourceType != null ? resourceType.Name : Resource.Unspecified_Resource_Element;
                string resourceNameMessage = isEmptyResourceName ? Resource.Unspecified_Resource_Element : resourceName;

                attributeDeclaration.Errors.Add(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_ValidationAttribute_Requires_ResourceType_And_Name,
                        validateionAttributeType,
                        resourceTypeMessage,
                        resourceNameMessage));
                return;
            }

            if (resourceType != null)
            {
                PropertyInfo resourceProperty = resourceType.GetProperty(resourceName);

                if (resourceProperty == null)
                {
                    attributeDeclaration.Errors.Add(
                        string.Format(
                            CultureInfo.CurrentCulture,
                            Resource.ClientCodeGen_ValidationAttribute_ResourcePropertyNotFound,
                            validateionAttributeType,
                            resourceName,
                            resourceType));
                }
                else
                {
                    attributeDeclaration.RequiredTypes.Add(resourceType);
                    attributeDeclaration.RequiredProperties.Add(resourceProperty);
                }
            }
        }
예제 #5
0
        public override AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            RangeAttribute       rangeAttribute       = (RangeAttribute)attribute;
            AttributeDeclaration attributeDeclaration = new AttributeDeclaration(typeof(RangeAttribute));

            // Register required resources for this ValidationAttribute
            RegisterSharedResources(rangeAttribute, attributeDeclaration);

            bool declareOperandType =
                rangeAttribute.Minimum == null ||
                rangeAttribute.Minimum.GetType() == typeof(string);

            // OperandType
            if (declareOperandType)
            {
                attributeDeclaration.ConstructorArguments.Add(rangeAttribute.OperandType);
            }

            // Minimum
            attributeDeclaration.ConstructorArguments.Add(rangeAttribute.Minimum);
            // Maximum
            attributeDeclaration.ConstructorArguments.Add(rangeAttribute.Maximum);

            // ErrorMessage
            if (rangeAttribute.ErrorMessage != null)
            {
                attributeDeclaration.NamedParameters.Add("ErrorMessage", rangeAttribute.ErrorMessage);
            }

            // ErrorMessageResourceType
            if (rangeAttribute.ErrorMessageResourceType != null)
            {
                attributeDeclaration.NamedParameters.Add("ErrorMessageResourceType", rangeAttribute.ErrorMessageResourceType);
            }

            // ErrorMessageResourceName
            if (rangeAttribute.ErrorMessageResourceName != null)
            {
                attributeDeclaration.NamedParameters.Add("ErrorMessageResourceName", rangeAttribute.ErrorMessageResourceName);
            }

            return(attributeDeclaration);
        }
예제 #6
0
        public override AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            CustomValidationAttribute cva = (CustomValidationAttribute)attribute;

            // Our convention is that parameter validation in the CVA occurs when it is
            // first used.  Simply ask the attribute to produce an error message, as this
            // will trigger an InvalidOperationException if the attribute is ill-formed
            cva.FormatErrorMessage(string.Empty);

            // Delegate to the base implementation to generate the attribute.
            // Note that the base implementation already checks that Types are
            // shared so we do not perform that check here.
            AttributeDeclaration attributeDeclaration = base.GetAttributeDeclaration(attribute);

            attributeDeclaration.RequiredTypes.Add(cva.ValidatorType);
            attributeDeclaration.RequiredMethods.Add(cva.ValidatorType.GetMethod(cva.Method));

            return(attributeDeclaration);
        }
        public override AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            RangeAttribute rangeAttribute = (RangeAttribute)attribute;
            AttributeDeclaration attributeDeclaration = new AttributeDeclaration(typeof(RangeAttribute));

            // Register required resources for this ValidationAttribute
            RegisterSharedResources(rangeAttribute, attributeDeclaration);

            bool declareOperandType =
                rangeAttribute.Minimum == null ||
                rangeAttribute.Minimum.GetType() == typeof(string);

            // OperandType
            if (declareOperandType)
            {
                attributeDeclaration.ConstructorArguments.Add(rangeAttribute.OperandType);
            }

            // Minimum
            attributeDeclaration.ConstructorArguments.Add(rangeAttribute.Minimum);
            // Maximum
            attributeDeclaration.ConstructorArguments.Add(rangeAttribute.Maximum);

            // ErrorMessage
            if (rangeAttribute.ErrorMessage != null)
            {
                attributeDeclaration.NamedParameters.Add("ErrorMessage", rangeAttribute.ErrorMessage);
            }

            // ErrorMessageResourceType
            if (rangeAttribute.ErrorMessageResourceType != null)
            {
                attributeDeclaration.NamedParameters.Add("ErrorMessageResourceType", rangeAttribute.ErrorMessageResourceType);
            }

            // ErrorMessageResourceName
            if (rangeAttribute.ErrorMessageResourceName != null)
            {
                attributeDeclaration.NamedParameters.Add("ErrorMessageResourceName", rangeAttribute.ErrorMessageResourceName);
            }

            return attributeDeclaration;
        }
        /// <summary>
        /// Generates a <see cref="AttributeDeclaration"/> representation of an
        /// <see cref="EditableAttribute"/> instance.
        /// </summary>
        /// <param name="attribute">The <see cref="EditableAttribute"/>.</param>
        /// <returns>A <see cref="AttributeDeclaration"/> representation of
        /// <paramref name="attribute"/>.</returns>
        /// <exception cref="InvalidCastException">if <paramref name="attribute"/> is
        /// not a <see cref="EditableAttribute"/>.</exception>
        public override AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            EditableAttribute    editableAttribute    = (EditableAttribute)attribute;
            AttributeDeclaration attributeDeclaration = new AttributeDeclaration(typeof(EditableAttribute));

            bool allowEdit         = editableAttribute.AllowEdit;
            bool allowInitialValue = editableAttribute.AllowInitialValue;

            // [EditableAttribute( {true|false} )]
            attributeDeclaration.ConstructorArguments.Add(allowEdit);

            // Only add the 'AllowInitialValue' parameter if its value does not match with
            // the 'AllowEdit' value.  See the documentation of EditableAttribute for more info.
            if (allowEdit != allowInitialValue)
            {
                // [EditableAttribute( {true|false}, AllowInitialValue = {true|false} )]
                attributeDeclaration.NamedParameters.Add("AllowInitialValue", allowInitialValue);
            }

            return(attributeDeclaration);
        }
        /// <summary>
        /// Generates a <see cref="AttributeDeclaration"/> representation of an 
        /// <see cref="EditableAttribute"/> instance.
        /// </summary>
        /// <param name="attribute">The <see cref="EditableAttribute"/>.</param>
        /// <returns>A <see cref="AttributeDeclaration"/> representation of 
        /// <paramref name="attribute"/>.</returns>
        /// <exception cref="InvalidCastException">if <paramref name="attribute"/> is 
        /// not a <see cref="EditableAttribute"/>.</exception>
        public override AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            EditableAttribute editableAttribute = (EditableAttribute)attribute;
            AttributeDeclaration attributeDeclaration = new AttributeDeclaration(typeof(EditableAttribute));

            bool allowEdit = editableAttribute.AllowEdit;
            bool allowInitialValue = editableAttribute.AllowInitialValue;

            // [EditableAttribute( {true|false} )]
            attributeDeclaration.ConstructorArguments.Add(allowEdit);

            // Only add the 'AllowInitialValue' parameter if its value does not match with
            // the 'AllowEdit' value.  See the documentation of EditableAttribute for more info.
            if (allowEdit != allowInitialValue)
            {
                // [EditableAttribute( {true|false}, AllowInitialValue = {true|false} )]
                attributeDeclaration.NamedParameters.Add("AllowInitialValue", allowInitialValue);
            }

            return attributeDeclaration;
        }
        public override AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            DisplayAttribute displayAttribute = (DisplayAttribute)attribute;
            AttributeDeclaration attributeDeclaration = new AttributeDeclaration(typeof(DisplayAttribute));

            // By convention, the attribute parameters are not validated until an attempt is made to
            // access the resources.  We do the following probe merely to trigger this validation process.
            // An InvalidOperationException will be thrown if the attribute is ill-formed.
            Type attributeType = attribute.GetType();

            try
            {
                displayAttribute.GetName();
            }
            catch (InvalidOperationException ex)
            {
                throw new AttributeBuilderException(ex, attributeType, "Name");
            }

            try
            {
                displayAttribute.GetShortName();
            }
            catch (InvalidOperationException ex)
            {
                throw new AttributeBuilderException(ex, attributeType, "ShortName");
            }

            try
            {
                displayAttribute.GetDescription();
            }
            catch (InvalidOperationException ex)
            {
                throw new AttributeBuilderException(ex, attributeType, "Description");
            }

            try
            {
                displayAttribute.GetPrompt();
            }
            catch (InvalidOperationException ex)
            {
                throw new AttributeBuilderException(ex, attributeType, "Prompt");
            }

            // Add AutoGenerateField
            if (displayAttribute.GetAutoGenerateField().HasValue)
            {
                attributeDeclaration.NamedParameters.Add("AutoGenerateField", displayAttribute.AutoGenerateField);
            }

            // Add AutoGenerateFilter
            if (displayAttribute.GetAutoGenerateFilter().HasValue)
            {
                attributeDeclaration.NamedParameters.Add("AutoGenerateFilter", displayAttribute.AutoGenerateFilter);
            }

            // Add Description
            if (!string.IsNullOrEmpty(displayAttribute.Description))
            {
                attributeDeclaration.NamedParameters.Add("Description", displayAttribute.Description);
            }

            // Add GroupName
            if (!string.IsNullOrEmpty(displayAttribute.GroupName))
            {
                attributeDeclaration.NamedParameters.Add("GroupName", displayAttribute.GroupName);
            }

            // Add Name
            if (!string.IsNullOrEmpty(displayAttribute.Name))
            {
                attributeDeclaration.NamedParameters.Add("Name", displayAttribute.Name);
            }

            // Add Order
            if (displayAttribute.GetOrder().HasValue)
            {
                attributeDeclaration.NamedParameters.Add("Order", displayAttribute.Order);
            }

            // Add Prompt
            if (!string.IsNullOrEmpty(displayAttribute.Prompt))
            {
                attributeDeclaration.NamedParameters.Add("Prompt", displayAttribute.Prompt);
            }

            // Add ResourceType
            if (displayAttribute.ResourceType != null)
            {
                attributeDeclaration.NamedParameters.Add("ResourceType", displayAttribute.ResourceType);
            }

            // Add ShortName
            if (!string.IsNullOrEmpty(displayAttribute.ShortName))
            {
                attributeDeclaration.NamedParameters.Add("ShortName", displayAttribute.ShortName);
            }

            return attributeDeclaration;
        }
        /// <summary>
        /// Returns a representative <see cref="AttributeDeclaration"/> for a given <see cref="Attribute"/> instance.
        /// </summary>
        /// <param name="attribute">An attribute instance to create a <see cref="AttributeDeclaration"/> for.</param>
        /// <returns>A <see cref="AttributeDeclaration"/> representing the <paramref name="attribute"/>.</returns>
        public virtual AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            if (attribute == null)
            {
                throw new ArgumentNullException(nameof(attribute));
            }

            Type attributeType = attribute.GetType();
            AttributeDeclaration attributeDeclaration = new AttributeDeclaration(attributeType);

            // Strategy is as follows:
            //  - Fetch all the public property values from the current attribute
            //  - Determine the default value for all of these properties
            //  - From these 2 lists, determine the set of "non-default" properties.  These are what we must code gen.
            //  - From this list, determine which of these can be set only through a ctor
            //  - From the list of ctor properties and values, find the best ctor pattern for it and code gen that
            //  - For all remaining non-default properties, code gen named argument setters
            List<PropertyMap> propertyMaps = this.BuildPropertyMaps(attribute);
            Dictionary<string, object> currentValues = GetPropertyValues(propertyMaps, attribute);
            Dictionary<string, object> defaultValues = GetDefaultPropertyValues(propertyMaps, attribute, currentValues);
            List<PropertyMap> nonDefaultProperties = GetNonDefaultProperties(propertyMaps, currentValues, defaultValues);
            List<PropertyMap> unsettableProperties = GetUnsettableProperties(nonDefaultProperties);

            // "Unsettable" properties are all those that can be set only through a ctor (they have no public setter).
            // Go find the best ctor pattern for them and code gen that much
            ParameterInfo[] ctorParameters = FindBestConstructor(unsettableProperties, currentValues, attributeType);
            if (ctorParameters == null)
            {
                // Return null, indicating we cannot build this attribute.
                return null;
            }

            // We found a ctor that will accept all our properties that need to be set.
            // Generate ctor arguments to match this signature.
            // Note: the ctor pattern obviously may require other arguments that are also settable,
            // so if we pass a value to the ctor, we omit it from the set of named parameters below
            foreach (ParameterInfo parameter in ctorParameters)
            {
                PropertyMap matchedPropertyMap = null;
                foreach (PropertyMap map in propertyMaps)
                {
                    PropertyInfo propertyInfo = map.Setter;
                    if (propertyInfo.Name.Equals(parameter.Name, StringComparison.OrdinalIgnoreCase) && CanValueBeAssignedToType(parameter.ParameterType, currentValues[propertyInfo.Name]))
                    {
                        matchedPropertyMap = map;
                        break;
                    }
                }
                object value = matchedPropertyMap != null ? currentValues[matchedPropertyMap.Getter.Name] : DefaultInstanceForType(parameter.ParameterType);
                attributeDeclaration.ConstructorArguments.Add(value);

                // Remove this from our list of properties we need to set so the code below skips it
                if (matchedPropertyMap != null)
                {
                    nonDefaultProperties.Remove(matchedPropertyMap);
                }
            }

            // For all remaining non-default properties, generate a named argument setter.
            // We sort these so the named parameters appear in a predictable order in generated code -- primarily for unit testing
            nonDefaultProperties.Sort(new Comparison<PropertyMap>((x, y) => string.Compare(x.Setter.Name, y.Setter.Name, StringComparison.Ordinal)));

            foreach (PropertyMap map in nonDefaultProperties)
            {
                attributeDeclaration.NamedParameters.Add(map.Setter.Name, currentValues[map.Getter.Name]);
            }

            return attributeDeclaration;
        }
예제 #12
0
        /// <summary>
        /// Registers any resource type used by the given <see cref="ValidationAttribute"/> that must be shared and
        /// have a named resource property available.
        /// </summary>
        /// <param name="validationAttribute">The <see cref="ValidationAttribute"/> instance to check.</param>
        /// <param name="attributeDeclaration">The <see cref="AttributeDeclaration"/> used to describe <paramref name="validationAttribute"/>.</param>
        protected static void RegisterSharedResources(ValidationAttribute validationAttribute, AttributeDeclaration attributeDeclaration)
        {
            string resourceName = validationAttribute.ErrorMessageResourceName;
            Type   resourceType = validationAttribute.ErrorMessageResourceType;

            bool isEmptyResourceName      = string.IsNullOrEmpty(resourceName);
            Type validateionAttributeType = validationAttribute.GetType();

            // At least one is non-null.  If the other is null, we have a problem.  We need both to
            // localize properly, or neither to signal we use the static string version
            if ((resourceType != null && isEmptyResourceName) || (resourceType == null && !isEmptyResourceName))
            {
                string resourceTypeMessage = resourceType != null ? resourceType.Name : Resource.Unspecified_Resource_Element;
                string resourceNameMessage = isEmptyResourceName ? Resource.Unspecified_Resource_Element : resourceName;

                attributeDeclaration.Errors.Add(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_ValidationAttribute_Requires_ResourceType_And_Name,
                        validateionAttributeType,
                        resourceTypeMessage,
                        resourceNameMessage));
                return;
            }

            if (resourceType != null)
            {
                PropertyInfo resourceProperty = resourceType.GetProperty(resourceName);

                if (resourceProperty == null)
                {
                    attributeDeclaration.Errors.Add(
                        string.Format(
                            CultureInfo.CurrentCulture,
                            Resource.ClientCodeGen_ValidationAttribute_ResourcePropertyNotFound,
                            validateionAttributeType,
                            resourceName,
                            resourceType));
                }
                else
                {
                    attributeDeclaration.RequiredTypes.Add(resourceType);
                    attributeDeclaration.RequiredProperties.Add(resourceProperty);
                }
            }
        }
        public override AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            DisplayAttribute     displayAttribute     = (DisplayAttribute)attribute;
            AttributeDeclaration attributeDeclaration = new AttributeDeclaration(typeof(DisplayAttribute));

            // By convention, the attribute parameters are not validated until an attempt is made to
            // access the resources.  We do the following probe merely to trigger this validation process.
            // An InvalidOperationException will be thrown if the attribute is ill-formed.
            Type attributeType = attribute.GetType();

            try
            {
                displayAttribute.GetName();
            }
            catch (InvalidOperationException ex)
            {
                throw new AttributeBuilderException(ex, attributeType, "Name");
            }

            try
            {
                displayAttribute.GetShortName();
            }
            catch (InvalidOperationException ex)
            {
                throw new AttributeBuilderException(ex, attributeType, "ShortName");
            }

            try
            {
                displayAttribute.GetDescription();
            }
            catch (InvalidOperationException ex)
            {
                throw new AttributeBuilderException(ex, attributeType, "Description");
            }

            try
            {
                displayAttribute.GetPrompt();
            }
            catch (InvalidOperationException ex)
            {
                throw new AttributeBuilderException(ex, attributeType, "Prompt");
            }

            // Add AutoGenerateField
            if (displayAttribute.GetAutoGenerateField().HasValue)
            {
                attributeDeclaration.NamedParameters.Add("AutoGenerateField", displayAttribute.AutoGenerateField);
            }

            // Add AutoGenerateFilter
            if (displayAttribute.GetAutoGenerateFilter().HasValue)
            {
                attributeDeclaration.NamedParameters.Add("AutoGenerateFilter", displayAttribute.AutoGenerateFilter);
            }

            // Add Description
            if (!string.IsNullOrEmpty(displayAttribute.Description))
            {
                attributeDeclaration.NamedParameters.Add("Description", displayAttribute.Description);
            }

            // Add GroupName
            if (!string.IsNullOrEmpty(displayAttribute.GroupName))
            {
                attributeDeclaration.NamedParameters.Add("GroupName", displayAttribute.GroupName);
            }

            // Add Name
            if (!string.IsNullOrEmpty(displayAttribute.Name))
            {
                attributeDeclaration.NamedParameters.Add("Name", displayAttribute.Name);
            }

            // Add Order
            if (displayAttribute.GetOrder().HasValue)
            {
                attributeDeclaration.NamedParameters.Add("Order", displayAttribute.Order);
            }

            // Add Prompt
            if (!string.IsNullOrEmpty(displayAttribute.Prompt))
            {
                attributeDeclaration.NamedParameters.Add("Prompt", displayAttribute.Prompt);
            }

            // Add ResourceType
            if (displayAttribute.ResourceType != null)
            {
                attributeDeclaration.NamedParameters.Add("ResourceType", displayAttribute.ResourceType);
            }

            // Add ShortName
            if (!string.IsNullOrEmpty(displayAttribute.ShortName))
            {
                attributeDeclaration.NamedParameters.Add("ShortName", displayAttribute.ShortName);
            }

            return(attributeDeclaration);
        }
 /// <summary>
 /// Generate comments indicating attribute propagation failure.
 /// </summary>
 /// <param name="proxyGenerator">The context for generating code.  It cannot be <c>null</c>.</param>
 /// <param name="attributeDeclaration">The attribute declaration to generate as a comment.</param>
 /// <returns>A collection of comments.</returns>
 private static CodeCommentStatementCollection ConstructCodeAttributeFailureComments(CodeDomClientCodeGenerator proxyGenerator, AttributeDeclaration attributeDeclaration)
 {
     // We are generating failure comments in the following example form:
     //
     //    // Unable to generate the following attribute(s) due to the following error(s):
     //    // - The attribute 'System.ComponentModel.DataAnnotations.CustomValidationAttribute' references type 'TestDomainServices.ServerOnlyValidator'.  This is not accessible in the client project.
     //    // [CustomValidationAttribute(typeof(TestDomainServices.ServerOnlyValidator), "IsObjectValid")]
     //    //
     CodeCommentStatementCollection comments = new CodeCommentStatementCollection();
     foreach (string error in attributeDeclaration.Errors)
     {
         comments.Add(new CodeCommentStatement(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_FailedToGenerate_ErrorTemplate, error)));
     }
     comments.Add(new CodeCommentStatement(GenerateCodeAttribute(proxyGenerator, attributeDeclaration)));
     comments.Add(new CodeCommentStatement(string.Empty /* blank comment */));
     return comments;
 }
        /// <summary>
        /// Creates a <see cref="CodeAttributeDeclaration"/> for the given <see cref="AttributeDeclaration"/>.
        /// </summary>
        /// <param name="proxyGenerator">The context for generating code.  It cannot be null.</param>
        /// <param name="referencingType">The referencing type.</param>
        /// <param name="attributeDeclaration">The <see cref="AttributeDeclaration"/> to build.</param>
        /// <returns>A <see cref="CodeAttributeDeclaration"/>.</returns>
        private static CodeAttributeDeclaration CreateCodeAttributeDeclaration(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, AttributeDeclaration attributeDeclaration)
        {
            CodeAttributeDeclaration codeAttributeDeclaration = CodeGenUtilities.CreateAttributeDeclaration(attributeDeclaration.AttributeType, proxyGenerator, referencingType);

            // Add ctor args
            foreach (object arg in attributeDeclaration.ConstructorArguments)
            {
                CodeExpression expression = CreateCodeExpression(proxyGenerator, referencingType, arg);
                codeAttributeDeclaration.Arguments.Add(new CodeAttributeArgument(expression));
            }

            // Add named params
            foreach (KeyValuePair <string, object> pair in attributeDeclaration.NamedParameters)
            {
                CodeExpression expression = CreateCodeExpression(proxyGenerator, referencingType, pair.Value);
                codeAttributeDeclaration.Arguments.Add(new CodeAttributeArgument(pair.Key, expression));
            }

            return(codeAttributeDeclaration);
        }
        /// <summary>
        /// Generates an attribute declaration string.  This is used in scenarios where an attribute declaration is needed
        /// in the form of a comment.  CodeDOM does not support generation of standalone attributes.
        /// </summary>
        /// <param name="proxyGenerator">The context for generating code.  It cannot be null.</param>
        /// <param name="attributeDeclaration">The <see cref="AttributeDeclaration"/> to represent.</param>
        /// <returns>An attribute declaration.</returns>
        private static string GenerateCodeAttribute(CodeDomClientCodeGenerator proxyGenerator, AttributeDeclaration attributeDeclaration)
        {
            StringBuilder result   = new StringBuilder();
            bool          isCSharp = proxyGenerator.IsCSharp;

            result.Append(isCSharp ? '[' : '<');
            result.Append(attributeDeclaration.AttributeType.Name);
            result.Append('(');

            // Add ctor args
            if (attributeDeclaration.ConstructorArguments.Count > 0)
            {
                foreach (object value in attributeDeclaration.ConstructorArguments)
                {
                    result.Append(ConvertValueToCode(value, isCSharp));
                    result.Append(", ");
                }
            }

            // Add named params
            if (attributeDeclaration.NamedParameters.Count > 0)
            {
                foreach (KeyValuePair <string, object> pair in attributeDeclaration.NamedParameters)
                {
                    result.Append(pair.Key);
                    result.Append(isCSharp ? " = " : " := ");
                    result.Append(ConvertValueToCode(pair.Value, isCSharp));
                    result.Append(", ");
                }
            }

            if (attributeDeclaration.ConstructorArguments.Count > 0 || attributeDeclaration.NamedParameters.Count > 0)
            {
                result.Remove(result.Length - 2, 2);
            }

            result.Append(')');
            result.Append(isCSharp ? "]" : "> _");

            return(result.ToString());
        }
        /// <summary>
        /// Verifies that a <see cref="AttributeDeclaration"/>'s shared type requirements are met.
        /// </summary>
        /// <param name="proxyGenerator">The context for code generation</param>
        /// <param name="attributeDeclaration">The <see cref="AttributeDeclaration"/> to verify.</param>
        private static void ValidateAttributeDeclarationRequirements(CodeDomClientCodeGenerator proxyGenerator, AttributeDeclaration attributeDeclaration)
        {
            // Verify the attribute itself is shared.
            CodeMemberShareKind shareKind = proxyGenerator.GetTypeShareKind(attributeDeclaration.AttributeType);

            // If there is no PDB or this type has no human-authored code, we cannot determine
            // whether it is shared and get a null value.  This requires a special message to
            // explain why we treat the type as not shared.
            if (shareKind == CodeMemberShareKind.Unknown)
            {
                attributeDeclaration.Errors.Add(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_Attribute_RequiresShared_NoPDB,
                        attributeDeclaration.AttributeType,
                        attributeDeclaration.AttributeType.Assembly.GetName().Name,
                        proxyGenerator.ClientProjectName));
            }
            else if (shareKind == CodeMemberShareKind.NotShared)
            {
                attributeDeclaration.Errors.Add(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_Attribute_RequiresShared,
                        attributeDeclaration.AttributeType,
                        proxyGenerator.ClientProjectName));
            }

            // Verify shared types.  Here, we order by type name so that any generated errors
            // are presented in a consistent order.
            foreach (var type in attributeDeclaration.RequiredTypes.OrderBy(t => t.FullName))
            {
                shareKind = proxyGenerator.GetTypeShareKind(type);

                // Missing PDB or lack of user code means we cannot know -- issue special warning
                if (shareKind == CodeMemberShareKind.Unknown)
                {
                    attributeDeclaration.Errors.Add(
                        string.Format(
                            CultureInfo.CurrentCulture,
                            Resource.ClientCodeGen_Attribute_RequiresShared_Type_NoPDB,
                            attributeDeclaration.AttributeType,
                            type,
                            type.Assembly.GetName().Name,
                            proxyGenerator.ClientProjectName));
                }
                else if (shareKind == CodeMemberShareKind.NotShared)
                {
                    attributeDeclaration.Errors.Add(
                        string.Format(
                            CultureInfo.CurrentCulture,
                            Resource.ClientCodeGen_Attribute_RequiresShared_Type,
                            attributeDeclaration.AttributeType,
                            type,
                            proxyGenerator.ClientProjectName));
                }
            }

            // Verify shared methods.  Here, we order by method name so that any generated errors
            // are presented in a consistent order.
            foreach (var method in attributeDeclaration.RequiredMethods.OrderBy(p => p.Name))
            {
                shareKind = proxyGenerator.GetMethodShareKind(method);
                if (shareKind == CodeMemberShareKind.NotShared)
                {
                    attributeDeclaration.Errors.Add(
                        string.Format(
                            CultureInfo.CurrentCulture,
                            Resource.ClientCodeGen_Attribute_RequiresShared_Method,
                            attributeDeclaration.AttributeType,
                            method.Name,
                            method.DeclaringType,
                            proxyGenerator.ClientProjectName));
                }
            }

            // Verify shared properties.  Here, we order by property name so that any generated errors
            // are presented in a consistent order.
            foreach (var property in attributeDeclaration.RequiredProperties.OrderBy(p => p.Name))
            {
                shareKind = proxyGenerator.GetPropertyShareKind(property.DeclaringType, property.Name);
                if (shareKind == CodeMemberShareKind.NotShared)
                {
                    attributeDeclaration.Errors.Add(
                        string.Format(
                            CultureInfo.CurrentCulture,
                            Resource.ClientCodeGen_Attribute_RequiresShared_Property,
                            attributeDeclaration.AttributeType,
                            property.Name,
                            property.DeclaringType,
                            proxyGenerator.ClientProjectName));
                }
            }
        }
        /// <summary>
        /// Generate comments indicating attribute propagation failure.
        /// </summary>
        /// <param name="proxyGenerator">The context for generating code.  It cannot be <c>null</c>.</param>
        /// <param name="attributeDeclaration">The attribute declaration to generate as a comment.</param>
        /// <returns>A collection of comments.</returns>
        private static CodeCommentStatementCollection ConstructCodeAttributeFailureComments(CodeDomClientCodeGenerator proxyGenerator, AttributeDeclaration attributeDeclaration)
        {
            // We are generating failure comments in the following example form:
            //
            //    // Unable to generate the following attribute(s) due to the following error(s):
            //    // - The attribute 'System.ComponentModel.DataAnnotations.CustomValidationAttribute' references type 'TestDomainServices.ServerOnlyValidator'.  This is not accessible in the client project.
            //    // [CustomValidationAttribute(typeof(TestDomainServices.ServerOnlyValidator), "IsObjectValid")]
            //    //
            CodeCommentStatementCollection comments = new CodeCommentStatementCollection();

            foreach (string error in attributeDeclaration.Errors)
            {
                comments.Add(new CodeCommentStatement(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_FailedToGenerate_ErrorTemplate, error)));
            }
            comments.Add(new CodeCommentStatement(GenerateCodeAttribute(proxyGenerator, attributeDeclaration)));
            comments.Add(new CodeCommentStatement(string.Empty /* blank comment */));
            return(comments);
        }
        /// <summary>
        /// Generates code for the given set of custom attributes
        /// </summary>
        /// <param name="proxyGenerator">Root client proxy generator</param>
        /// <param name="referencingType">The referencing type</param>
        /// <param name="getLogWarningMessage">The function to call to get the warning message to be logged</param>
        /// <param name="attributes">Collection of attributes for which to generate code</param>
        /// <param name="comments">Collection of comments that should be updated if errors are discovered.</param>
        /// <param name="customCommentHeader">A custom comment header that will be displayed for any generated comment errors.</param>
        /// <param name="forcePropagation">Indicates whether or not to force attribute propagation.</param>
        /// <returns>The collection of generated attribute declarations corresponding to <paramref name="attributes"/></returns>
        private static IEnumerable <CodeAttributeDeclaration> GenerateCustomAttributes(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, Func <AttributeBuilderException, string> getLogWarningMessage, IEnumerable <Attribute> attributes, CodeCommentStatementCollection comments, string customCommentHeader, bool forcePropagation)
        {
            bool emittedErrorCommentHeader         = false;
            List <CodeAttributeDeclaration> result = new List <CodeAttributeDeclaration>(attributes.Count());

            // Enumerate over attributes sorted by name.  Here, we sort by name to ensure that our
            // generated baselines (including possible error comments!) are ordered consistently.
            foreach (Attribute attribute in attributes.OrderBy(a => a.GetType().Name))
            {
                Type attributeType = attribute.GetType();

                // Check if this attribute should be blocked
                if (IsAttributeBlocked(attributeType))
                {
                    continue;
                }

                bool attributePropagated        = false;
                bool isDataAnnotationsAttribute = string.Equals(attributeType.Namespace, typeof(ValidationAttribute).Namespace, StringComparison.Ordinal);

                ICustomAttributeBuilder cab = GetCustomAttributeBuilder(attributeType);

                if (cab != null)
                {
                    AttributeDeclaration attributeDeclaration = null;
                    // If the attempt to build the attribute fails, log a clean error.
                    // One common exception path is InvalidOperationException arising from
                    // attributes that have been improperly constructed (see DisplayAttribute)
                    try
                    {
                        attributeDeclaration = cab.GetAttributeDeclaration(attribute);
                    }
                    catch (AttributeBuilderException attributeBuilderException)
                    {
                        // Ensure we've generated the attribute generation failure error header
                        GenerateCustomAttributesErrorCommentHeader(comments, customCommentHeader, ref emittedErrorCommentHeader);

                        // Generate comments stating the attribute couldn't be generated
                        comments.AddRange(ConstructCodeAttributeFailureComments(attributeBuilderException.Message));

                        // Log the build warning if a method was specified to get the warning message
                        if (getLogWarningMessage != null)
                        {
                            string warningMessage = getLogWarningMessage(attributeBuilderException);
                            proxyGenerator.LogWarning(warningMessage);
                        }

                        // Move on to the next attribute
                        continue;
                    }

                    // Null is acceptable indicator that code-gen was not possible.
                    if (attributeDeclaration != null)
                    {
                        if (!forcePropagation)
                        {
                            // Verify attribute's shared type|property|method requirements are met
                            ValidateAttributeDeclarationRequirements(proxyGenerator, attributeDeclaration);
                        }

                        if (attributeDeclaration.HasErrors)
                        {
                            // Only generate comments if the attribute is a DataAnnotations attribute
                            if (isDataAnnotationsAttribute)
                            {
                                // Ensure we've generated the attribute generation failure error header
                                GenerateCustomAttributesErrorCommentHeader(comments, customCommentHeader, ref emittedErrorCommentHeader);

                                // Generate attribute and an error message as comments
                                comments.AddRange(ConstructCodeAttributeFailureComments(proxyGenerator, attributeDeclaration));
                            }
                        }
                        else
                        {
                            // Generate the attribute declaration
                            CodeAttributeDeclaration codeAttributeDeclaration = CreateCodeAttributeDeclaration(proxyGenerator, referencingType, attributeDeclaration);
                            result.Add(codeAttributeDeclaration);
                            attributePropagated = true;
                        }
                    }
                }

                // We generate VS warnings in certain scenarios:
                //  - A DataAnnotation attribute type was not available on the client, user needs to add a reference.
                //  - An attribute subclassed ValidationAttribute (custom or framework) and we couldn't build it.
                if (!attributePropagated)
                {
                    // Was it a DA attribute that wasn't available?  If so, log a warning.
                    if (isDataAnnotationsAttribute)
                    {
                        CodeMemberShareKind shareKind = proxyGenerator.GetTypeShareKind(attributeType);
                        if (shareKind == CodeMemberShareKind.NotShared)
                        {
                            // Indicate that a reference to 'System.ComponentModel.DataAnnotations' is required.
                            proxyGenerator.LogWarning(
                                string.Format(
                                    CultureInfo.CurrentCulture,
                                    Resource.ClientCodeGen_Attribute_RequiresDataAnnotations,
                                    attributeType,
                                    proxyGenerator.ClientProjectName));
                        }
                    }
                    // Was it a validation attribute that we couldn't build?  If so, log a warning.
                    else if (cab == null && typeof(ValidationAttribute).IsAssignableFrom(attributeType))
                    {
                        // Indicate that a builder was not found, attribute does not meet heuristics.
                        proxyGenerator.LogWarning(
                            string.Format(
                                CultureInfo.CurrentCulture,
                                Resource.ClientCodeGen_Attribute_RequiresBuilder,
                                attributeType));
                    }
                }
            }

            // Issue -- CodeDom outputs the attributes in the order they are generated.
            // To allow consistent output for easy baseline comparisons, sort the list.
            result.Sort(new Comparison <CodeAttributeDeclaration>((x, y) => string.Compare(x.Name, y.Name, StringComparison.Ordinal)));
            return(result);
        }
        /// <summary>
        /// Returns a representative <see cref="AttributeDeclaration"/> for a given <see cref="Attribute"/> instance.
        /// </summary>
        /// <param name="attribute">An attribute instance to create a <see cref="AttributeDeclaration"/> for.</param>
        /// <returns>A <see cref="AttributeDeclaration"/> representing the <paramref name="attribute"/>.</returns>
        public virtual AttributeDeclaration GetAttributeDeclaration(Attribute attribute)
        {
            if (attribute == null)
            {
                throw new ArgumentNullException("attribute");
            }

            Type attributeType = attribute.GetType();
            AttributeDeclaration attributeDeclaration = new AttributeDeclaration(attributeType);

            // Strategy is as follows:
            //  - Fetch all the public property values from the current attribute
            //  - Determine the default value for all of these properties
            //  - From these 2 lists, determine the set of "non-default" properties.  These are what we must code gen.
            //  - From this list, determine which of these can be set only through a ctor
            //  - From the list of ctor properties and values, find the best ctor pattern for it and code gen that
            //  - For all remaining non-default properties, code gen named argument setters
            List<PropertyMap> propertyMaps = this.BuildPropertyMaps(attribute);
            Dictionary<string, object> currentValues = GetPropertyValues(propertyMaps, attribute);
            Dictionary<string, object> defaultValues = GetDefaultPropertyValues(propertyMaps, attribute, currentValues);
            List<PropertyMap> nonDefaultProperties = GetNonDefaultProperties(propertyMaps, currentValues, defaultValues);
            List<PropertyMap> unsettableProperties = GetUnsettableProperties(nonDefaultProperties);

            // "Unsettable" properties are all those that can be set only through a ctor (they have no public setter).
            // Go find the best ctor pattern for them and code gen that much
            ParameterInfo[] ctorParameters = FindBestConstructor(unsettableProperties, currentValues, attributeType);
            if (ctorParameters == null)
            {
                // Return null, indicating we cannot build this attribute.
                return null;
            }

            // We found a ctor that will accept all our properties that need to be set.
            // Generate ctor arguments to match this signature.
            // Note: the ctor pattern obviously may require other arguments that are also settable,
            // so if we pass a value to the ctor, we omit it from the set of named parameters below
            foreach (ParameterInfo parameter in ctorParameters)
            {
                PropertyMap matchedPropertyMap = null;
                foreach (PropertyMap map in propertyMaps)
                {
                    PropertyInfo propertyInfo = map.Setter;
                    if (propertyInfo.Name.Equals(parameter.Name, StringComparison.OrdinalIgnoreCase) && CanValueBeAssignedToType(parameter.ParameterType, currentValues[propertyInfo.Name]))
                    {
                        matchedPropertyMap = map;
                        break;
                    }
                }
                object value = matchedPropertyMap != null ? currentValues[matchedPropertyMap.Getter.Name] : DefaultInstanceForType(parameter.ParameterType);
                attributeDeclaration.ConstructorArguments.Add(value);

                // Remove this from our list of properties we need to set so the code below skips it
                if (matchedPropertyMap != null)
                {
                    nonDefaultProperties.Remove(matchedPropertyMap);
                }
            }

            // For all remaining non-default properties, generate a named argument setter.
            // We sort these so the named parameters appear in a predictable order in generated code -- primarily for unit testing
            nonDefaultProperties.Sort(new Comparison<PropertyMap>((x, y) => string.Compare(x.Setter.Name, y.Setter.Name, StringComparison.Ordinal)));

            foreach (PropertyMap map in nonDefaultProperties)
            {
                attributeDeclaration.NamedParameters.Add(map.Setter.Name, currentValues[map.Getter.Name]);
            }

            return attributeDeclaration;
        }
        /// <summary>
        /// Creates a <see cref="CodeAttributeDeclaration"/> for the given <see cref="AttributeDeclaration"/>.
        /// </summary>
        /// <param name="proxyGenerator">The context for generating code.  It cannot be null.</param>
        /// <param name="referencingType">The referencing type.</param>
        /// <param name="attributeDeclaration">The <see cref="AttributeDeclaration"/> to build.</param>
        /// <returns>A <see cref="CodeAttributeDeclaration"/>.</returns>
        private static CodeAttributeDeclaration CreateCodeAttributeDeclaration(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, AttributeDeclaration attributeDeclaration)
        {
            CodeAttributeDeclaration codeAttributeDeclaration = CodeGenUtilities.CreateAttributeDeclaration(attributeDeclaration.AttributeType, proxyGenerator, referencingType);

            // Add ctor args
            foreach (object arg in attributeDeclaration.ConstructorArguments)
            {
                CodeExpression expression = CreateCodeExpression(proxyGenerator, referencingType, arg);
                codeAttributeDeclaration.Arguments.Add(new CodeAttributeArgument(expression));
            }

            // Add named params
            foreach (KeyValuePair<string, object> pair in attributeDeclaration.NamedParameters)
            {
                CodeExpression expression = CreateCodeExpression(proxyGenerator, referencingType, pair.Value);
                codeAttributeDeclaration.Arguments.Add(new CodeAttributeArgument(pair.Key, expression));
            }

            return codeAttributeDeclaration;
        }
        /// <summary>
        /// Generates an attribute declaration string.  This is used in scenarios where an attribute declaration is needed
        /// in the form of a comment.  CodeDOM does not support generation of standalone attributes.
        /// </summary>
        /// <param name="proxyGenerator">The context for generating code.  It cannot be null.</param>
        /// <param name="attributeDeclaration">The <see cref="AttributeDeclaration"/> to represent.</param>
        /// <returns>An attribute declaration.</returns>
        private static string GenerateCodeAttribute(CodeDomClientCodeGenerator proxyGenerator, AttributeDeclaration attributeDeclaration)
        {
            StringBuilder result = new StringBuilder();
            bool isCSharp = proxyGenerator.IsCSharp;

            result.Append(isCSharp ? '[' : '<');
            result.Append(attributeDeclaration.AttributeType.Name);
            result.Append('(');

            // Add ctor args
            if (attributeDeclaration.ConstructorArguments.Count > 0)
            {
                foreach (object value in attributeDeclaration.ConstructorArguments)
                {
                    result.Append(ConvertValueToCode(value, isCSharp));
                    result.Append(", ");
                }
            }

            // Add named params
            if (attributeDeclaration.NamedParameters.Count > 0)
            {
                foreach (KeyValuePair<string, object> pair in attributeDeclaration.NamedParameters)
                {
                    result.Append(pair.Key);
                    result.Append(isCSharp ? " = " : " := ");
                    result.Append(ConvertValueToCode(pair.Value, isCSharp));
                    result.Append(", ");
                }
            }

            if (attributeDeclaration.ConstructorArguments.Count > 0 || attributeDeclaration.NamedParameters.Count > 0)
            {
                result.Remove(result.Length - 2, 2);
            }

            result.Append(')');
            result.Append(isCSharp ? "]" : "> _");

            return result.ToString();
        }
        /// <summary>
        /// Verifies that a <see cref="AttributeDeclaration"/>'s shared type requirements are met.
        /// </summary>
        /// <param name="proxyGenerator">The context for code generation</param>
        /// <param name="attributeDeclaration">The <see cref="AttributeDeclaration"/> to verify.</param>
        private static void ValidateAttributeDeclarationRequirements(CodeDomClientCodeGenerator proxyGenerator, AttributeDeclaration attributeDeclaration)
        {
            // Verify the attribute itself is shared.
            CodeMemberShareKind shareKind = proxyGenerator.GetTypeShareKind(attributeDeclaration.AttributeType);

            // If there is no PDB or this type has no human-authored code, we cannot determine
            // whether it is shared and get a null value.  This requires a special message to
            // explain why we treat the type as not shared.
            if (shareKind == CodeMemberShareKind.Unknown)
            {
                attributeDeclaration.Errors.Add(
                string.Format(
                    CultureInfo.CurrentCulture,
                    Resource.ClientCodeGen_Attribute_RequiresShared_NoPDB,
                    attributeDeclaration.AttributeType,
                    attributeDeclaration.AttributeType.Assembly.GetName().Name,
                    proxyGenerator.ClientProjectName));
            }
            else if (shareKind == CodeMemberShareKind.NotShared)
            {
                attributeDeclaration.Errors.Add(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_Attribute_RequiresShared,
                        attributeDeclaration.AttributeType,
                        proxyGenerator.ClientProjectName));
            }

            // Verify shared types.  Here, we order by type name so that any generated errors
            // are presented in a consistent order.
            foreach (var type in attributeDeclaration.RequiredTypes.OrderBy(t => t.FullName))
            {
                shareKind = proxyGenerator.GetTypeShareKind(type);

                // Missing PDB or lack of user code means we cannot know -- issue special warning
                if (shareKind == CodeMemberShareKind.Unknown)
                {
                    attributeDeclaration.Errors.Add(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_Attribute_RequiresShared_Type_NoPDB,
                        attributeDeclaration.AttributeType,
                        type,
                        type.Assembly.GetName().Name,
                        proxyGenerator.ClientProjectName));
                }
                else if (shareKind == CodeMemberShareKind.NotShared)
                {
                    attributeDeclaration.Errors.Add(
                        string.Format(
                            CultureInfo.CurrentCulture,
                            Resource.ClientCodeGen_Attribute_RequiresShared_Type,
                            attributeDeclaration.AttributeType,
                            type,
                            proxyGenerator.ClientProjectName));
                }
            }

            // Verify shared methods.  Here, we order by method name so that any generated errors
            // are presented in a consistent order.
            foreach (var method in attributeDeclaration.RequiredMethods.OrderBy(p => p.Name))
            {
                shareKind = proxyGenerator.GetMethodShareKind(method);
                if (shareKind == CodeMemberShareKind.NotShared)
                {
                    attributeDeclaration.Errors.Add(
                        string.Format(
                            CultureInfo.CurrentCulture,
                            Resource.ClientCodeGen_Attribute_RequiresShared_Method,
                            attributeDeclaration.AttributeType,
                            method.Name,
                            method.DeclaringType,
                            proxyGenerator.ClientProjectName));
                }
            }

            // Verify shared properties.  Here, we order by property name so that any generated errors
            // are presented in a consistent order.
            foreach (var property in attributeDeclaration.RequiredProperties.OrderBy(p => p.Name))
            {
                shareKind = proxyGenerator.GetPropertyShareKind(property.DeclaringType, property.Name);
                if (shareKind == CodeMemberShareKind.NotShared)
                {
                    attributeDeclaration.Errors.Add(
                        string.Format(
                            CultureInfo.CurrentCulture,
                            Resource.ClientCodeGen_Attribute_RequiresShared_Property,
                            attributeDeclaration.AttributeType,
                            property.Name,
                            property.DeclaringType,
                            proxyGenerator.ClientProjectName));
                }
            }
        }