帮助 System.Web.Compilation.BuildManager 在非引用程序集中查找类型
Posted
技术标签:
【中文标题】帮助 System.Web.Compilation.BuildManager 在非引用程序集中查找类型【英文标题】:Help System.Web.Compilation.BuildManager find a type in a non-referenced assembly 【发布时间】:2010-04-16 10:51:22 【问题描述】:我正在尝试编写一个插件系统,可以将程序集放在 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:命名空间“PluginAssembly”中不存在类型或命名空间名称“DefinedType”(您是否缺少程序集引用?)”,源输出如下:
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
这有什么帮助?
【问题讨论】:
添加插件时必须回收应用程序有什么问题? 因为刷新一个插件就需要关闭整个网站。此外,它可能无法在中等信任度下工作,并且是一个非常糟糕的解决方案。 记下您正在寻找的答案,但您尝试过 MEF 吗? blogs.msdn.com/hammett/archive/2009/04/23/… 是的,我正在使用 MEF,它绝对不能帮助我编译嵌入在程序集中的.aspx
文件。
【参考方案1】:
我看到有两种方法可以指定用于编译页面的程序集:
调用 BuildManager.AddReferencedAssembly(但我假设您已经尝试过那个?) 在编译页面的虚拟目录配置中放入所需程序集的列表(在 system.web/compilation/assemblies 部分中)并在 appdomain 中访问这些程序集(框架似乎使用 Assembly.Load 来查找找到的程序集在配置文件中)。【讨论】:
BuildManager.AddReferencedAssembly
抛出“此方法只能在应用程序的预启动初始化阶段调用”并且修改 web.config 不是一个可行的选项,因为这需要重新启动应用程序和模块预先知道并非总是如此。【参考方案2】:
我不知道 BuildManager
是如何加载类型的,但您可以尝试使用 AssemblyResolve
- 订阅 AppDomain.CurrentDomain.AssemblyResolve
事件,然后自己加载程序集并返回(是的,返回)Assembly
实例(或null
,如果你不认识它)。
并非所有此类代码都使用与此兼容的方法,但值得一试。
【讨论】:
我已经这样做了,它可以在编译 .aspx.cs 文件时解析程序集,但是在编译 .aspx 文件时它引用global::PluginAssembly.DefinedType
不提供任何方法解析任何程序集,因为 BuildManager 假定程序集已存在于应用程序域中。【参考方案3】:
我最终通过 Web Deployment Projects [1] 解决了这个问题,方法是将整个 Web 应用程序预编译为两个单独的程序集,然后使用 Assembly.GetTypes()
挖掘正确的程序集,为给定的 HTTP 请求实例化正确的 Page
.
它让插件开发人员承担了更多责任,但产生了更好的性能,另外一个好处是所有插件在执行之前都经过 ASP.NET 编译器完全验证(安全敏感和脆弱) ) 网络上下文。
【讨论】:
【参考方案4】:我自己正在为 ASP.NET 开发一个延迟加载框架。
您的插件始终可以在其页面中使用<@ Assembly>
指令来手动引用程序集。
【讨论】:
以上是关于帮助 System.Web.Compilation.BuildManager 在非引用程序集中查找类型的主要内容,如果未能解决你的问题,请参考以下文章
url重写—适用html为伪静态后真实的html无法访问的解决方法
BuildManager.GetReferencedAssemblies 等效于非 Web 应用程序