帮助 System.Web.Compilation.BuildManager 在非引用程序集中查找类型
我正在尝试编写一个插件系统,其中可以将程序集放入 ASP.NET 不知道的文件夹中。该插件系统适用于基于 ASP.NET MVC 的程序集,但适用于老式 WebForm 程序集(其中 .aspx
文件继承
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 事件,我现在可以找到插件assembly 并返回它,以便 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
它有什么用呢?
I'm trying to write a plug-in system where assemblies can be dropped in a folder that ASP.NET has no knowledge about. This plug-in system works fine for ASP.NET MVC based assemblies, but for old-school WebForm assemblies (where the .aspx
files Inherits
the System.Web.UI.Page
derived classes) System.Web.Compilation.BuildManager
is responsible for compiling the .aspx
file into a dynamic assembly.
My problem is that the BuildManager
knows nothing about the assemblies within my plug-in folder and it seems to be absolutely nothing I can do to help it. If I do:
BuildManager.GetType("PluginAssembly.DefinedType", true, true)
it throws. If I first get a reference to the Type
and then try:
var instance = BuildManager.CreateInstanceFromVirtualPath(path, type);
it still throws, even though I've now passed in the specific type
it needs to compile the .aspx
file. Is there anything I can do to help BuildManager
find the types it needs to compile the .aspx
file?
Update:
I've come one step further, by looking into what BuildManager.GetType()
actually does. By specifying the assembly the type is defined in (such as "PluginAssembly.DefinedType, PluginAssembly") and then hooking myself onto the System.AppDomain.CurrentDomain.AssemblyResolve
event, I can now find the plug-in assembly and return it so BuildManager can successfully construct the type. This makes the following work with flying colors:
BuildManager.GetType("PluginAssembly.DefinedType, PluginAssembly", true, true)
However, this still fails:
var instance = BuildManager.CreateInstanceFromVirtualPath(path, type);
Even though the .aspx
file now has the same assembly reference in its Inherits
directive:
<%@ Page Language="C#"
CodeBehind="Index.aspx.cs"
Inherits="PluginAssembly.DefinedType, PluginAssembly" %>
The error I receive is:
"Compiler Error Message: CS0234: The type or namespace name 'DefinedType' does not exist in the namespace 'PluginAssembly' (are you missing an assembly reference?)" with the following source output:
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;
It seems like what happens inside BuildManager.CreateInstanceFromVirtualPath()
involves a certain System.Web.Util.IWebObjectFactory
that it might be responsible for throwing this exception by not finding my assembly. I can implement this interface without any problems, but what does that help if I can't tell the BuildManager
about it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我看到有两种方法可以指定用于编译页面的程序集:
I see two ways you can specify the assemblies used to compile a page :
我不知道
BuildManager
如何加载类型,但您可以尝试使用AssemblyResolve
- 订阅AppDomain.CurrentDomain.AssemblyResolve
事件,并自行加载程序集并返回(是的,返回)Assembly
实例(如果您不认识它,则返回null
)。并非所有此类代码都使用与此兼容的方法,但值得一试。
I don't know how
BuildManager
loads the types, but you could try usingAssemblyResolve
- subscribe to theAppDomain.CurrentDomain.AssemblyResolve
event, and load the assembly yourself and return (yes, return) theAssembly
instance (ornull
if you don't recognise it).Not all such code uses approaches compatible with this, but it is worth a try.
我最终用 解决了这个问题Web 部署项目 [1] 通过将整个 Web 应用程序预编译为两个单独的程序集,然后使用
Assembly.GetTypes()
挖掘正确的程序集以实例化正确的Page 给定的 HTTP 请求。
它让插件开发人员承担更多的责任,但可以带来更好的性能,并带来额外的好处,即所有插件在(安全敏感且脆弱的)Web 上下文中执行之前都经过 ASP.NET 编译器的完全验证。 。
I ended up solving this with Web Deployment Projects [1] by pre-compiling the whole web application into two separate assemblies and then digging into the right assembly with
Assembly.GetTypes()
to instantiate the correctPage
for the given HTTP request.It puts more on the shoulders of the plug-in developers, but yields better performance with the added benefit of having all plug-ins completely verified by the ASP.NET compiler before they're executed in a (security sensitive and fragile) web context.
我正在为 ASP.NET 自己开发一个延迟加载框架。
您的插件始终可以在其页面中使用
<@Assembly>
指令来手动引用程序集。I'm developing a lazy loading framework for ASP.NET myself.
Your plug-ins can always use the
<@ Assembly>
directive in their pages to manually reference the assembly.