/// <summary> /// Tries to loads the OpenRiaServices.DomainServices.Server assembly from the server projects references. /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="loggingService">The logging service.</param> private static void LoadOpenRiaServicesServerAssembly(SharedCodeServiceParameters parameters, ILoggingService loggingService) { // Try to load the OpenRiaServices.DomainServies.Server assembly using the one used by the server project // This way we can be sure that codegen works with both signed and unsigned server assembly while // making sure that only a single version is loaded var filename = OpenRiaServices_DomainServices_Server_Assembly; var serverAssemblyPath = parameters.ServerAssemblies.FirstOrDefault(sa => sa.EndsWith(filename)); if (serverAssemblyPath != null) { var serverAssembly = AssemblyUtilities.LoadAssembly(serverAssemblyPath, loggingService); if (serverAssembly != null) { // Since this assembly (OpenRiaServices.DomainServices.Tools) requires the Server assembly to be loaded // before the final call to AssemblyUtilities.SetAssemblyResolver (when the DomainServiceCatalog is instanciated) // we need to setup our assembly resolver with the server assembly in case the server version is signed // but this version is unsigned if (!serverAssembly.GetName().IsSigned()) { loggingService.LogWarning(Resource.ClientCodeGen_SignedTools_UnsignedServer); } } else { loggingService.LogError(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Failed_Loading_OpenRiaServices_Assembly, filename, serverAssemblyPath)); } } else { loggingService.LogError(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Missing_OpenRiaServices_Reference, filename)); } }
/// <summary> /// Generates client proxy source code using the generator specified by <paramref name="codeGeneratorName"/>. /// </summary> /// <param name="options">The options to use for code generation.</param> /// <param name="parameters">The parameters required to create the <see cref="ISharedCodeService"/>.</param> /// <param name="loggingService">The service to use for logging.</param> /// <param name="codeGeneratorName">Optional generator name. A <c>null</c> or empty value will select the default generator.</param> /// <returns>The generated source code or <c>null</c> if none was generated.</returns> internal string GenerateCode(ClientCodeGenerationOptions options, SharedCodeServiceParameters parameters, ILoggingService loggingService, string codeGeneratorName) { Debug.Assert(options != null, "options cannot be null"); Debug.Assert(parameters != null, "parameters cannot be null"); Debug.Assert(loggingService != null, "loggingService cannot be null"); try { AppDomainUtilities.ConfigureAppDomain(options); LoadOpenRiaServicesServerAssembly(parameters, loggingService); using (SharedCodeService sharedCodeService = new SharedCodeService(parameters, loggingService)) { CodeGenerationHost host = new CodeGenerationHost(loggingService, sharedCodeService); return(this.GenerateCode(host, options, parameters.ServerAssemblies, codeGeneratorName)); } } catch (Exception ex) { // Fatal exceptions are never swallowed or processed if (ex.IsFatal()) { throw; } // Any exception from the code generator is caught and reported, otherwise it will // hit the MSBuild backstop and report failure of the custom build task. // It is acceptable to report this exception and "ignore" it because we // are running in a separate AppDomain which will be torn down immediately // after our return. loggingService.LogError(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGenDispatecher_Threw_Exception_Before_Generate, ex.Message)); loggingService.LogException(ex); return(null); } }
/// <summary> /// Generates client proxy source code using the generator specified by <paramref name="codeGeneratorName"/>. /// </summary> /// <param name="options">The options to use for code generation.</param> /// <param name="parameters">The parameters required to create the <see cref="ISharedCodeService"/>.</param> /// <param name="loggingService">The service to use for logging.</param> /// <param name="codeGeneratorName">Optional generator name. A <c>null</c> or empty value will select the default generator.</param> /// <returns>The generated source code or <c>null</c> if none was generated.</returns> internal string GenerateCode(ClientCodeGenerationOptions options, SharedCodeServiceParameters parameters, ILoggingService loggingService, string codeGeneratorName) { Debug.Assert(options != null, "options cannot be null"); Debug.Assert(parameters != null, "parameters cannot be null"); Debug.Assert(loggingService != null, "loggingService cannot be null"); try { AppDomainUtilities.ConfigureAppDomain(options); LoadOpenRiaServicesServerAssembly(parameters, loggingService); using (SharedCodeService sharedCodeService = new SharedCodeService(parameters, loggingService)) { CodeGenerationHost host = new CodeGenerationHost(loggingService, sharedCodeService); return this.GenerateCode(host, options, parameters.ServerAssemblies, codeGeneratorName); } } catch (Exception ex) { // Fatal exceptions are never swallowed or processed if (ex.IsFatal()) { throw; } // Any exception from the code generator is caught and reported, otherwise it will // hit the MSBuild backstop and report failure of the custom build task. // It is acceptable to report this exception and "ignore" it because we // are running in a separate AppDomain which will be torn down immediately // after our return. loggingService.LogError(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGenDispatecher_Threw_Exception_Before_Generate, ex.Message)); loggingService.LogException(ex); return null; } }
/// <summary> /// Constructs the parameters to pass across the AppDomain boundary to construct a /// <see cref="SharedCodeService"/> in the AppDomain that will do code generation. /// </summary> /// <param name="serverAssemblies">The set of full paths to the server assemblies to use for code generation.</param> /// <returns>A <see cref="SharedCodeServiceParameters"/> instance ready to use to construct a <see cref="SharedCodeService"/>.</returns> private SharedCodeServiceParameters CreateSharedCodeServiceParameters(IEnumerable<string> serverAssemblies) { SharedCodeServiceParameters parameters = new SharedCodeServiceParameters(); parameters.ServerAssemblies = serverAssemblies.ToArray(); // Get all *.shared.* and linked files in common between client and server. // These are consider "shared files" by the shared type service parameters.SharedSourceFiles = this.GetSharedAndLinkedFiles().ToArray(); // Present the list of shared files to the user as a informational level log if (parameters.SharedSourceFiles.Any()) { StringBuilder sb = new StringBuilder(); foreach (string file in parameters.SharedSourceFiles) { sb.AppendLine(); sb.Append(" " + file); } this.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Shared_Files, sb.ToString())); } parameters.ClientAssemblies = this.NormalizedTaskItems(this.ClientReferenceAssemblies, this.ClientProjectDirectory).ToArray(); parameters.ClientAssemblyPathsNormalized = this.ClientAssemblyPathsNormalized.ToArray(); // Convert the list of server assemblies into a search path for PDB's parameters.SymbolSearchPaths = serverAssemblies.Select(a => Path.GetDirectoryName(a)).ToArray(); return parameters; }
/// <summary> /// Tries to loads the OpenRiaServices.DomainServices.Server assembly from the server projects references. /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="loggingService">The logging service.</param> private static void LoadOpenRiaServicesServerAssembly(SharedCodeServiceParameters parameters, ILoggingService loggingService) { // Try to load the OpenRiaServices.DomainServies.Server assembly using the one used by the server project // This way we can be sure that codegen works with both signed and unsigned server assembly while // making sure that only a single version is loaded var filename = OpenRiaServices_DomainServices_Server_Assembly; var serverAssemblyPath = parameters.ServerAssemblies.FirstOrDefault(sa => sa.EndsWith(filename)); if (serverAssemblyPath != null) { var serverAssembly = AssemblyUtilities.LoadAssembly(serverAssemblyPath, loggingService); if (serverAssembly != null) { // Since this assembly (OpenRiaServices.DomainServices.Tools) requires the Server assembly to be loaded // before the final call to AssemblyUtilities.SetAssemblyResolver (when the DomainServiceCatalog is instanciated) // we need to setup our assembly resolver with the server assembly in case the server version is signed // but this version is unsigned #if SIGNED if (!serverAssembly.GetName().IsSigned()) { loggingService.LogWarning(Resource.ClientCodeGen_SignedTools_UnsignedServer); } #else AssemblyUtilities.SetAssemblyResolver(new[] { serverAssembly }); #endif } else { loggingService.LogError(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Failed_Loading_OpenRiaServices_Assembly, filename, serverAssemblyPath)); } } else { loggingService.LogError(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Missing_OpenRiaServices_Reference, filename)); } }