从动态创建的类引用嵌入式程序集

时间:2011-06-11 13:43:30

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

我一直在使用将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视图引擎无关,而是与在动态生成的类中引用嵌入式程序集有关。

更新: stacktrace

  

运行时出现异常   项目任务消息:   Spark.Compiler.BatchCompilerException:   动态视图编译失败。   C:\用户\亚当\应用程序数据\本地\ TEMP \ kdsjyhvu.0.cs(6,14):   错误CS0012:类型   'Spark.AbstractSparkView'已定义   在未引用的程序集中。   您必须添加对程序集的引用   'Spark,版本= 1.5.0.0,   文化=中性,   PublicKeyToken = 7f8549eed921a12c'at   Spark.Compiler.BatchCompiler.Compile(布尔   debug,String languageOrExtension,   String [] sourceCode)at   Spark.Compiler.CSharp.CSharpViewCompiler.CompileView(IEnumerable的1 viewTemplates, IEnumerable 1   allResources)at   Spark.SparkViewEngine.CreateEntryInternal(SparkViewDescriptor   描述符,布尔编译)at   Spark.SparkViewEngine.CreateEntry(SparkViewDescriptor   描述符)   Spark.SparkViewEngine.CreateInstance(SparkViewDescriptor   描述符)   ProjectTasks.Core.Templater.Populate(字符串   templateFilePath,Object data)in   \ ProjectTasks \核心\ Templater.cs:行   33点   ProjectTasks..Core.EmailTemplates.RenderImpl(字符串   名称,对象数据)   \ ProjectTasks \核心\ EmailTemplates.cs:行   19点到   ProjectTasks.Tasks.EmailUsersWithIncompleteModules.Run()   在   \ ProjectTasks \ \任务EmailUsersWithIncompleteModules.cs:行   41点   ProjectTasks.MaintenanceTaskRunner.Run(布尔   runNow,IMaintenanceTask []任务)in   \ \ ProjectTasks MaintenanceTaskRunner.cs:行   25点   ProjectTasks.Initialiser.Init(字符串[]   args)in   \ ProjectTasks \ Initialiser.cs:行   30

如果确实存在任何决议,任何人都对决议有任何想法吗?

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

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

你无法做到这一点。

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

答案 2 :(得分:0)

正如其他人所说,问题在于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。

希望有所帮助 罗布