コード例 #1
0
        /// <summary>
        /// Examines a <see cref="DomainServiceDescription"/> to discover and invoke <see cref="CodeProcessor"/> types.
        /// </summary>
        /// <param name="workItem">The <see cref="CodeProcessorWorkItem"/> unit of work.</param>
        private void InvokeDomainServiceCodeProcessor(CodeProcessorWorkItem workItem)
        {
            Type codeProcessorType = workItem.CodeProcessorType;
            DomainServiceDescription domainServiceDescription   = workItem.DomainServiceDescription;
            IDictionary <Type, CodeTypeDeclaration> typeMapping = workItem.TypeMapping;

            // Verify the type defined is a valid CodeProcessor
            if (!typeof(CodeProcessor).IsAssignableFrom(codeProcessorType))
            {
                this.LogError(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_DomainService_CodeProcessor_NotValidType,
                        codeProcessorType,
                        domainServiceDescription.DomainServiceType));
                return;
            }

            // Verify the type has a default constructor that accepts a CodeDomProvider
            ConstructorInfo codeProcessorCtor =
                codeProcessorType.GetConstructor(
                    BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
                    null,
                    new Type[] { typeof(CodeDomProvider) },
                    null);

            if (codeProcessorCtor == null)
            {
                this.LogError(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_DomainService_CodeProcessor_InvalidConstructorSignature,
                        codeProcessorType,
                        domainServiceDescription.DomainServiceType,
                        typeof(CodeDomProvider)));
                return;
            }

            try
            {
                // Create a new CodeProcessor and invoke it
                CodeProcessor postProcessor = codeProcessorCtor.Invoke(new object[] { this._provider }) as CodeProcessor;
                postProcessor.ProcessGeneratedCode(domainServiceDescription, this.CompileUnit, typeMapping);
            }
            catch (Exception ex)
            {
                if (ex.IsFatal())
                {
                    throw;
                }

                // Unwrap TargetInvocationExceptions
                TargetInvocationException tie = ex as TargetInvocationException;
                if (tie != null && tie.InnerException != null)
                {
                    ex = tie.InnerException;
                }

                // Intercept the exception to log it
                this.LogError(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_DomainService_CodeProcessor_ExceptionCaught,
                        codeProcessorType,
                        domainServiceDescription.DomainServiceType,
                        ex.Message));

                // Since we can't handle the exception, let it continue.
                throw;
            }
        }
コード例 #2
0
        private string GenerateProxyClass()
        {
            var generatedCode = string.Empty;

            // Analyze the assemblies to extract all the EntityDescriptions
            var allDescriptions       = _entityDescriptions;
            var generatedEntityTypes  = new List <Type>();
            var generatedComplexTypes = new List <Type>();
            var typeMapping           = new Dictionary <Type, CodeTypeDeclaration>();

            // Used to queue CodeProcessor invocations
            var codeProcessorQueue = new Queue <CodeProcessorWorkItem>();

            // Before we begin codegen, we want to register type names with our codegen
            // utilities so that we can avoid type name conflicts later.
            PreprocessProxyTypes();

            // Generate a new proxy class for each entity we found.
            // OrderBy type name of entity to give code-gen predictability
            foreach (var dsd in allDescriptions)
            {
                // Log information level message to help users see progress and debug code-gen issues
                LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Generating));

                // Generate all entities.
                GenerateDataContractTypes(dsd.EntityTypes, generatedEntityTypes, Resource.ClientCodeGen_EntityTypesCannotBeShared_Reference, t =>
                {
                    new EntityProxyGenerator(this, t, allDescriptions, typeMapping).Generate();
                });
            }

            // If there are no entityDescriptions, we do not generate any client proxies
            // We don't consider this an error, since this task might be invoked before the user has created any.
            if (allDescriptions.Count == 0)
            {
                return(generatedCode);
            }

            // Generate any enum types we have decided we need to generate
            this.GenerateAllEnumTypes();

            // Fix up CodeDOM graph before invoking CodeProcessors
            this.FixUpCompileUnit(this.CompileUnit);

            // Invoke CodeProcessors after we've completed our CodeDOM graph
            while (codeProcessorQueue.Count > 0)
            {
                // Allow CodeProcessors to do post processing work
                CodeProcessorWorkItem workItem = codeProcessorQueue.Dequeue();
                this.InvokeCodeProcessor(workItem);
            }

            // Write the entire "file" to a single string to permit us to redirect it
            // to a file, a TextBuffer, etc
            if (!this.CodeGenerationHost.HasLoggedErrors)
            {
                using (TextWriter t = new StringWriter(CultureInfo.InvariantCulture))
                {
                    this.Provider.GenerateCodeFromCompileUnit(this.CompileUnit, t, this._options);
                    generatedCode = this.FixupVBOptionStatements(t.ToString());
                }
            }

            return(generatedCode);
        }
コード例 #3
0
        private string GenerateProxyClass()
        {
            string generatedCode = string.Empty;

            // Analyze the assemblies to extract all the DomainServiceDescriptions
            ICollection <DomainServiceDescription> allDescriptions = this._domainServiceDescriptions;
            List <Type> generatedEntityTypes  = new List <Type>();
            List <Type> generatedComplexTypes = new List <Type>();
            Dictionary <Type, CodeTypeDeclaration> typeMapping = new Dictionary <Type, CodeTypeDeclaration>();

            // Used to queue CodeProcessor invocations
            Queue <CodeProcessorWorkItem> codeProcessorQueue = new Queue <CodeProcessorWorkItem>();

            // Before we begin codegen, we want to register type names with our codegen
            // utilities so that we can avoid type name conflicts later.
            this.PreprocessProxyTypes();

            // Generate a new domain service proxy class for each domain service we found.
            // OrderBy type name of DomainService to give code-gen predictability
            foreach (DomainServiceDescription dsd in allDescriptions.OrderBy(d => d.DomainServiceType.Name))
            {
                // If we detect the client already has the DomainContext we would have
                // generated, skip it.  This condition arises when the client has references
                // to class libraries as well as a code-gen link to the server which has
                // references to the server-side equivalent libraries.  Without this check, we would
                // re-generate the same DomainContext that already lives in the class library.
                CodeMemberShareKind domainContextShareKind = this.GetDomainContextTypeMemberShareKind(dsd);
                if ((domainContextShareKind & CodeMemberShareKind.Shared) != 0)
                {
                    this.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.Shared_DomainContext_Skipped, dsd.DomainServiceType.Name));
                    continue;
                }

                // Log information level message to help users see progress and debug code-gen issues
                this.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Generating_DomainService, dsd.DomainServiceType.FullName));

                new DomainServiceProxyGenerator(this, dsd, typeMapping).Generate();

                // Generate all entities.
                this.GenerateDataContractTypes(dsd.EntityTypes, generatedEntityTypes, Resource.ClientCodeGen_EntityTypesCannotBeShared_Reference, t =>
                {
                    new EntityProxyGenerator(this, t, allDescriptions, typeMapping).Generate();
                });

                // Generate all complex types.
                this.GenerateDataContractTypes(dsd.ComplexTypes, generatedComplexTypes, Resource.ClientCodeGen_ComplexTypesCannotBeShared_Reference, t =>
                {
                    new ComplexTypeProxyGenerator(this, t, dsd, typeMapping).Generate();
                });

                DomainIdentifierAttribute domainIdentifier = dsd.Attributes.OfType <DomainIdentifierAttribute>().SingleOrDefault();
                if (domainIdentifier != null)
                {
                    Type codeProcessorType = domainIdentifier.CodeProcessor;
                    if (codeProcessorType != null)
                    {
                        // Create a limited type-mapping dictionary that contains references to
                        // the DomainService and related entity type CodeTypeDeclarations.
                        Dictionary <Type, CodeTypeDeclaration> scopedTypeMapping =
                            typeMapping.Where(kvp => kvp.Key == dsd.DomainServiceType || dsd.EntityTypes.Contains(kvp.Key))
                            .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

                        // Register CodeProc
                        codeProcessorQueue.Enqueue(
                            new CodeProcessorWorkItem(codeProcessorType, dsd, scopedTypeMapping));
                    }
                }
            }

            // Generate an application-level WebContext class
            if (this.ClientProxyCodeGenerationOptions.IsApplicationContextGenerationEnabled)
            {
                new WebContextGenerator(this).Generate();
            }
            // If there are no descriptions, we do not generate any client proxies
            // We don't consider this an error, since this task might be invoked before the user has created any.
            else if (allDescriptions.Count == 0)
            {
                return(generatedCode);
            }

            // Generate any enum types we have decided we need to generate
            this.GenerateAllEnumTypes();

            // Fix up CodeDOM graph before invoking CodeProcessors
            this.FixUpCompileUnit(this.CompileUnit);

            // Invoke CodeProcessors after we've completed our CodeDOM graph
            while (codeProcessorQueue.Count > 0)
            {
                // Allow CodeProcessors to do post processing work
                CodeProcessorWorkItem workItem = codeProcessorQueue.Dequeue();
                this.InvokeDomainServiceCodeProcessor(workItem);
            }

            // Write the entire "file" to a single string to permit us to redirect it
            // to a file, a TextBuffer, etc
            if (!this.CodeGenerationHost.HasLoggedErrors)
            {
                using (TextWriter t = new StringWriter(CultureInfo.InvariantCulture))
                {
                    this.Provider.GenerateCodeFromCompileUnit(this.CompileUnit, t, this._options);
                    generatedCode = this.FixupVBOptionStatements(t.ToString());
                }
            }

            return(generatedCode);
        }
コード例 #4
0
        /// <summary>
        /// Examines a <see cref="DomainServiceDescription"/> to discover and invoke <see cref="CodeProcessor"/> types.
        /// </summary>
        /// <param name="workItem">The <see cref="CodeProcessorWorkItem"/> unit of work.</param>
        private void InvokeDomainServiceCodeProcessor(CodeProcessorWorkItem workItem)
        {
            Type codeProcessorType = workItem.CodeProcessorType;
            DomainServiceDescription domainServiceDescription = workItem.DomainServiceDescription;
            IDictionary<Type, CodeTypeDeclaration> typeMapping = workItem.TypeMapping;

            // Verify the type defined is a valid CodeProcessor
            if (!typeof(CodeProcessor).IsAssignableFrom(codeProcessorType))
            {
                this.LogError(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_DomainService_CodeProcessor_NotValidType,
                        codeProcessorType,
                        domainServiceDescription.DomainServiceType));
                return;
            }

            // Verify the type has a default constructor that accepts a CodeDomProvider
            ConstructorInfo codeProcessorCtor =
                codeProcessorType.GetConstructor(
                    BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
                    null,
                    new Type[] { typeof(CodeDomProvider) },
                    null);

            if (codeProcessorCtor == null)
            {
                this.LogError(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_DomainService_CodeProcessor_InvalidConstructorSignature,
                        codeProcessorType,
                        domainServiceDescription.DomainServiceType,
                        typeof(CodeDomProvider)));
                return;
            }

            try
            {
                // Create a new CodeProcessor and invoke it
                CodeProcessor postProcessor = codeProcessorCtor.Invoke(new object[] { this._provider }) as CodeProcessor;
                postProcessor.ProcessGeneratedCode(domainServiceDescription, this.CompileUnit, typeMapping);
            }
            catch (Exception ex)
            {
                if (ex.IsFatal())
                {
                    throw;
                }

                // Unwrap TargetInvocationExceptions
                TargetInvocationException tie = ex as TargetInvocationException;
                if (tie != null && tie.InnerException != null)
                {
                    ex = tie.InnerException;
                }

                // Intercept the exception to log it
                this.LogError(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resource.ClientCodeGen_DomainService_CodeProcessor_ExceptionCaught,
                        codeProcessorType,
                        domainServiceDescription.DomainServiceType,
                        ex.Message));

                // Since we can't handle the exception, let it continue.
                throw;
            }
        }