コード例 #1
0
        /// <summary>
        /// In cases where we are emitting types that aren't already in the root namespace,
        /// we need to translate the generated type namespace so that it resides in the
        /// root namespace.
        /// </summary>
        /// <remarks>
        /// Here, we're interested in cases where we're generating VB code
        /// and our target project has a non-null root namespace.
        /// </remarks>
        /// <param name="type">The type who namespace should be translated</param>
        /// <param name="codeGenerator">The current proxy generator</param>
        /// <returns>A translated namespace string</returns>
        internal static string TranslateNamespace(Type type, CodeDomClientCodeGenerator codeGenerator)
        {
            // Set default namespace
            string typeNamespace;

            if (!typeNamespaceTranslations.TryGetValue(type, out typeNamespace))
            {
                // Set the appropriate namespace
                if (NeedToPrefaceRootNamespace(type, codeGenerator))
                {
                    typeNamespace = string.IsNullOrEmpty(type.Namespace) ?
                                    rootNamespace :
                                    (rootNamespace + "." + type.Namespace);
                }
                else
                {
                    typeNamespace = type.Namespace;
                }

                // Cache the value for next time
                typeNamespaceTranslations[type] = typeNamespace;
            }

            return(typeNamespace);
        }
コード例 #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DataContractProxyGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.  Cannot be <c>null</c>.</param>
 /// <param name="type">The type to generate.  Cannot be null.</param>
 /// <param name="typeMapping">A dictionary of <see cref="DomainService"/> and related types that maps to their corresponding client-side <see cref="CodeTypeReference"/> representations.</param>
 protected DataContractProxyGenerator(CodeDomClientCodeGenerator proxyGenerator, Type type, IDictionary<Type, CodeTypeDeclaration> typeMapping)
     : base(proxyGenerator)
 {
     this.Type = type;
     this._typeMapping = typeMapping;
     this.NotificationMethodGen = new NotificationMethodGenerator(proxyGenerator);
     this._isRoundtripType = type.Attributes()[typeof(RoundtripOriginalAttribute)] != null;
 }
コード例 #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CustomMethodProxyGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.  Cannot be null.</param>
 /// <param name="proxyClass">Entity <see cref="CodeTypeDeclaration"/> into which to generate code</param>
 /// <param name="entityType">The type of the entity.  Cannot be null.</param>
 /// <param name="domainServiceDescriptions">Collection of all <see cref="DomainServiceDescription"/>s defined in this project</param>
 /// <param name="notificationMethodGen">Code generator for OnMethodName() methods</param>
 public CustomMethodProxyGenerator(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration proxyClass, Type entityType, ICollection<DomainServiceDescription> domainServiceDescriptions, NotificationMethodGenerator notificationMethodGen)
     : base(proxyGenerator)
 {
     this._entityType = entityType;
     this._proxyClass = proxyClass;
     this._domainServiceDescriptions = domainServiceDescriptions;
     this._notificationMethodGen = notificationMethodGen;
 }
コード例 #4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CustomMethodProxyGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.  Cannot be null.</param>
 /// <param name="proxyClass">Entity <see cref="CodeTypeDeclaration"/> into which to generate code</param>
 /// <param name="entityType">The type of the entity.  Cannot be null.</param>
 /// <param name="domainServiceDescriptions">Collection of all <see cref="DomainServiceDescription"/>s defined in this project</param>
 /// <param name="notificationMethodGen">Code generator for OnMethodName() methods</param>
 public CustomMethodProxyGenerator(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration proxyClass, Type entityType, ICollection <DomainServiceDescription> domainServiceDescriptions, NotificationMethodGenerator notificationMethodGen)
     : base(proxyGenerator)
 {
     this._entityType = entityType;
     this._proxyClass = proxyClass;
     this._domainServiceDescriptions = domainServiceDescriptions;
     this._notificationMethodGen     = notificationMethodGen;
 }
コード例 #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DataContractProxyGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.  Cannot be <c>null</c>.</param>
 /// <param name="type">The type to generate.  Cannot be null.</param>
 /// <param name="typeMapping">A dictionary of <see cref="DomainService"/> and related types that maps to their corresponding client-side <see cref="CodeTypeReference"/> representations.</param>
 protected DataContractProxyGenerator(CodeDomClientCodeGenerator proxyGenerator, Type type, IDictionary <Type, CodeTypeDeclaration> typeMapping)
     : base(proxyGenerator)
 {
     this.Type                  = type;
     this._typeMapping          = typeMapping;
     this.NotificationMethodGen = new NotificationMethodGenerator(proxyGenerator);
     this._isRoundtripType      = type.Attributes()[typeof(RoundtripOriginalAttribute)] != null;
 }
コード例 #6
0
        /// <summary>
        /// Generates code for the given custom attributes and adds them to the given <see cref="CodeAttributeDeclarationCollection"/>
        /// </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 to generate</param>
        /// <param name="outputCollection">The collection to which the generated attributes will be added</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>
        public static void GenerateCustomAttributes(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, Func <AttributeBuilderException, string> getLogWarningMessage, IEnumerable <Attribute> attributes, CodeAttributeDeclarationCollection outputCollection, CodeCommentStatementCollection comments, string customCommentHeader, bool forcePropagation)
        {
            IEnumerable <CodeAttributeDeclaration> cads = GenerateCustomAttributes(proxyGenerator, referencingType, getLogWarningMessage, attributes, comments, customCommentHeader, forcePropagation);

            foreach (var cad in cads)
            {
                outputCollection.Add(cad);
            }
        }
コード例 #7
0
        /// <summary>
        /// Creates the CodeDom CodeExpression for the given value.  Returns null if unable to generate a CodeExpression.
        /// </summary>
        /// <remarks>This method exists solely to help generate code for all object types that can appear in an
        /// attribute declaration, such as typeof()</remarks>
        /// <param name="proxyGenerator">The context for generating code.  It cannot be null.</param>
        /// <param name="referencingType">The referencing type</param>
        /// <param name="value">The value.  Null is permitted.</param>
        /// <returns>The code expression</returns>
        private static CodeExpression CreateCodeExpression(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, object value)
        {
            Type typeOfValue = value == null ? null : value.GetType();

            if (value == null || typeOfValue.IsPrimitive || value is string)
            {
                CodeExpression e = new CodePrimitiveExpression(value);

                // Workaround CodeDom issue -- it looks like CodePrimitiveExpression is fooled and generates double
                // literals as integers when there is no fraction.  We take a general strategy of forcing an explicit
                // compile time cast to ensure we recompile the same type.
                if (value != null && (value is double || value is float))
                {
                    e = new CodeCastExpression(value.GetType(), e);
                }
                return(e);
            }

            // typeof(T) requires special handling
            Type valueAsType = value as Type;

            if (valueAsType != null)
            {
                // Verify the type is shared
                // Don't know counts as not shared
                CodeMemberShareKind shareKind = proxyGenerator.GetTypeShareKind(valueAsType);
                if ((shareKind & CodeMemberShareKind.Shared) == 0)
                {
                    // Here we return a fully-qualified type name to ensure we don't cause compilation
                    // errors by adding invalid 'using' statements into our codedom graph.
                    CodeTypeReference valueTypeReference = CodeGenUtilities.GetTypeReference(valueAsType, proxyGenerator, referencingType, false, /*Use fully qualified name*/ true);
                    valueTypeReference.Options = CodeTypeReferenceOptions.GlobalReference;
                    return(new CodeTypeOfExpression(valueTypeReference));
                }

                return(new CodeTypeOfExpression(CodeGenUtilities.GetTypeReference(valueAsType, proxyGenerator, referencingType)));
            }

            // Enum values need special handling
            if (typeOfValue.IsEnum)
            {
                string enumValueName = Enum.GetName(typeOfValue, value);
                string enumTypeName;
                if (proxyGenerator.ClientProxyCodeGenerationOptions.UseFullTypeNames)
                {
                    enumTypeName = typeOfValue.FullName;
                }
                else
                {
                    enumTypeName = typeOfValue.Name;
                }
                return(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(enumTypeName), enumValueName));
            }

            return(null);
        }
コード例 #8
0
 /// <summary>
 /// Generates code for the given custom attributes and adds them to the given <see cref="CodeAttributeDeclarationCollection"/>
 /// </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 to generate</param>
 /// <param name="outputCollection">The collection to which the generated attributes will be added</param>
 /// <param name="comments">Collection of comments that should be updated if errors are discovered.</param>
 public static void GenerateCustomAttributes(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, Func <AttributeBuilderException, string> getLogWarningMessage, IEnumerable <Attribute> attributes, CodeAttributeDeclarationCollection outputCollection, CodeCommentStatementCollection comments)
 {
     GenerateCustomAttributes(
         proxyGenerator,
         referencingType,
         getLogWarningMessage,
         attributes,
         outputCollection,
         comments,
         Resource.ClientCodeGen_Attribute_FailedToGenerate);
 }
コード例 #9
0
        /// <summary>
        /// Creates a <see cref="CodeAttributeDeclaration"/> for a <see cref="DisplayAttribute"/>.
        /// </summary>
        /// <param name="codeGenerator">The client proxy generator</param>
        /// <param name="referencingType">The type on whose member <see cref="DisplayAttribute"/> will be applied</param>
        /// <returns>The new attribute declaration</returns>
        internal static CodeAttributeDeclaration CreateDisplayAttributeDeclaration(CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
        {
            CodeAttributeDeclaration displayAttributeDeclaration = CodeGenUtilities.CreateAttributeDeclaration(
                typeof(DisplayAttribute),
                codeGenerator,
                referencingType);

            displayAttributeDeclaration.Arguments.Add(new CodeAttributeArgument("AutoGenerateField", new CodePrimitiveExpression(false)));

            return(displayAttributeDeclaration);
        }
コード例 #10
0
 /// <summary>
 /// Generates code for the given custom attributes and adds them to the given <see cref="CodeAttributeDeclarationCollection"/>
 /// </summary>
 /// <param name="proxyGenerator">Root client proxy generator</param>
 /// <param name="referencingType">The referencing type</param>
 /// <param name="attributes">Collection of attributes to generate</param>
 /// <param name="outputCollection">The collection to which the generated attributes will be added</param>
 /// <param name="comments">Collection of comments that should be updated if errors are discovered.</param>
 /// <param name="forcePropagation">Indicates whether or not to force attribute propagation.</param>
 public static void GenerateCustomAttributes(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, IEnumerable <Attribute> attributes, CodeAttributeDeclarationCollection outputCollection, CodeCommentStatementCollection comments, bool forcePropagation)
 {
     GenerateCustomAttributes(
         proxyGenerator,
         referencingType,
         null,
         attributes,
         outputCollection,
         comments,
         Resource.ClientCodeGen_Attribute_FailedToGenerate,
         forcePropagation);
 }
コード例 #11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="EntityProxyGenerator"/> class.
        /// </summary>
        /// <param name="proxyGenerator">The client proxy generator against which this will generate code.  Cannot be null.</param>
        /// <param name="entityType">The type of the entity.  Cannot be null.</param>
        /// <param name="allDomainServiceDescriptions">Collection of all <see cref="DomainServiceDescription"/> defined in this project</param>
        /// <param name="typeMapping">A dictionary of <see cref="DomainService"/> and related entity types that maps to their corresponding client-side <see cref="CodeTypeReference"/> representations.</param>
        public EntityProxyGenerator(CodeDomClientCodeGenerator proxyGenerator, Type entityType, ICollection<DomainServiceDescription> allDomainServiceDescriptions, IDictionary<Type, CodeTypeDeclaration> typeMapping)
            : base(proxyGenerator, entityType, typeMapping)
        {
            this._domainServiceDescriptionAggregate = new DomainServiceDescriptionAggregate(allDomainServiceDescriptions.Where(dsd => dsd.EntityTypes.Contains(entityType)));
            this._allDomainServiceDescriptions = allDomainServiceDescriptions;

            // Determine this entity's logical (visible) base type based on the type hierarchy
            // and list of known types.  Null meant it was already the root.
            this._visibleBaseType = this._domainServiceDescriptionAggregate.GetEntityBaseType(this.Type);

            this._generateGetIdentity = !this.IsDerivedType;
            this._keyProperties = new List<PropertyDescriptor>();
        }
コード例 #12
0
        internal void Initialize(ICodeGenerationHost host, IEnumerable <DomainServiceDescription> descriptions, ClientCodeGenerationOptions options)
        {
            if (host == null)
            {
                throw new ArgumentNullException(nameof(host));
            }

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            if (descriptions == null)
            {
                throw new ArgumentNullException(nameof(descriptions));
            }

            // Initialize all the instance variables
            this._host = host;
            this._clientProxyCodeGenerationOptions = options;

            this._domainServiceDescriptions = descriptions.ToList();
            this._compileUnit = new CodeCompileUnit();

            this._namespaces          = new Dictionary <string, CodeNamespace>();
            this._enumTypesToGenerate = new HashSet <Type>();

            CodeDomClientCodeGenerator.ValidateOptions(this._clientProxyCodeGenerationOptions);

            // Unconditionally initialize some options
            CodeGeneratorOptions cgo = new CodeGeneratorOptions();

            cgo.IndentString             = "    ";
            cgo.VerbatimOrder            = false;
            cgo.BlankLinesBetweenMembers = true;
            cgo.BracingStyle             = "C";
            this._options = cgo;

            // Choose the provider for the language.  C# is the default if unspecified.
            string language = this.ClientProxyCodeGenerationOptions.Language;
            bool   isCSharp = String.IsNullOrEmpty(language) || String.Equals(language, "C#", StringComparison.OrdinalIgnoreCase);

            this._provider = isCSharp ? (CodeDomProvider) new CSharpCodeProvider() : (CodeDomProvider) new VBCodeProvider();

            // Configure our code gen utility package
            CodeGenUtilities.Initialize(!this.IsCSharp, this.ClientProxyCodeGenerationOptions.UseFullTypeNames, this.ClientProxyCodeGenerationOptions.ClientRootNamespace);
        }
コード例 #13
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NotificationMethodGenerator"/> class.
        /// </summary>
        /// <param name="proxyGenerator">The current <see cref="CodeDomClientCodeGenerator"/>.</param>
        /// <param name="indentLevel">The indentation level for the code to write.</param>
        public NotificationMethodGenerator(CodeDomClientCodeGenerator proxyGenerator, IndentationLevel indentLevel)
        {
            this.proxyGenerator = proxyGenerator;
            this.isCSharp = proxyGenerator.IsCSharp;
            int level = (int)indentLevel;
            if (level < 0)
            {
                level = (int)DefaultIndentLevel;
            }

            while (level-- > 0)
            {
                this.indent += IndentString;
            }

            this.AddMethodFor("Created", Resource.CommentOnCreated); // add default partial method.
        }
コード例 #14
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NotificationMethodGenerator"/> class.
        /// </summary>
        /// <param name="proxyGenerator">The current <see cref="CodeDomClientCodeGenerator"/>.</param>
        /// <param name="indentLevel">The indentation level for the code to write.</param>
        public NotificationMethodGenerator(CodeDomClientCodeGenerator proxyGenerator, IndentationLevel indentLevel)
        {
            this.proxyGenerator = proxyGenerator;
            this.isCSharp       = proxyGenerator.IsCSharp;
            int level = (int)indentLevel;

            if (level < 0)
            {
                level = (int)DefaultIndentLevel;
            }

            while (level-- > 0)
            {
                this.indent += IndentString;
            }

            this.AddMethodFor("Created", Resource.CommentOnCreated); // add default partial method.
        }
コード例 #15
0
        /// <summary>
        /// Determines if we need to preface the root namespace to the type
        /// </summary>
        /// <param name="type">The type in question</param>
        /// <param name="codeGenerator">The current proxy generator</param>
        /// <returns><c>true</c> if if we need to preface the root namespace to the type, <c>false</c> otherwise</returns>
        private static bool NeedToPrefaceRootNamespace(Type type, CodeDomClientCodeGenerator codeGenerator)
        {
            // System assemblies never preface with the root namespace
            if (type.Assembly.IsSystemAssembly())
            {
                return(false);
            }
            bool isVbProjectWithRootNamespace = !codeGenerator.IsCSharp && !string.IsNullOrEmpty(codeGenerator.ClientProxyCodeGenerationOptions.ClientRootNamespace);

            bool typeIsGeneratedOnTheClient = (type.IsEnum && codeGenerator.NeedToGenerateEnumType(type)) ||
                                              codeGenerator.DomainServiceDescriptions.Any(dsd => dsd.EntityTypes.Contains(type) || dsd.ComplexTypes.Contains(type) || dsd.DomainServiceType == type);

            bool typeNameStartsWithRootNamespace =
                string.Equals(type.Namespace, rootNamespace, StringComparison.Ordinal) ||
                (!string.IsNullOrEmpty(type.Namespace) && type.Namespace.StartsWith(rootNamespace + ".", StringComparison.Ordinal));

            return(isVbProjectWithRootNamespace && typeIsGeneratedOnTheClient && !typeNameStartsWithRootNamespace);
        }
コード例 #16
0
        /// <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);
        }
コード例 #17
0
        /// <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());
        }
コード例 #18
0
        /// <summary>
        /// Creates an attribute declaration based on the specified attribute
        /// </summary>
        /// <param name="attributeType">type of the attribute</param>
        /// <param name="codeGenerator">A <see cref="CodeDomClientCodeGenerator"/>.</param>
        /// <param name="referencingType">The referencing type.</param>
        /// <returns>the attribute declaration</returns>
        internal static CodeAttributeDeclaration CreateAttributeDeclaration(Type attributeType, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
        {
            if (!typeof(Attribute).IsAssignableFrom(attributeType))
            {
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Resource.Type_Must_Be_Attribute, attributeType.Name), nameof(attributeType));
            }

            CodeTypeReference attribute = GetTypeReference(attributeType, codeGenerator, referencingType, true);

            return(new CodeAttributeDeclaration(attribute));
        }
コード例 #19
0
 /// <summary>
 /// Gets a <see cref="CodeTypeReference"/> for a CLR type.
 /// </summary>
 /// <param name="type">A CLR type.</param>
 /// <param name="codeGenerator">A <see cref="CodeDomClientCodeGenerator"/>.</param>
 /// <param name="referencingType">The referencing type.</param>
 /// <returns>A <see cref="CodeTypeReference"/> for a CLR type.</returns>
 internal static CodeTypeReference GetTypeReference(Type type, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
 {
     return GetTypeReference(type, codeGenerator, referencingType, false, false);
 }
コード例 #20
0
        /// <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);
        }
コード例 #21
0
        /// <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));
                }
            }
        }
コード例 #22
0
 /// <summary>
 /// Gets a <see cref="CodeTypeReference"/> for a CLR type.
 /// </summary>
 /// <param name="type">A CLR type.</param>
 /// <param name="codeGenerator">A <see cref="CodeDomClientCodeGenerator"/>.</param>
 /// <param name="referencingType">The referencing type.</param>
 /// <param name="optimizeAttributeName">Indicates whether or not the optimize <see cref="Attribute"/> names by removing the "Attribute" suffix.</param>
 /// <returns>A <see cref="CodeTypeReference"/> for a CLR type.</returns>
 internal static CodeTypeReference GetTypeReference(Type type, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType, bool optimizeAttributeName)
 {
     return(GetTypeReference(type, codeGenerator, referencingType, optimizeAttributeName, false));
 }
コード例 #23
0
        /// <summary>
        /// Creates a <see cref="CodeAttributeDeclaration"/> for a <see cref="DataContractAttribute"/>
        /// </summary>
        /// <param name="sourceType">The type to which the attribute will be applied (to use as a reference)</param>
        /// <param name="codeGenerator">The client proxy generator</param>
        /// <param name="referencingType">The type referencing this declaration</param>
        /// <returns>The new attribute declaration</returns>
        internal static CodeAttributeDeclaration CreateDataContractAttributeDeclaration(Type sourceType, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
        {
            CodeAttributeDeclaration dataContractAttrib = CodeGenUtilities.CreateAttributeDeclaration(typeof(System.Runtime.Serialization.DataContractAttribute), codeGenerator, referencingType);

            string dataContractNamespace = CodeGenUtilities.GetContractNamespace(sourceType);
            string dataContractName = null;

            // If the user specified a DataContract, we should copy the namespace and name. 
            DataContractAttribute sourceDataContractAttrib = (DataContractAttribute)Attribute.GetCustomAttribute(sourceType, typeof(DataContractAttribute));
            if (sourceDataContractAttrib != null)
            {
                if (sourceDataContractAttrib.Namespace != null)
                {
                    dataContractNamespace = sourceDataContractAttrib.Namespace;
                }
                if (sourceDataContractAttrib.Name != null)
                {
                    dataContractName = sourceDataContractAttrib.Name;
                }
            }

            dataContractAttrib.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(dataContractNamespace)));
            if (dataContractName != null)
            {
                dataContractAttrib.Arguments.Add(new CodeAttributeArgument("Name", new CodePrimitiveExpression(dataContractName)));
            }
            return dataContractAttrib;
        }
コード例 #24
0
        /// <summary>
        /// Determines if we need to preface the root namespace to the type
        /// </summary>
        /// <param name="type">The type in question</param>
        /// <param name="codeGenerator">The current proxy generator</param>
        /// <returns><c>true</c> if if we need to preface the root namespace to the type, <c>false</c> otherwise</returns>
        private static bool NeedToPrefaceRootNamespace(Type type, CodeDomClientCodeGenerator codeGenerator)
        {
            // System assemblies never preface with the root namespace
            if (type.Assembly.IsSystemAssembly())
            {
                return false;
            }
            bool isVbProjectWithRootNamespace = !codeGenerator.IsCSharp && !string.IsNullOrEmpty(codeGenerator.ClientProxyCodeGenerationOptions.ClientRootNamespace);

            bool typeIsGeneratedOnTheClient = (type.IsEnum && codeGenerator.NeedToGenerateEnumType(type)) ||
                codeGenerator.DomainServiceDescriptions.Any(dsd => dsd.EntityTypes.Contains(type) || dsd.ComplexTypes.Contains(type) || dsd.DomainServiceType == type);

            bool typeNameStartsWithRootNamespace = 
                string.Equals(type.Namespace, rootNamespace, StringComparison.Ordinal) ||
                (!string.IsNullOrEmpty(type.Namespace) && type.Namespace.StartsWith(rootNamespace + ".", StringComparison.Ordinal));

            return isVbProjectWithRootNamespace && typeIsGeneratedOnTheClient && !typeNameStartsWithRootNamespace;
        }
コード例 #25
0
 /// <summary>
 /// Initializes a new instance of the <see cref="InvokeOperationProxyGenerator"/> class.
 /// </summary>
 /// <param name="clientProxyGenerator">The client proxy generator against which this will generate code.  Cannot be null.</param>
 /// <param name="proxyClass">The class into which to inject the generated code</param>
 /// <param name="domainServiceDescription">The description for the DomainService we're generating for</param>
 public InvokeOperationProxyGenerator(CodeDomClientCodeGenerator clientProxyGenerator, CodeTypeDeclaration proxyClass, DomainServiceDescription domainServiceDescription)
     : base(clientProxyGenerator)
 {
     this._proxyClass = proxyClass;
     this._domainServiceDescription = domainServiceDescription;
 }
コード例 #26
0
        /// <summary>
        /// Creates an attribute declaration for <see cref="EnumMemberAttribute"/>
        /// </summary>
        /// <param name="memberInfo">The member that may contain an existing <see cref="EnumMemberAttribute"/></param>
        /// <param name="codeGenerator">The proxy generator</param>
        /// <param name="referencingType">The referencing type</param>
        /// <returns>A new attribute declaration</returns>
        internal static CodeAttributeDeclaration CreateEnumMemberAttributeDeclaration(MemberInfo memberInfo, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
        {
            CodeAttributeDeclaration enumMemberDecl = CodeGenUtilities.CreateAttributeDeclaration(typeof(System.Runtime.Serialization.EnumMemberAttribute), codeGenerator, referencingType);

            // If the user specified a DataContract, we should copy the namespace and name.
            EnumMemberAttribute enumMemberAttrib = (EnumMemberAttribute)Attribute.GetCustomAttribute(memberInfo, typeof(EnumMemberAttribute));

            if (enumMemberAttrib != null)
            {
                string value = enumMemberAttrib.Value;
                if (!string.IsNullOrEmpty(value))
                {
                    enumMemberDecl.Arguments.Add(new CodeAttributeArgument("Value", new CodePrimitiveExpression(value)));
                }
            }
            return(enumMemberDecl);
        }
コード例 #27
0
        /// <summary>
        /// Creates a new <see cref="CodeTypeDeclaration"/> that is the generated form of
        /// the given <paramref name="enumType"/>.
        /// </summary>
        /// <param name="enumType">The enum type to generate.</param>
        /// <param name="codeGenerator">The current proxy generator context.</param>
        /// <returns>The newly generated enum type declaration.</returns>
        internal static CodeTypeDeclaration CreateEnumTypeDeclaration(Type enumType, CodeDomClientCodeGenerator codeGenerator)
        {
            System.Diagnostics.Debug.Assert(enumType.IsEnum, "Type must be an enum type");

            CodeTypeDeclaration typeDecl = CodeGenUtilities.CreateTypeDeclaration(enumType);

            typeDecl.IsEnum = true;

            // Always force generated enums to be public
            typeDecl.TypeAttributes |= TypeAttributes.Public;

            // Enums deriving from anything but int get an explicit base type
            Type underlyingType = enumType.GetEnumUnderlyingType();

            if (underlyingType != typeof(int))
            {
                typeDecl.BaseTypes.Add(new CodeTypeReference(underlyingType));
            }

            typeDecl.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment($"Enum {enumType.Name}", codeGenerator.IsCSharp));

            // Generate [DataContract] if it appears in the original only.  Use Reflection only because that matches
            // what WCF will do.
            DataContractAttribute dataContractAttr = (DataContractAttribute)Attribute.GetCustomAttribute(enumType, typeof(DataContractAttribute));

            if (dataContractAttr != null)
            {
                CodeAttributeDeclaration attrDecl = CodeGenUtilities.CreateDataContractAttributeDeclaration(enumType, codeGenerator, typeDecl);
                typeDecl.CustomAttributes.Add(attrDecl);
            }

            string[] memberNames   = Enum.GetNames(enumType);
            Type     enumValueType = Enum.GetUnderlyingType(enumType);

            for (int i = 0; i < memberNames.Length; ++i)
            {
                string            memberName  = memberNames[i];
                CodeTypeReference enumTypeRef = CodeGenUtilities.GetTypeReference(enumValueType, codeGenerator, typeDecl);
                CodeMemberField   enumMember  = new CodeMemberField(enumTypeRef, memberName);

                enumMember.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(memberName, codeGenerator.IsCSharp));

                // Generate an initializer for the enum member.
                // GetRawConstantValue is the safest way to get the raw value of the enum field
                // and works for both Reflection and ReflectionOnly loaded assemblies.
                FieldInfo fieldInfo = enumType.GetField(memberName);
                if (fieldInfo != null)
                {
                    object memberValue = fieldInfo.GetRawConstantValue();

                    Debug.Assert(memberValue != null, "Enum type's GetRawConstantValue should never return null");

                    // We special-case MinValue and MaxValue for the integral types
                    // because VisualBasic will generate overflow compiler error for
                    // Int64.MinValue.   If we detect a known MinValue or MaxValue for
                    // this integral type, we generate that reference, otherwise we
                    // just generate a constant integral value of the enum's type
                    object[] minMaxValues = null;
                    CodeGenUtilities.integralMinMaxValues.TryGetValue(underlyingType, out minMaxValues);
                    Debug.Assert(minMaxValues == null || minMaxValues.Length == 3, "integralMinMaxValues elements must always contain 3 values");

                    // Gen xxx.MinValue if it matches, but give precedence to matching a true zero,
                    // which is the min value for the unsigned integral types
                    // minMaxValues[0]: the MinValue for this type
                    // minMaxValues[1]: the MaxValue for this type
                    // minMaxValues[2]: the zero for this type (memberValue is not boxed and cannot be cast)
                    if (minMaxValues != null && !memberValue.Equals(minMaxValues[2]) && memberValue.Equals(minMaxValues[0]))
                    {
                        enumMember.InitExpression = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(underlyingType), "MinValue");
                    }
                    // Gen xxx.MaxValue if it matches
                    else if (minMaxValues != null && memberValue.Equals(minMaxValues[1]))
                    {
                        enumMember.InitExpression = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(underlyingType), "MaxValue");
                    }
                    // All other cases generate an integral constant.
                    // CodeDom knows how to generate the right integral constant based on memberValue's type.
                    else
                    {
                        enumMember.InitExpression = new CodePrimitiveExpression(memberValue);
                    }
                }

                typeDecl.Members.Add(enumMember);

                // Generate an [EnumMember] if appropriate
                EnumMemberAttribute enumMemberAttr = (EnumMemberAttribute)Attribute.GetCustomAttribute(fieldInfo, typeof(EnumMemberAttribute));
                if (enumMemberAttr != null)
                {
                    CodeAttributeDeclaration enumAttrDecl = CodeGenUtilities.CreateEnumMemberAttributeDeclaration(fieldInfo, codeGenerator, typeDecl);
                    enumMember.CustomAttributes.Add(enumAttrDecl);
                }

                // Propagate any other attributes that can be seen by the client
                CustomAttributeGenerator.GenerateCustomAttributes(
                    codeGenerator,
                    typeDecl,
                    ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeTypeMember, ex.Message, fieldInfo.Name, typeDecl.Name, ex.InnerException.Message),
                    fieldInfo.GetCustomAttributes(false).Cast <Attribute>().Where(a => a.GetType() != typeof(EnumMemberAttribute)),
                    enumMember.CustomAttributes,
                    enumMember.Comments);
            }

            // Attributes marked with [Flag] propagate it
            if (enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0)
            {
                CodeAttributeDeclaration attrDecl = CodeGenUtilities.CreateAttributeDeclaration(typeof(FlagsAttribute), codeGenerator, typeDecl);
                typeDecl.CustomAttributes.Add(attrDecl);
            }
            return(typeDecl);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="DomainOperationEntryProxyGenerator"/> class.
 /// </summary>
 /// <param name="clientProxyGenerator">The client proxy generator against which this will generate code.  Cannot be null.</param>
 /// <param name="proxyClass">The class into which to inject the generated code</param>
 /// <param name="domainServiceDescription">The description for the DomainService we're generating for</param>
 public DomainOperationEntryProxyGenerator(CodeDomClientCodeGenerator clientProxyGenerator, CodeTypeDeclaration proxyClass, DomainServiceDescription domainServiceDescription)
     : base(clientProxyGenerator)
 {
     this._proxyClass = proxyClass;
     this._domainServiceDescription = domainServiceDescription;
 }
コード例 #29
0
        /// <summary>
        /// Creates a <see cref="CodeAttributeDeclaration"/> for a <see cref="DataContractAttribute"/>
        /// </summary>
        /// <param name="sourceType">The type to which the attribute will be applied (to use as a reference)</param>
        /// <param name="codeGenerator">The client proxy generator</param>
        /// <param name="referencingType">The type referencing this declaration</param>
        /// <returns>The new attribute declaration</returns>
        internal static CodeAttributeDeclaration CreateDataContractAttributeDeclaration(Type sourceType, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
        {
            CodeAttributeDeclaration dataContractAttrib = CodeGenUtilities.CreateAttributeDeclaration(typeof(System.Runtime.Serialization.DataContractAttribute), codeGenerator, referencingType);

            string dataContractNamespace = CodeGenUtilities.GetContractNamespace(sourceType);
            string dataContractName      = null;

            // If the user specified a DataContract, we should copy the namespace and name.
            DataContractAttribute sourceDataContractAttrib = (DataContractAttribute)Attribute.GetCustomAttribute(sourceType, typeof(DataContractAttribute));

            if (sourceDataContractAttrib != null)
            {
                if (sourceDataContractAttrib.Namespace != null)
                {
                    dataContractNamespace = sourceDataContractAttrib.Namespace;
                }
                if (sourceDataContractAttrib.Name != null)
                {
                    dataContractName = sourceDataContractAttrib.Name;
                }
            }

            dataContractAttrib.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(dataContractNamespace)));
            if (dataContractName != null)
            {
                dataContractAttrib.Arguments.Add(new CodeAttributeArgument("Name", new CodePrimitiveExpression(dataContractName)));
            }
            return(dataContractAttrib);
        }
コード例 #30
0
        /// <summary>
        /// Gets a <see cref="CodeTypeReference"/> for a CLR type.
        /// </summary>
        /// <param name="type">A CLR type.</param>
        /// <param name="codeGenerator">A <see cref="CodeDomClientCodeGenerator"/>.</param>
        /// <param name="referencingType">The referencing type.</param>
        /// <param name="optimizeAttributeName">Indicates whether or not to optimize <see cref="Attribute"/> names by removing the "Attribute" suffix.</param>
        /// <param name="forceUseFullyQualifiedName">Indicates whether or not to generate the type using the fully qualified name irrespective the global setting.</param>
        /// <returns>A <see cref="CodeTypeReference"/> for a CLR type.</returns>
        internal static CodeTypeReference GetTypeReference(Type type, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType, bool optimizeAttributeName, bool forceUseFullyQualifiedName)
        {
            string typeName      = type.Name;
            string typeNamespace = type.Namespace;

            // Add an import statement to the referencing type if needed
            CodeNamespace     ns = codeGenerator.GetNamespace(referencingType);
            CodeTypeReference codeTypeReference = null;

            // Attribute?  If so, we special case these and remove the 'Attribute' suffix if present.
            if (optimizeAttributeName)
            {
                typeName = OptimizeAttributeName(type);
            }

            // Determine if we should generate this type with a full type name
            bool useFullyQualifiedName = forceUseFullyQualifiedName || CodeGenUtilities.useFullTypeNames || RegisterTypeName(typeNamespace, typeName, ns.Name);

            // Make sure we take into account root namespace in VB codegen.
            typeNamespace = TranslateNamespace(type, codeGenerator);

            // Conditionally add an import statement.  Skip this step if we need to generate a full
            // type name, if we're already in the target namespace, or if the type is in the global namespace.
            if (!useFullyQualifiedName && !ns.Name.Equals(type.Namespace) && !string.IsNullOrEmpty(type.Namespace))
            {
                // If the namespace is already imported, the following line will be a no-op.
                ns.Imports.Add(new CodeNamespaceImport(typeNamespace));
            }

            // If forced using Fully Qualified names, dont look up or store the code reference in the cache. That is because,
            // we force the use of fully qualified names only in certain cases. Caching at this time will cause the fully qualified name
            // to be used every time.
            bool useCache = !forceUseFullyQualifiedName;

            // See if we already have a reference for this type
            Tuple <CodeNamespace, Type> tupleKey = new Tuple <CodeNamespace, Type>(ns, type);

            if (!useCache || !CodeGenUtilities.codeTypeReferences.TryGetValue(tupleKey, out codeTypeReference))
            {
                if (useFullyQualifiedName && !string.IsNullOrEmpty(typeNamespace))
                {
                    // While this splicing may seem awkward, we perform this task
                    // rather than rely on 'type.FullName' as we may have performed
                    // a VB root namespace translation task above.
                    typeName = typeNamespace + "." + typeName;
                }

                // If not, create a new type reference. Use the constructor for CodeTypeReference
                // that takes a type's name rather than type to generate short names.
                if (type.IsArray)
                {
                    codeTypeReference = new CodeTypeReference(
                        CodeGenUtilities.GetTypeReference(type.GetElementType(), codeGenerator, referencingType, /* optimizeAttributeName */ false, forceUseFullyQualifiedName),
                        type.GetArrayRank());
                }
                else if (type.IsGenericType)
                {
                    Type[] genericArguments           = type.GetGenericArguments();
                    CodeTypeReference[] typeArguments = new CodeTypeReference[genericArguments.Length];
                    for (int i = 0; i < genericArguments.Length; i++)
                    {
                        typeArguments[i] = GetTypeReference(genericArguments[i], codeGenerator, referencingType);
                    }
                    codeTypeReference = new CodeTypeReference(typeName, typeArguments);
                }
                else
                {
                    // Generate language-specific shorthands for core types by using CodeTypeReference constructor that takes a Type
                    if (type.IsPrimitive || type == typeof(void) || type == typeof(decimal) || type == typeof(string) || type == typeof(object))
                    {
                        codeTypeReference = new CodeTypeReference(type);
                    }
                    else
                    {
                        codeTypeReference = new CodeTypeReference(typeName);
                    }
                }

                // Keep track of the CLR type for identification purposes.
                codeTypeReference.UserData["ClrType"] = type;

                // Cache for later use.
                if (useCache)
                {
                    CodeGenUtilities.codeTypeReferences.Add(tupleKey, codeTypeReference);
                }
            }

            return(codeTypeReference);
        }
コード例 #31
0
 /// <summary>
 /// Initializes a new instance of the <see cref="WebContextGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.</param>
 internal WebContextGenerator(CodeDomClientCodeGenerator proxyGenerator)
     : base(proxyGenerator)
 {
 }
コード例 #32
0
 /// <summary>
 /// Initializes a new instance of the <see cref="NotificationMethodGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The current <see cref="CodeDomClientCodeGenerator"/>.</param>
 public NotificationMethodGenerator(CodeDomClientCodeGenerator proxyGenerator) :
     this(proxyGenerator, DefaultIndentLevel)
 {
 }
コード例 #33
0
 /// <summary>
 /// Initializes a new instance of the <see cref="NotificationMethodGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The current <see cref="CodeDomClientCodeGenerator"/>.</param>
 public NotificationMethodGenerator(CodeDomClientCodeGenerator proxyGenerator) :
     this(proxyGenerator, DefaultIndentLevel)
 {
 }
コード例 #34
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ComplexTypeProxyGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.  Cannot be null.</param>
 /// <param name="complexType">The complex type.  Cannot be null.</param>
 /// <param name="domainServiceDescription"><see cref="DomainServiceDescription"/> that exposes this complex type.</param>
 /// <param name="typeMapping">A dictionary of <see cref="DomainService"/> and related complex types that maps to their corresponding client-side <see cref="CodeTypeReference"/> representations.</param>
 public ComplexTypeProxyGenerator(CodeDomClientCodeGenerator proxyGenerator, Type complexType, DomainServiceDescription domainServiceDescription, IDictionary <Type, CodeTypeDeclaration> typeMapping)
     : base(proxyGenerator, complexType, typeMapping)
 {
     this._domainServiceDescription = domainServiceDescription;
 }
コード例 #35
0
 /// <summary>
 /// Generates code for the given custom attributes and adds them to the given <see cref="CodeAttributeDeclarationCollection"/>
 /// </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 to generate</param>
 /// <param name="outputCollection">The collection to which the generated attributes will be added</param>
 /// <param name="comments">Collection of comments that should be updated if errors are discovered.</param>
 public static void GenerateCustomAttributes(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, Func<AttributeBuilderException, string> getLogWarningMessage, IEnumerable<Attribute> attributes, CodeAttributeDeclarationCollection outputCollection, CodeCommentStatementCollection comments)
 {
     GenerateCustomAttributes(
         proxyGenerator,
         referencingType,
         getLogWarningMessage,
         attributes,
         outputCollection,
         comments,
         Resource.ClientCodeGen_Attribute_FailedToGenerate);
 }
コード例 #36
0
 /// <summary>
 /// Gets a <see cref="CodeTypeReference"/> for a CLR type.
 /// </summary>
 /// <param name="type">A CLR type.</param>
 /// <param name="codeGenerator">A <see cref="CodeDomClientCodeGenerator"/>.</param>
 /// <param name="referencingType">The referencing type.</param>
 /// <returns>A <see cref="CodeTypeReference"/> for a CLR type.</returns>
 internal static CodeTypeReference GetTypeReference(Type type, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
 {
     return(GetTypeReference(type, codeGenerator, referencingType, false, false));
 }
コード例 #37
0
        /// <summary>
        /// Creates an attribute declaration for <see cref="EnumMemberAttribute"/>
        /// </summary>
        /// <param name="memberInfo">The member that may contain an existing <see cref="EnumMemberAttribute"/></param>
        /// <param name="codeGenerator">The proxy generator</param>
        /// <param name="referencingType">The referencing type</param>
        /// <returns>A new attribute declaration</returns>
        internal static CodeAttributeDeclaration CreateEnumMemberAttributeDeclaration(MemberInfo memberInfo, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
        {
            CodeAttributeDeclaration enumMemberDecl = CodeGenUtilities.CreateAttributeDeclaration(typeof(System.Runtime.Serialization.EnumMemberAttribute), codeGenerator, referencingType);

            // If the user specified a DataContract, we should copy the namespace and name. 
            EnumMemberAttribute enumMemberAttrib = (EnumMemberAttribute)Attribute.GetCustomAttribute(memberInfo, typeof(EnumMemberAttribute));
            if (enumMemberAttrib != null)
            {
                string value = enumMemberAttrib.Value;
                if (!string.IsNullOrEmpty(value))
                {
                    enumMemberDecl.Arguments.Add(new CodeAttributeArgument("Value", new CodePrimitiveExpression(value)));
                }
            }
            return enumMemberDecl;
        }
コード例 #38
0
        /// <summary>
        /// In cases where we are emitting types that aren't already in the root namespace, 
        /// we need to translate the generated type namespace so that it resides in the 
        /// root namespace.
        /// </summary>
        /// <remarks>
        /// Here, we're interested in cases where we're generating VB code
        /// and our target project has a non-null root namespace.  
        /// </remarks>
        /// <param name="type">The type who namespace should be translated</param>
        /// <param name="codeGenerator">The current proxy generator</param>
        /// <returns>A translated namespace string</returns>
        internal static string TranslateNamespace(Type type, CodeDomClientCodeGenerator codeGenerator)
        {
            // Set default namespace
            string typeNamespace;

            if (!typeNamespaceTranslations.TryGetValue(type, out typeNamespace))
            {
                // Set the appropriate namespace
                if (NeedToPrefaceRootNamespace(type, codeGenerator))
                {
                    typeNamespace = string.IsNullOrEmpty(type.Namespace) ? 
                        rootNamespace :
                        (rootNamespace + "." + type.Namespace);
                }
                else
                {
                    typeNamespace = type.Namespace;
                }

                // Cache the value for next time
                typeNamespaceTranslations[type] = typeNamespace;
            }

            return typeNamespace;
        }
コード例 #39
0
        /// <summary>
        /// Creates a <see cref="CodeAttributeDeclaration"/> for a <see cref="DisplayAttribute"/>.
        /// </summary>
        /// <param name="codeGenerator">The client proxy generator</param>
        /// <param name="referencingType">The type on whose member <see cref="DisplayAttribute"/> will be applied</param>
        /// <returns>The new attribute declaration</returns>
        internal static CodeAttributeDeclaration CreateDisplayAttributeDeclaration(CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
        {
            CodeAttributeDeclaration displayAttributeDeclaration = CodeGenUtilities.CreateAttributeDeclaration(
                typeof(DisplayAttribute), 
                codeGenerator, 
                referencingType);

            displayAttributeDeclaration.Arguments.Add(new CodeAttributeArgument("AutoGenerateField", new CodePrimitiveExpression(false)));

            return displayAttributeDeclaration;
        }
コード例 #40
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DomainServiceProxyGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.  Cannot be null.</param>
 /// <param name="domainServiceDescription">The domain service description to use as source metadata</param>
 /// <param name="typeMapping">A dictionary of <see cref="DomainService"/> and related entity types that maps to their corresponding client-side <see cref="CodeTypeReference"/> representations.</param>
 public DomainServiceProxyGenerator(CodeDomClientCodeGenerator proxyGenerator, DomainServiceDescription domainServiceDescription, IDictionary <Type, CodeTypeDeclaration> typeMapping)
     : base(proxyGenerator)
 {
     this._domainServiceDescription = domainServiceDescription;
     this._typeMapping = typeMapping;
 }
コード例 #41
0
        /// <summary>
        /// Gets a <see cref="CodeTypeReference"/> for a CLR type.
        /// </summary>
        /// <param name="type">A CLR type.</param>
        /// <param name="codeGenerator">A <see cref="CodeDomClientCodeGenerator"/>.</param>
        /// <param name="referencingType">The referencing type.</param>
        /// <param name="optimizeAttributeName">Indicates whether or not to optimize <see cref="Attribute"/> names by removing the "Attribute" suffix.</param>
        /// <param name="forceUseFullyQualifiedName">Indicates whether or not to generate the type using the fully qualified name irrespective the global setting.</param>
        /// <returns>A <see cref="CodeTypeReference"/> for a CLR type.</returns>
        internal static CodeTypeReference GetTypeReference(Type type, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType, bool optimizeAttributeName, bool forceUseFullyQualifiedName)
        {
            string typeName = type.Name;
            string typeNamespace = type.Namespace;

            // Add an import statement to the referencing type if needed
            CodeNamespace ns = codeGenerator.GetNamespace(referencingType);
            CodeTypeReference codeTypeReference = null;

            // Attribute?  If so, we special case these and remove the 'Attribute' suffix if present.
            if (optimizeAttributeName)
            {
                typeName = OptimizeAttributeName(type);
            }

            // Determine if we should generate this type with a full type name
            bool useFullyQualifiedName = forceUseFullyQualifiedName || CodeGenUtilities.useFullTypeNames || RegisterTypeName(typeNamespace, typeName, ns.Name);

            // Make sure we take into account root namespace in VB codegen.
            typeNamespace = TranslateNamespace(type, codeGenerator);

            // Conditionally add an import statement.  Skip this step if we need to generate a full
            // type name, if we're already in the target namespace, or if the type is in the global namespace.
            if (!useFullyQualifiedName && !ns.Name.Equals(type.Namespace) && !string.IsNullOrEmpty(type.Namespace))
            {
                // If the namespace is already imported, the following line will be a no-op.
                ns.Imports.Add(new CodeNamespaceImport(typeNamespace));
            }

            // If forced using Fully Qualified names, dont look up or store the code reference in the cache. That is because, 
            // we force the use of fully qualified names only in certain cases. Caching at this time will cause the fully qualified name 
            // to be used every time. 
            bool useCache = !forceUseFullyQualifiedName;

            // See if we already have a reference for this type            
            Tuple<CodeNamespace, Type> tupleKey = new Tuple<CodeNamespace, Type>(ns, type);
            if (!useCache || !CodeGenUtilities.codeTypeReferences.TryGetValue(tupleKey, out codeTypeReference))
            {
                if (useFullyQualifiedName && !string.IsNullOrEmpty(typeNamespace))
                {
                    // While this splicing may seem awkward, we perform this task
                    // rather than rely on 'type.FullName' as we may have performed
                    // a VB root namespace translation task above.
                    typeName = typeNamespace + "." + typeName;
                }

                // If not, create a new type reference. Use the constructor for CodeTypeReference
                // that takes a type's name rather than type to generate short names.
                if (type.IsArray)
                {
                    codeTypeReference = new CodeTypeReference(
                        CodeGenUtilities.GetTypeReference(type.GetElementType(), codeGenerator, referencingType, /* optimizeAttributeName */ false, forceUseFullyQualifiedName),
                        type.GetArrayRank());
                }
                else if (type.IsGenericType)
                {
                    Type[] genericArguments = type.GetGenericArguments();
                    CodeTypeReference[] typeArguments = new CodeTypeReference[genericArguments.Length];
                    for (int i = 0; i < genericArguments.Length; i++)
                    {
                        typeArguments[i] = GetTypeReference(genericArguments[i], codeGenerator, referencingType);
                    }
                    codeTypeReference = new CodeTypeReference(typeName, typeArguments);
                }
                else
                {
                    // Generate language-specific shorthands for core types by using CodeTypeReference constructor that takes a Type
                    if (type.IsPrimitive || type == typeof(void) || type == typeof(decimal) || type == typeof(string) || type == typeof(object))
                    {
                        codeTypeReference = new CodeTypeReference(type);
                    }
                    else
                    {
                        codeTypeReference = new CodeTypeReference(typeName);
                    }
                }

                // Keep track of the CLR type for identification purposes.
                codeTypeReference.UserData["ClrType"] = type;

                // Cache for later use.
                if (useCache)
                {
                    CodeGenUtilities.codeTypeReferences.Add(tupleKey, codeTypeReference);
                }
            }

            return codeTypeReference;
        }
コード例 #42
0
        /// <summary>
        /// Creates a new <see cref="CodeTypeDeclaration"/> that is the generated form of
        /// the given <paramref name="enumType"/>.
        /// </summary>
        /// <param name="enumType">The enum type to generate.</param>
        /// <param name="codeGenerator">The current proxy generator context.</param>
        /// <returns>The newly generated enum type declaration.</returns>
        internal static CodeTypeDeclaration CreateEnumTypeDeclaration(Type enumType, CodeDomClientCodeGenerator codeGenerator)
        {
            System.Diagnostics.Debug.Assert(enumType.IsEnum, "Type must be an enum type");

            CodeTypeDeclaration typeDecl = CodeGenUtilities.CreateTypeDeclaration(enumType);
            typeDecl.IsEnum = true;

            // Always force generated enums to be public
            typeDecl.TypeAttributes |= TypeAttributes.Public;

            // Enums deriving from anything but int get an explicit base type
            Type underlyingType = enumType.GetEnumUnderlyingType();
            if (underlyingType != typeof(int))
            {
                typeDecl.BaseTypes.Add(new CodeTypeReference(underlyingType));
            }

            // Generate [DataContract] if it appears in the original only.  Use Reflection only because that matches
            // what WCF will do.
            DataContractAttribute dataContractAttr = (DataContractAttribute)Attribute.GetCustomAttribute(enumType, typeof(DataContractAttribute));
            if (dataContractAttr != null)
            {
                CodeAttributeDeclaration attrDecl = CodeGenUtilities.CreateDataContractAttributeDeclaration(enumType, codeGenerator, typeDecl);
                typeDecl.CustomAttributes.Add(attrDecl);
            }

            string[] memberNames = Enum.GetNames(enumType);
            Type enumValueType = Enum.GetUnderlyingType(enumType);
            for (int i = 0; i < memberNames.Length; ++i)
            {
                string memberName = memberNames[i];
                CodeTypeReference enumTypeRef = CodeGenUtilities.GetTypeReference(enumValueType, codeGenerator, typeDecl);
                CodeMemberField enumMember = new CodeMemberField(enumTypeRef, memberName);

                // Generate an initializer for the enum member.
                // GetRawConstantValue is the safest way to get the raw value of the enum field
                // and works for both Reflection and ReflectionOnly loaded assemblies.
                FieldInfo fieldInfo = enumType.GetField(memberName);
                if (fieldInfo != null)
                {
                    object memberValue = fieldInfo.GetRawConstantValue();

                    Debug.Assert(memberValue != null, "Enum type's GetRawConstantValue should never return null");

                    // We special-case MinValue and MaxValue for the integral types
                    // because VisualBasic will generate overflow compiler error for
                    // Int64.MinValue.   If we detect a known MinValue or MaxValue for
                    // this integral type, we generate that reference, otherwise we
                    // just generate a constant integral value of the enum's type
                    object[] minMaxValues = null;
                    CodeGenUtilities.integralMinMaxValues.TryGetValue(underlyingType, out minMaxValues);
                    Debug.Assert(minMaxValues == null || minMaxValues.Length == 3, "integralMinMaxValues elements must always contain 3 values");

                    // Gen xxx.MinValue if it matches, but give precedence to matching a true zero,
                    // which is the min value for the unsigned integral types
                    // minMaxValues[0]: the MinValue for this type
                    // minMaxValues[1]: the MaxValue for this type
                    // minMaxValues[2]: the zero for this type (memberValue is not boxed and cannot be cast)
                    if (minMaxValues != null && !memberValue.Equals(minMaxValues[2]) && memberValue.Equals(minMaxValues[0]))
                    {
                         enumMember.InitExpression = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(underlyingType), "MinValue");
                    }
                    // Gen xxx.MaxValue if it matches
                    else if (minMaxValues != null && memberValue.Equals(minMaxValues[1]))
                    {
                         enumMember.InitExpression = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(underlyingType), "MaxValue");
                    }
                    // All other cases generate an integral constant.
                    // CodeDom knows how to generate the right integral constant based on memberValue's type.
                    else
                    {
                         enumMember.InitExpression = new CodePrimitiveExpression(memberValue);
                    }
                }

                typeDecl.Members.Add(enumMember);

                // Generate an [EnumMember] if appropriate
                EnumMemberAttribute enumMemberAttr = (EnumMemberAttribute)Attribute.GetCustomAttribute(fieldInfo, typeof(EnumMemberAttribute));
                if (enumMemberAttr != null)
                {
                    CodeAttributeDeclaration enumAttrDecl = CodeGenUtilities.CreateEnumMemberAttributeDeclaration(fieldInfo, codeGenerator, typeDecl);
                    enumMember.CustomAttributes.Add(enumAttrDecl);
                }

                // Propagate any other attributes that can be seen by the client
                CustomAttributeGenerator.GenerateCustomAttributes(
                    codeGenerator,
                    typeDecl,
                    ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeTypeMember, ex.Message, fieldInfo.Name, typeDecl.Name, ex.InnerException.Message),
                    fieldInfo.GetCustomAttributes(false).Cast<Attribute>().Where(a => a.GetType() != typeof(EnumMemberAttribute)),
                    enumMember.CustomAttributes,
                    enumMember.Comments);
            }

            // Attributes marked with [Flag] propagate it
            if (enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0)
            {
                CodeAttributeDeclaration attrDecl = CodeGenUtilities.CreateAttributeDeclaration(typeof(FlagsAttribute), codeGenerator, typeDecl);
                typeDecl.CustomAttributes.Add(attrDecl);
            }
            return typeDecl;
        }
コード例 #43
0
        /// <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);
        }
コード例 #44
0
        /// <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;
        }
コード例 #45
0
 /// <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;
 }
コード例 #46
0
        /// <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));
                }
            }
        }
コード例 #47
0
 /// <summary>
 /// Gets a <see cref="CodeTypeReference"/> for a CLR type.
 /// </summary>
 /// <param name="type">A CLR type.</param>
 /// <param name="codeGenerator">A <see cref="CodeDomClientCodeGenerator"/>.</param>
 /// <param name="referencingType">The referencing type.</param>
 /// <param name="optimizeAttributeName">Indicates whether or not the optimize <see cref="Attribute"/> names by removing the "Attribute" suffix.</param>
 /// <returns>A <see cref="CodeTypeReference"/> for a CLR type.</returns>
 internal static CodeTypeReference GetTypeReference(Type type, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType, bool optimizeAttributeName)
 {
     return GetTypeReference(type, codeGenerator, referencingType, optimizeAttributeName, false);
 }
コード例 #48
0
        /// <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();
        }
コード例 #49
0
 /// <summary>
 /// Initializes a new instance of the <see cref="WebContextGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.</param>
 internal WebContextGenerator(CodeDomClientCodeGenerator proxyGenerator)
     : base(proxyGenerator)
 {
 }
コード例 #50
0
        /// <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;
        }
コード例 #51
0
        /// <summary>
        /// Creates an attribute declaration based on the specified attribute
        /// </summary>
        /// <param name="attributeType">type of the attribute</param>
        /// <param name="codeGenerator">A <see cref="CodeDomClientCodeGenerator"/>.</param>
        /// <param name="referencingType">The referencing type.</param>
        /// <returns>the attribute declaration</returns>
        internal static CodeAttributeDeclaration CreateAttributeDeclaration(Type attributeType, CodeDomClientCodeGenerator codeGenerator, CodeTypeDeclaration referencingType)
        {
            if (!typeof(Attribute).IsAssignableFrom(attributeType))
            {
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Resource.Type_Must_Be_Attribute, attributeType.Name), "attributeType");
            }

            CodeTypeReference attribute = GetTypeReference(attributeType, codeGenerator, referencingType, true);
            return new CodeAttributeDeclaration(attribute);
        }
コード例 #52
0
        /// <summary>
        /// Creates the CodeDom CodeExpression for the given value.  Returns null if unable to generate a CodeExpression.
        /// </summary>
        /// <remarks>This method exists solely to help generate code for all object types that can appear in an
        /// attribute declaration, such as typeof()</remarks>
        /// <param name="proxyGenerator">The context for generating code.  It cannot be null.</param>
        /// <param name="referencingType">The referencing type</param>
        /// <param name="value">The value.  Null is permitted.</param>
        /// <returns>The code expression</returns>
        private static CodeExpression CreateCodeExpression(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, object value)
        {
            Type typeOfValue = value == null ? null : value.GetType();
            if (value == null || typeOfValue.IsPrimitive || value is string)
            {
                CodeExpression e = new CodePrimitiveExpression(value);

                // Workaround CodeDom issue -- it looks like CodePrimitiveExpression is fooled and generates double
                // literals as integers when there is no fraction.  We take a general strategy of forcing an explicit
                // compile time cast to ensure we recompile the same type.
                if (value != null && (value is double || value is float))
                {
                    e = new CodeCastExpression(value.GetType(), e);
                }
                return e;
            }

            // typeof(T) requires special handling
            Type valueAsType = value as Type;
            if (valueAsType != null)
            {
                // Verify the type is shared
                // Don't know counts as not shared
                CodeMemberShareKind shareKind = proxyGenerator.GetTypeShareKind(valueAsType);
                if ((shareKind & CodeMemberShareKind.Shared) == 0)
                {
                    // Here we return a fully-qualified type name to ensure we don't cause compilation
                    // errors by adding invalid 'using' statements into our codedom graph.
                    CodeTypeReference valueTypeReference = CodeGenUtilities.GetTypeReference(valueAsType, proxyGenerator, referencingType, false, /*Use fully qualified name*/ true);
                    valueTypeReference.Options = CodeTypeReferenceOptions.GlobalReference;
                    return new CodeTypeOfExpression(valueTypeReference);
                }

                return new CodeTypeOfExpression(CodeGenUtilities.GetTypeReference(valueAsType, proxyGenerator, referencingType));
            }

            // Enum values need special handling
            if (typeOfValue.IsEnum)
            {
                string enumValueName = Enum.GetName(typeOfValue, value);
                string enumTypeName;
                if (proxyGenerator.ClientProxyCodeGenerationOptions.UseFullTypeNames)
                {
                    enumTypeName = typeOfValue.FullName;
                }
                else
                {
                    enumTypeName = typeOfValue.Name;
                }
                return new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(enumTypeName), enumValueName);
            }

            return null;
        }
コード例 #53
0
 /// <summary>
 /// Generates code for the given custom attributes and adds them to the given <see cref="CodeAttributeDeclarationCollection"/>
 /// </summary>
 /// <param name="proxyGenerator">Root client proxy generator</param>
 /// <param name="referencingType">The referencing type</param>
 /// <param name="attributes">Collection of attributes to generate</param>
 /// <param name="outputCollection">The collection to which the generated attributes will be added</param>
 /// <param name="comments">Collection of comments that should be updated if errors are discovered.</param>
 /// <param name="forcePropagation">Indicates whether or not to force attribute propagation.</param>
 public static void GenerateCustomAttributes(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, IEnumerable<Attribute> attributes, CodeAttributeDeclarationCollection outputCollection, CodeCommentStatementCollection comments, bool forcePropagation)
 {
     GenerateCustomAttributes(
         proxyGenerator,
         referencingType,
         null,
         attributes,
         outputCollection,
         comments,
         Resource.ClientCodeGen_Attribute_FailedToGenerate,
         forcePropagation);
 }
コード例 #54
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ComplexTypeProxyGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.  Cannot be null.</param>
 /// <param name="complexType">The complex type.  Cannot be null.</param>
 /// <param name="domainServiceDescription"><see cref="DomainServiceDescription"/> that exposes this complex type.</param>
 /// <param name="typeMapping">A dictionary of <see cref="DomainService"/> and related complex types that maps to their corresponding client-side <see cref="CodeTypeReference"/> representations.</param>
 public ComplexTypeProxyGenerator(CodeDomClientCodeGenerator proxyGenerator, Type complexType, DomainServiceDescription domainServiceDescription, IDictionary<Type, CodeTypeDeclaration> typeMapping)
     : base(proxyGenerator, complexType, typeMapping)
 {
     this._domainServiceDescription = domainServiceDescription;
 }
コード例 #55
0
 /// <summary>
 /// Generates code for the given custom attributes and adds them to the given <see cref="CodeAttributeDeclarationCollection"/>
 /// </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 to generate</param>
 /// <param name="outputCollection">The collection to which the generated attributes will be added</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>
 public static void GenerateCustomAttributes(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration referencingType, Func<AttributeBuilderException, string> getLogWarningMessage, IEnumerable<Attribute> attributes, CodeAttributeDeclarationCollection outputCollection, CodeCommentStatementCollection comments, string customCommentHeader, bool forcePropagation)
 {
     IEnumerable<CodeAttributeDeclaration> cads = GenerateCustomAttributes(proxyGenerator, referencingType, getLogWarningMessage, attributes, comments, customCommentHeader, forcePropagation);
     foreach (var cad in cads)
     {
         outputCollection.Add(cad);
     }
 }
コード例 #56
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DomainServiceProxyGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.  Cannot be null.</param>
 /// <param name="domainServiceDescription">The domain service description to use as source metadata</param>
 /// <param name="typeMapping">A dictionary of <see cref="DomainService"/> and related entity types that maps to their corresponding client-side <see cref="CodeTypeReference"/> representations.</param>
 public DomainServiceProxyGenerator(CodeDomClientCodeGenerator proxyGenerator, DomainServiceDescription domainServiceDescription, IDictionary<Type, CodeTypeDeclaration> typeMapping)
     : base(proxyGenerator)
 {
     this._domainServiceDescription = domainServiceDescription;
     this._typeMapping = typeMapping;
 }