简体   繁体   English

动态扩展应用程序的功能?

[英]Dynamically extending features of an application?

I recently came across a way to develop pluggable application modules when using ASP.NET MVC3/4 and I loved the simplicity of the approach. 我最近遇到了一种在使用ASP.NET MVC3 / 4时开发可插拔应用程序模块的方法,我喜欢这种方法的简单性。 Currently, I have my applications structured as follows: 目前,我的应用程序结构如下:

在此输入图像描述

Therefore, anyone wanting to develop an extension for my application, follows the approach from the above tutorial and creates an extension that stays in the Areas folder. 因此,任何想要为我的应用程序开发扩展的人都遵循上述教程中的方法,并创建一个保留在Areas文件夹中的扩展。 I figure that when new Areas (created as new projects) are added, .pdb files are created and placed in the bin directory. 我想,当添加新Areas (创建为新项目)时,会创建.pdb文件并将其放在bin目录中。 My question is this: 我的问题是:

  • How does one distribute the Areas as pluggable modules? 如何将Areas分配为可插拔模块?
  • How do I change the following code so that when someone drops a new Area into the bin folder, the application automatically picks it up and creates a link? 如何更改以下代码,以便当有人将新Area放入bin文件夹时,应用程序会自动将其拾取并创建链接? And what should the plugin author do to enable this? 插件作者应该怎么做才能启用它?

In my _Layout.cshtml (global shared layout), I do the following to construct the links: 在我的_Layout.cshtml (全局共享布局)中,我执行以下操作来构建链接:

<ul>
      <li>@Html.ActionLink("Area1", "Index", "Area1", new { Area = "Area1" }, null)</li>
      <li>@Html.ActionLink("Area2", "Index", "Area2", new { Area = "Area2" }, null)</li>
      <li>@Html.ActionLink("Area3", "Index", "Area3", new { Area = "Area3" }, null)</li>
</ul>

For simplicity, assume that the area names are unique. 为简单起见,假设区域名称是唯一的。 Any suggestions on how to do this? 有关如何做到这一点的任何建议?

How does one distribute the Areas as pluggable modules? 如何将Areas分配为可插拔模块?

Don't create the Areas in the hosting web app, but create separate projects, that compile to separate dll's. 不要在托管Web应用程序中创建区域,而是创建单独的项目,编译以分离dll。 Copy the dll's to any web app where you want to use it. 将dll复制到您要使用它的任何Web应用程序。 Remember to set all static files as "EmbeddedResource". 请记住将所有静态文件设置为“EmbeddedResource”。

How do I change the following code so that when someone drops a new Area into the bin folder, the application automatically picks it up and creates a link? 如何更改以下代码,以便当有人将新区域放入bin文件夹时,应用程序会自动将其拾取并创建链接? And what should the plugin author do to enable this? 插件作者应该怎么做才能启用它?

You can use MvcContrib PortableAreaRegistration's "Bus" to send messages, commands from the portable area to anyone on the 'bus'. 您可以使用MvcContrib PortableAreaRegistration的“总线”将便携式区域中的消息,命令发送给“总线”上的任何人。 That can be the hosting web app, or in theory independent Area's can send message to each other. 这可以是托管网络应用程序,或理论上独立区域可以发送消息给对方。

Created two crude, but functional demo of this, code on github: 在github上创建了两个粗略但功能性的演示代码:

MVC3 version: MVC3版本:

https://github.com/AkosLukacs/PluggablePortableAreas https://github.com/AkosLukacs/PluggablePortableAreas

MVC4 RC version: MVC4 RC版本:

https://github.com/AkosLukacs/PluggablePortableAreasMVC4 https://github.com/AkosLukacs/PluggablePortableAreasMVC4

First, you define a message that can carry the information you need. 首先,定义一条可以传递所需信息的消息。 Just a POCO that has some properties (PluggablePortableAreas.Common\\RegisterAreaMessage.cs): 只是一个具有一些属性的POCO(PluggablePortableAreas.Common \\ RegisterAreaMessage.cs):

public class RegisterAreaMessage : IEventMessage
{
    public string LinkText { get; private set; }
    public string AreaName { get; private set; }
    public string ControllerName { get; private set; }
    public string ActionName { get; private set; }
    //...
}

Create a handler for that message type (PluggablePortableAreas.Common\\RegisterAreaEventHandler.cs): 为该消息类型创建一个处理程序(PluggablePortableAreas.Common \\ RegisterAreaEventHandler.cs):

public class RegisterAreaEventHandler : MessageHandler<RegisterAreaMessage>{}

In this case, the MessageHandler just adds the received messages to a static ConcurrentBag<RegisterAreaMessage> . 在这种情况下,MessageHandler只是将收到的消息添加到静态ConcurrentBag<RegisterAreaMessage> You can use DI, if you want to, but wanted to keep it simple. 如果您愿意,可以使用DI,但希望保持简单。

You can send the message from the portable area like this (Areas\\DemoArea1\\Areas\\Demo1\\Demo1AreaRegistration.cs): 您可以从便携式区域发送消息(Areas \\ DemoArea1 \\ Areas \\ Demo1 \\ Demo1AreaRegistration.cs):

 //the portable area sends a message to the 'bus'
 bus.Send(new RegisterAreaMessage("Link to the Demo area", AreaName, DefaultController, DefaultAction));

The dynamically added links are displayed by iterating over the collection of messages(PluggablePortableAreas.Web\\Views\\Shared_Layout.cshtml): 通过迭代消息集合(PluggablePortableAreas.Web \\ Views \\ Shared_Layout.cshtml)显示动态添加的链接:

                @foreach(var sor in PluggablePortableAreas.Common.RegisterAreaEventHandler.RegisteredAreas) {
                <li>@Html.ActionLink(sor.LinkText, sor.ActionName, sor.ControllerName, new{Area=sor.AreaName}, null)</li>
                }

One more thing to take care of: Use "fully qualified" Area names. 还有一件事需要注意:使用“完全限定”的区域名称。 If you don't specify the area name explicitly, MVC assumes it's the current area. 如果未明确指定区域名称,则MVC假定它是当前区域。 No problems without areas, but the second will point to "/path_to_your_app/CurrentArea/Home" instead of "/path_to_your_app/Home" . 没有区域没有问题,但第二个将指向"/path_to_your_app/CurrentArea/Home"而不是"/path_to_your_app/Home"

<li>@Html.ActionLink("Home", "Index", "Home", new { Area = "" }, null)</li>
<li>@Html.ActionLink("I don't work from the portable area!", "Index", "Home")</li>

Even one more thing to note! 还有一件事需要注意!

The development server in VS feels a bit "erratic", sometimes the portable area doesn't load. VS中的开发服务器感觉有点“不稳定”,有时便携式区域无法加载。 Works reliably in full IIS tho... 在完整的IIS中可靠地运行...

What you're doing looks very much alike the MVCContrib 's Portable Areas. 你在做什么看起来与MVCContrib的便携式领域非常相似。

They use the message/application bus pattern to dynamically add new widgets on web elements. 他们使用消息/应用程序总线模式在Web元素上动态添加新的小部件。 MessageHandlers are discovered via reflection and each message is passed to all of them. 通过反射发现MessageHandler,并将每条消息传递给所有消息。 So in your case the plugin author should just implement a handler for a standard message(say register global menu link). 所以在你的情况下,插件作者应该只为标准消息实现一个处理程序(比如注册全局菜单链接)。

Resources of the Portable Areas are embedded so just a single dll could be dropped in the bin folder. 嵌入了可移植区域的资源,因此只能在bin文件夹中删除一个dll。 In order to automatically pick it up and use it in your app you will have to watch the bin folder say via FileSystemWatcher and restart your app(there is no other way to load the new .dll into the AppDomain in asp.net application I think). 为了自动提取并在你的应用程序中使用它你必须通过FileSystemWatcher观察bin文件夹并重新启动你的应用程序(没有其他方法可以将新的.dll加载到asp.net应用程序中的AppDomain中我认为)。

You may load .dlls from other folders as well by using BuildManager functionality in ASP.NET 4. More useful info on that here . 您也可以使用ASP.NET 4中的BuildManager功能从其他文件夹加载.dll。 这里有更多有用的信息。

This looks similar to how Orchard CMS does modules. 这看起来类似于Orchard CMS的模块。

Take a look at their Gallery ... The modules are distributed as Nuget packages, containing the whole module project. 看看他们的画廊 ......模块作为Nuget包发布,包含整个模块项目。

嗨,你可以在nopcommerce项目中寻找相当不错的插件架构。

看看这个教程,我认为它会对你有很大的帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM