【问题标题】:Dynamically extending features of an application?动态扩展应用程序的功能?
【发布时间】:2012-06-13 21:43:54
【问题描述】:

我最近在使用 ASP.NET MVC3/4 时遇到了一个 way 来开发可插拔应用程序模块,我喜欢这种方法的简单性。目前,我的应用程序结构如下:

因此,任何想要为我的应用程序开发扩展的人,都遵循上述tutorial 的方法,并创建一个保留在Areas 文件夹中的扩展。我认为当添加新的Areas(创建为新项目)时,会创建.pdb 文件并将其放置在bin 目录中。我的问题是这样的:

  • 如何将Areas 分发为可插拔模块?
  • 如何更改以下代码,以便当有人将新的Area 放入bin 文件夹时,应用程序会自动拾取它并创建一个链接?插件作者应该怎么做才能启用它?

在我的_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>

为简单起见,假设区域名称是唯一的。有关如何执行此操作的任何建议?

【问题讨论】:

  • @tereško:也许你是对的。如果这就是您的意思,我删除了mvc 标签。谢谢指出。
  • 您可能想查看我的类似问题,因为它可能会为您提供一些见解(但没有答案):stackoverflow.com/questions/10151566/…

标签: c# asp.net asp.net-mvc asp.net-mvc-4


【解决方案1】:

如何将区域分配为可插拔模块?

不要在托管 Web 应用程序中创建区域,而是创建单独的项目,编译成单独的 dll。将 dll 复制到您想要使用它的任何 Web 应用程序中。请记住将所有静态文件设置为“EmbeddedResource”。

如何更改以下代码,以便当有人将新区域放入 bin 文件夹时,应用程序会自动将其拾取并创建一个链接?插件作者应该怎么做才能启用它?

您可以使用 MvcContrib PortableAreaRegistration 的“总线”从便携式区域向“总线”上的任何人发送消息、命令。这可以是托管网络应用程序,或者理论上独立的区域可以相互发送消息。

在 github 上创建了两个粗略但实用的演示代码:

MVC3 版本:

https://github.com/AkosLukacs/PluggablePortableAreas

MVC4 RC 版本:

https://github.com/AkosLukacs/PluggablePortableAreasMVC4

首先,您定义一个可以携带您需要的信息的消息。只是一个具有一些属性的 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; }
    //...
}

为该消息类型创建一个处理程序 (PluggablePortableAreas.Common\RegisterAreaEventHandler.cs):

public class RegisterAreaEventHandler : MessageHandler<RegisterAreaMessage>{}

在这种情况下,MessageHandler 只是将接收到的消息添加到静态ConcurrentBag&lt;RegisterAreaMessage&gt;。如果您愿意,可以使用 DI,但要保持简单。

您可以像这样从便携式区域发送消息(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));

通过遍历消息集合(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>
                }

还有一点需要注意:使用“完全限定”的区域名称。如果您没有明确指定区域名称,MVC 会假定它是当前区域。没有区域没有问题,但是第二个会指向"/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>

还有一件事要注意!

VS 中的开发服务器感觉有点“不稳定”,有时可移植区域无法加载。在完整的 IIS 中可靠地工作...

【讨论】:

  • +1 感谢您的详细回答。我目前正在尝试这个。我的最后一个问题是 MVCContrib 是否与 MVC4 兼容,因为这是我目前使用的。如果这种技术不能向后兼容,我将来可能会面临更大的问题。如果您对此有任何意见,请告诉我。另外,我很想知道 MVCContrib 是否有任何替代方案,或者这是每个人都采用基于插件的架构的方式吗?
  • MVC4 仍然是测试版,所以还没有尝试过。我猜(也希望)MVCContrib 会在它最终定稿时跟进。或者可能会有一些框架支持在没有 MVCContrib 的情况下完成。
  • 在 MVC4 RC 中工作,代码在 github -> 检查链接的更新答案。
  • 非常感谢您在这件事上花费的时间。也非常感谢您提供示例回购!抱歉,我耽搁了一点……刚刚转移了赏金:)
【解决方案2】:

您所做的与MVCContrib 的便携式区域非常相似。

他们使用消息/应用程序总线模式在 Web 元素上动态添加新的小部件。 MessageHandlers 是通过反射发现的,每条消息都传递给它们。所以在你的情况下,插件作者应该只为标准消息实现一个处理程序(比如注册全局菜单链接)。

便携式区域的资源是嵌入的,因此可以将单个 dll 放入 bin 文件夹中。为了自动获取它并在您的应用程序中使用它,您必须通过FileSystemWatcher 观看 bin 文件夹并重新启动您的应用程序(没有其他方法可以将新的 .dll 加载到 asp.net 应用程序中的 AppDomain我认为)。

您也可以使用 ASP.NET 4 中的 BuildManager 功能从其他文件夹加载 .dll。有关 here 的更多有用信息。

【讨论】:

  • 无需添加 FileSystemWatcher,因为 ASP.NET Web 应用程序会在 bin 目录内容、您的 web.config 或 App_code 内容发生变化时自动重启。
【解决方案3】:

这看起来类似于 Orchard CMS 处理模块的方式。

看看他们的Gallery... 这些模块作为 Nuget 包分发,包含整个模块项目。

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      看看这个tutorial我想它会对你有很大帮助。

      【讨论】:

      • 唯一的问题似乎是本教程与 MVC2 相关,而我目前正在使用 MVC4。不知道这会对我有什么影响。
      • 实际上我没有在 MVC4 中测试它,但我想它应该可以工作。顺便说一句,感谢您提出这个精彩的问题 :)
      • 也感谢您的教程! :) @AkosLukacs 如果您有兴趣,请在 github 上发布示例项目。
      猜你喜欢
      • 2014-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      相关资源
      最近更新 更多