帮助 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 文件 InheritsSystem.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 开发一个延迟加载框架。 您的插件始终可以在其页面中使用&lt;@ Assembly&gt; 指令来手动引用程序集。

【讨论】:

以上是关于帮助 System.Web.Compilation.BuildManager 在非引用程序集中查找类型的主要内容,如果未能解决你的问题,请参考以下文章

url重写—适用html为伪静态后真实的html无法访问的解决方法

未能执行URL

BuildManager.GetReferencedAssemblies 等效于非 Web 应用程序

dtcms在windows虚拟主机下怎么配置url地址伪静态显示

Linux学习之路帮助命令

day 2 帮助命令 扩展.md