.NET MVC 控制器扩展指南

.NET MVC框架中,经常会遇到需要扩展现有控制器功能的情况。例如,可能需要在主MVC应用程序之外的项目或程序集中添加额外的控制器动作。本文将介绍如何实现这种扩展,包括继承、路由、构建事件等关键步骤。

基本思路

假设有两个项目:

  • ProjectA - 主MVC应用程序
  • ProjectB - 简单的类库

目标是在ProjectA中的现有控制器上添加额外的控制器动作或功能。这些额外的动作不会在主应用程序中出现,而是来自不同的项目/程序集。这在实现特定客户端功能时非常有用,例如,某个客户端可能需要特定的行为,而这些行为在主应用程序中可能并不相关。

控制器定义

在ProjectA中,控制器定义可能如下所示:

namespace ProjectA.Controllers { public class FooController : ApplicationController { public ActionResult Index() { return Content("Foo"); } } }

而在ProjectB中,可能有一个类似的类:

namespace ProjectB.Controllers { public class CustomFooController : FooController { public ActionResult Bar() { return Content("Bar"); } } }

希望所有不同的客户端都能访问Foo,但可能只有特定的客户端才能访问Foo/Bar。

分解步骤

这个过程需要执行几个不同的步骤,以确保一切按预期工作,具体如下:

  • 继承 - 自定义控制器将继承主应用程序中的控制器,以简化扩展。
  • 路由 - 路由可能比较复杂,使用属性路由可以减轻与路由表或冲突控制器名称的负担。
  • 构建事件 - 构建事件是一种简单的方法,可以将自定义项目中的必要.dll文件放入主应用程序中,以便使用。

利用继承

如果确实想要扩展现有控制器的功能,那么继承可能是一个好方法。从主应用程序中的控制器继承将允许利用任何现有的属性、重写的方法或可能已经存在的底层基控制器。

只需要在ProjectB中添加对ProjectA项目的引用,然后定位希望继承的适当控制器:

using ProjectA.Controllers; namespace ProjectB.Controllers { public class CustomFooController : FooController { public ActionResult Bar() { return Content("Bar"); } } }

利用属性路由

这样做在路由方面可能会有些棘手。当尝试在当前应用程序中创建这个新控制器时,它会尝试使用该应用程序中定义的现有路由,这可能导致命名冲突和歧义,如果不小心的话。

根据提供的代码,这意味着可以轻松访问/CustomFoo/Bar,但可能无法像希望的那样访问/Foo/Bar。幸运的是,属性路由可以帮助解决这个问题。

简单地为自定义控制器动作添加一个[Route]属性,指明希望如何访问它:

[Route("Foo/Bar")] public ActionResult Bar() { return new Content("Bar"); }

这将让MVC知道在查看其他一些路由之前,将这个动作映射到Foo/Bar URL。

为了使属性路由按预期工作,需要确保在主应用程序的RouteConfig.cs文件中调用MapMvcAttributeRoutes()方法:

public static void RegisterRoutes(RouteCollection routes) { routes.MapMvcAttributeRoutes(); }

注意:如果正在扩展MVC区域中的控制器,将需要在AreaRegistration.cs文件中的RegisterArea()方法内做同样的事情:

public override void RegisterArea(AreaRegistrationContext context) { context.Routes.MapMvcAttributeRoutes(); }

正确设置路由范围

在主应用程序中,还需要进行一个额外的更改,即优先考虑其自己的命名空间中的路由。MapRoute()方法支持一个重载,可以通过namespaces参数来处理这个问题。

将namespaces参数设置为指向希望优先考虑的命名空间,即主应用程序中的命名空间(例如"ProjectA.Controllers")。

routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Foo", action = "Index", id = UrlParameter.Optional }, namespaces: new[] { "ProjectA.Controllers" } );

到目前为止,从代码的角度来看,一切都应该已经就绪。剩下的唯一事情就是将ProjectB中的代码放入ProjectA中,以便可以运行它。

处理和配置整个过程有多种方法,但一个非常简单的方法可能是通过构建事件。构建事件允许在构建过程的各个阶段执行一些代码。

感兴趣的是定义一个Post-Build事件,将ProjectB.dll文件移动到ProjectA的bin目录中,可能如下所示:

xcopy /E /Y /S "$(ProjectName).dll" "$(SolutionDir)\ProjectA\Bin\"

这将在ProjectB > Properties > Build Events > Post-Build Event Command Line下定义,如下所示:

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485