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

发布于 2024-08-29 07:12:10 字数 2185 浏览 9 评论 0原文

我正在尝试编写一个插件系统,其中可以将程序集放入 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

好多鱼好多余 2024-09-05 07:12:10

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

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

I see two ways you can specify the assemblies used to compile a page :

  • Calling BuildManager.AddReferencedAssembly (but I assume you already tried that one ?)
  • Putting in the compiling page's virtual directory configuration a list of the required assemblies (in the system.web/compilation/assemblies section) and having these assemblies accessible in the appdomain (the framework seems to use Assembly.Load to find assemblies found in the config files).
∞梦里开花 2024-09-05 07:12:10

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

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

I don't know how BuildManager loads the types, but you could try using AssemblyResolve - subscribe to the AppDomain.CurrentDomain.AssemblyResolve event, and load the assembly yourself and return (yes, return) the Assembly instance (or null if you don't recognise it).

Not all such code uses approaches compatible with this, but it is worth a try.

黑白记忆 2024-09-05 07:12:10

我最终用 解决了这个问题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 correct Page 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.

瑾兮 2024-09-05 07:12:10

我正在为 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文