[转载]OSGi.NET-based ASP.NET插件平台开发中遇到的一个很有意思的问题

[转载]OSGi.NET-based ASP.NET插件平台开发中遇到的一个很有意思的问题 – 道法自然 – 博客园.

到目前为止,我们的OSGi.NET平台已经越来越完善了,因此我开始着手实现基于OSGi.NET的Desktop Plugin Framework和ASP.NET Web Plugin Framework。Desktop Plugin Framewok比较简单,可以直接将OSGi集成到启动类里面,不过在ASP.NET遇到了一个很有意思的问题。
以 下是Web Plugin Framework的结构,它只是暴露出一个Default.aspx页面,这是一个完全空白的页面,根据具体应用由Plugin来填充内容。 Global.asax用于启动和停止OSGi框架。bin目录包含了对OSGi.NET类库的引用。
WebPluginFramework
–Default.aspx
–Global.asax
–bin
——–WebPluginFramework.dll
——–UIShell.OSGi.dll
——–UIShell.OSGi.Web.dll
–Plugins
——–TestPlugin(使 用VS创建的ASP.NET网站项目)
—————–bin/lib/share…*.dll
—————–Default.aspx
—————–Manifest.xml
——–TestPlugin2(使 用VS创建的ASP.NET网站项目)
—————–bin/lib/share…*.dll
—————–Default.aspx
—————–Manifest.xml
我 们在设计用户开发和调试插件的场景如下:(1)用户在Plugins目录下创建一个ASP.NET网站工程项目,比如TestPlugin项目;(2)添 加Manifest.xml文件,设置插件的名称、插件运行时类库、插件激活器、插件注册的服务;(3)用户可以通过2种模式调试插件:A)将 WebPluginFramework部署到IIS,利用附加进程到w3wp.exe进行调试;B)用户打开WebPluginFramework项目, 利用VS直接进行调试。
这种模式听起来我觉得还不错,但是当我运行Web应用时,一旦加载 TestPlugin/Default.aspx时,我便遇到一个Parser Error错误。这个错误指示无法加载TestPlugin/Default.aspx绑定的类TestPlugin._Default。

起初我以为是类加载机 制出了问题,因为OSGi.NET实现了一套插件类加载机制,确保能够从插件的私有程序集中加载到相应的类,即OSGi.NET能够从 TestPlugin/bin等目录下加载到所需的类。然后经过初步调试和判断,发现问题出在ASP.NET的Compilation。ASPX页面是在 请求时动态编译成相应的dll,这个动态编译是由BuildManager来实现,它在编译时无法找到TestPlugin/bin /TestPlugin.dll,也就无法找到TestPlugin._Default这个类了。我搜索了一下相关解决方案,发现搞插件平台的国内外同行 也遇到过类似问题,但是都没有给出一个好的方案。我还查看了Kooboo的插件方案,看能否借鉴点思路。Kooboo CMS开源系统在解决这个问题的时候,采用了很简单的方式,即将TestPlugin.dll直接拷贝到WebPluinFramework/bin目录 底下。然而,我不能这样做,因为这种做法破坏了OSGi.NET优雅的类加载机制,我希望能够在保持这种优雅类加载前提下,实现ASP.NET插件框架。
于 是我下载了.NET框架的PDB,直接Debug进去到BuildManager,发现BuildManager编译ASPX页面的原理,该类在 BuildManager.CompileWebFile实现ASPX页面动态编译,看完源码后,我想到一种简单的解决方法,就是在编译这个页面之前利用 反射将TestPlugin.dll添加到BuildManager.TopLevelReferencedAssemblies私有属性。这种方法最终 解决了ASP.NET插件的实现问题。
1 var assemblyFile = context.Request.PhysicalApplicationPath +
2 @”\\plugins\\TestPlugin\\bin\\TestPlugin.dll;
3 Assembly assembly = Assembly.LoadFile(assemblyFile);
4 IList<Assembly> assemblies = null;
5 PropertyInfo buildManagerProp = typeof(BuildManager).GetProperty(TheBuildManager,
6 BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetProperty);
7 if (buildManagerProp != null)
8 {
9 BuildManager buildManager = buildManagerProp.GetValue(null, null) as BuildManager;
10 if (buildManager != null)
11 {
12 PropertyInfo toplevelAssembliesProp = typeof(BuildManager).GetProperty(
13 TopLevelReferencedAssemblies, BindingFlags.NonPublic |
14 BindingFlags.Instance | BindingFlags.GetProperty);
15 if (toplevelAssembliesProp != null)
16 {
17 assemblies = toplevelAssembliesProp.GetValue(
18 buildManager, null) as IList<Assembly>;
19 }
20 }
21 }
22 if (assemblies != null && assembly != null)
23 {
24 assemblies.Add(assembly);
25 }

Creative  Commons License

本文基于Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必 须保留本文的署名道法自然(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏