/// <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; } }
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); }
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); }
/// <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; } }