【问题标题】:Referencing embedded assemblies from dynamically created classes从动态创建的类中引用嵌入式程序集
【发布时间】:2011-06-11 13:43:29
【问题描述】:

我一直在使用将dll(嵌入资源)嵌入到exe中的技术,并使用以下代码在运行时解析未知的dll。

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    String resourceName = "Project.lib." + new AssemblyName(args.Name).Name + ".dll";

    using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
    {
        Byte[] assemblyData = new Byte[stream.Length];
        stream.Read(assemblyData, 0, assemblyData.Length);
        return Assembly.Load(assemblyData);
    }
};

但是,当我嵌入 Spark View Engine dll(例如)时,它会崩溃。但仅限于一个特定的地方。 Spark 本身动态地生成类。然后这些类引用 Spark(using Spark 等)。正是在这一点上,我收到以下错误。

“Spark.Class”类型定义在 未引用的程序集。 您必须添加对 装配“火花”

我很确定这与 Spark 视图引擎无关,而是与从动态生成的类中引用嵌入式程序集有关。

更新:堆栈跟踪

运行时出现异常 项目任务消息: Spark.Compiler.BatchCompilerException: 动态视图编译失败。 c:\Users\Adam\AppData\Local\Temp\kdsjyhvu.0.cs(6,14): 错误 CS0012:类型 'Spark.AbstractSparkView' 已定义 在未引用的程序集中。 您必须添加对程序集的引用 '火花,版本=1.5.0.0, 文化=中性, PublicKeyToken=7f8549eed921a12c' 在 Spark.Compiler.BatchCompiler.Compile(布尔 调试,字符串语言或扩展, 字符串 [] 源代码)在 Spark.Compiler.CSharp.CSharpViewCompiler.CompileView(IEnumerable1 viewTemplates, IEnumerable1 所有资源)在 Spark.SparkViewEngine.CreateEntryInternal(SparkViewDescriptor 描述符,布尔编译)在 Spark.SparkViewEngine.CreateEntry(SparkViewDescriptor 描述符)在 Spark.SparkViewEngine.CreateInstance(SparkViewDescriptor 描述符)在 ProjectTasks.Core.Templater.Populate(字符串 模板文件路径,对象数据)在 \ProjectTasks\Core\Templater.cs:line 33 在 ProjectTasks..Core.EmailTemplates.RenderImpl(字符串 名称,对象数据)在 \ProjectTasks\Core\EmailTemplates.cs:line 19 在 ProjectTasks.Tasks.EmailUsersWithIncompleteModules.Run() 在 \ProjectTasks\Tasks\EmailUsersWithIncompleteModules.cs:line 41 在 ProjectTasks.MaintenanceTaskRunner.Run(布尔 runNow,IMaintenanceTask[] 任务)在 \ProjectTasks\MaintenanceTaskRunner.cs:line 25 在 ProjectTasks.Initialiser.Init(字符串 [] 参数)在 \ProjectTasks\Initialiser.cs:line 30

如果确实有一个解决方案,有人对解决方案有任何想法吗?

【问题讨论】:

  • 您能否验证对 AssemblyResolve 的所有调用都返回 Assembly?你也可以分享异常的调用堆栈吗?
  • 对 AssemblyResolve 的所有调用都会返回一个程序集。

标签: c# assemblies embedded-resource dynamic-class


【解决方案1】:

我猜 Spark 使用 CodeDom 进行动态代码生成。 CSharpCodeProvider 内部生成源代码并运行 csc.exe 以获取新类型。由于 csc.exe 需要物理文件作为参考,因此在这种情况下,AssemblyResolve 技巧将无济于事。

【讨论】:

    【解决方案2】:

    堆栈跟踪强烈表明 Spark 正在使用 System.CodeDom 动态生成程序集。这要求引用程序集是磁盘上的文件,C# 编译器在进程外运行。这通常不是问题,因为 Spark.dll 与 EXE 位于同一目录中。

    你无法做到这一点。

    Fwiw:这种技术非常浪费系统资源。您将装配所需的内存量增加一倍。它也是一种昂贵的内存,它不能在进程之间共享,并且由分页文件而不是汇编文件支持。你也可以给自己买一些严重的类型识别麻烦。 .NET 已经支持在单个文件中部署。它被称为 setup.exe

    【讨论】:

      【解决方案3】:

      正如其他人所说,问题在于 CodeDom 在磁盘上生成工件,随后需要访问这些工件以呈现视图。

      除了嵌入 Spark 是一个潜在的内存消耗这一事实之外,我相信这个问题有一个潜在的解决方案。鉴于问题是由动态生成的动态视图引起的,为什么不利用Spark's batch compilation 选项为您的视图生成 dll 作为构建的一部分。

      您可以使用类似于以下的代码来实现此目的:

      var factory = new SparkViewFactory(settings)
                     {
                         ViewFolder = new FileSystemViewFolder(viewsLocation)
                     };
      
      // And generate all of the known view/master templates into the target assembly
      var batch = new SparkBatchDescriptor(targetPath);
      
      factory.Precompile(batch);
      

      最后,您应该有一个包含编译视图的输出 dll,然后您可以像嵌入主 Spark.dll 一样嵌入该 dll。

      希望有所帮助

      【讨论】:

      • Rob 这不是一个坏主意。完全忘记了预编译视图。会试一试!
      猜你喜欢
      • 1970-01-01
      • 2014-06-11
      • 2018-10-15
      • 2015-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-05
      相关资源
      最近更新 更多