帮助System.Web.Compilation.BuildManager在未引用的程序集中查找类型

时间:2010-04-16 10:51:23

标签: asp.net-mvc compilation embedded-resource assembly-resolution buildmanager

我正在尝试编写一个插件系统,其中程序集可以放在ASP.NET不知道的文件夹中。此插件系统适用于基于ASP.NET MVC的程序集,但适用于旧式WebForm程序集(.aspx文件Inherits System.Web.UI.Page派生类)System.Web.Compilation.BuildManager负责将.aspx文件编译为动态程序集。

我的问题是BuildManager对我的插件文件夹中的程序集一无所知,似乎我无能为力。如果我这样做:

BuildManager.GetType("PluginAssembly.DefinedType", true, true)
它扔了。如果我首先获得对Type的引用,然后尝试:

var instance = BuildManager.CreateInstanceFromVirtualPath(path, type);

它仍然会抛出,即使我现在已经传入了需要编译type文件的特定.aspx。我能做些什么来帮助BuildManager找到编译.aspx文件所需的类型吗?

更新 通过研究BuildManager.GetType()实际做了什么,我更进一步了。通过指定程序集定义类型(例如“PluginAssembly.DefinedType,PluginAssembly”)然后将自己挂钩到System.AppDomain.CurrentDomain.AssemblyResolve事件,我现在可以找到插件程序集并返回它,以便BuildManager可以成功构建类型。这使得以下工作具有绚丽的色彩:

BuildManager.GetType("PluginAssembly.DefinedType, PluginAssembly", true, true)

然而,这仍然失败:

var instance = BuildManager.CreateInstanceFromVirtualPath(path, type);

即使.aspx文件现在在Inherits指令中具有相同的程序集引用:

<%@ Page Language="C#"              
         CodeBehind="Index.aspx.cs"
         Inherits="PluginAssembly.DefinedType, PluginAssembly" %>

我收到的错误是:

“编译器错误消息:CS0234:类型或命名空间名称'DefinedType'在名称空间'PluginAssembly'中不存在(您是否缺少程序集引用?)”,具有以下源输出:

Line 205:
Line 206:    [System.Runtime.CompilerServices.CompilerGlobalScopeAttribute()]
Line 207:    public class plugins_pluginassembly_dll_index_aspx
                 : global::PluginAssembly.DefinedType,
                   System.Web.SessionState.IRequiresSessionState, 
                   System.Web.IHttpHandler {
Line 208:        
Line 209:        private static bool @__initialized;

似乎BuildManager.CreateInstanceFromVirtualPath()内部发生的事情涉及某个System.Web.Util.IWebObjectFactory,它可能会因未找到我的程序集而抛出此异常。我可以毫无问题地实现这个界面,但如果我不能告诉BuildManager它有什么帮助呢?

4 个答案:

答案 0 :(得分:1)

我看到两种方法可以指定用于编译页面的程序集:

  • 调用BuildManager.AddReferencedAssembly(但我假设您已尝试过那个?)
  • 在编译页面的虚拟目录配置中放入所需程序集的列表(在system.web / compilation / assemblies部分中),并在appdomain中访问这些程序集(框架似乎使用Assembly.Load查找已找到的程序集在配置文件中。)。

答案 1 :(得分:1)

我不知道BuildManager如何加载类型,但你可以尝试使用AssemblyResolve - 订阅AppDomain.CurrentDomain.AssemblyResolve事件,然后加载程序集自己并返回(是的,返回)Assembly实例(如果您不认识它,则返回null。)

并非所有此类代码都使用与此兼容的方法,但值得一试。

答案 2 :(得分:0)

我最终使用Web Deployment Projects [1]通过将整个Web应用程序预编译为两个单独的程序集然后使用Assembly.GetTypes()挖掘到正确的程序集来实例化正确的{{}来解决此问题。 1}}用于给定的HTTP请求。

它更多地放在插件开发人员的肩上,但产生了更好的性能,并且所有插件在它们被执行之前完全由ASP.NET编译器验证(安全敏感且易碎) )网络背景。

答案 3 :(得分:0)

我正在为ASP.NET自己开发一个延迟加载框架。 您的插件始终可以在其页面中使用<@ Assembly>指令手动引用程序集。