我目前正在开发一个MVC项目,我试图弄清楚如何扩展区域内现有控制器的路由,特别是来自另一个项目。
例如,我有一个控制器,其区域如下所示:
namespace MyProject.Areas.Foo.Controllers
{
[Authorize]
public class FooController : ApplicationController
{
//code
}
}
我想做的是,能够在一个单独的项目中定义另一个Controller,可以像这样扩展它:
namespace MyOtherProject.Areas.Foo.Custom.Controllers
{
public class FooController : ApplicationController
{
public string Bar()
{
return "Bar";
}
}
}
基本上,我希望控制器几乎像我使用partial
关键字那样起作用(这样我就可以调用原始或新的操作中的任何操作)。
主要问题
我真正想要实现的是我有一个主要项目,包含多个区域和我的解决方案的另一个区域,其中包含各种客户端文件夹。我希望能够为我的主项目扩展基本控制器,并在这些客户端文件夹中添加特定于客户端的操作,以便它们可以在主项目中使用。我已经使用某些MVC视图执行此操作,但我希望我也可以使用控制器完成它。
我尝试了什么
partial
关键字,但由于它们位于不同的项目/程序集中,我认为这不起作用。bin
目录中,但似乎没有按预期工作。ControllerFactory
的信息,但我不确定如何实施。路由示例(AreaRegistration)
context.MapRoute(
AreaName,
String.Format("{0}/{{action}}/{{id}}", AreaName),
new { controller = AreaName, action = "Index", id = UrlParameter.Optional },
new[] {
String.Format("MyProject.Areas.{0}.Controllers", AreaName),
String.Format("MyOtherProject.Areas.{0}.Custom.Controllers", AreaName)
}
);
更新
我根据一些评论讨论尝试了一种方法seen here,只需通过继承来处理这个问题:
// Main Project
namespace MyProject.Areas.Foo.Controllers
{
[Authorize]
public class FooController : ApplicationController
{
public ActionResult Index()
{
return View();
}
}
}
// This is in another project / namespace / assembly
namespace MyOtherProject.Foo.Controllers
{
public class CustomFooController : MyProject.Areas.Foo.Controllers.FooController
{
[Route("Foo/Bar")]
public string Bar()
{
return "Bar";
}
}
}
所以我目前的步骤如下:
FooController
。这似乎没有任何区别。我试着去Foo/Bar
网址,但它刚刚扔了404就好像它根本没看到它一样。 CustomFooController.cs
文件位于它自己的独立项目中,只是一个类文件而不是MVC项目。它是否正确?我是否需要在主项目中设置路由规则?
答案 0 :(得分:6)
控制器继承
使用评论部分中提到的Chris继承可能也是解决此问题的最佳方式。如果您已经从示例中的另一个基本控制器类(如ApplicationController
)派生,则尤其如此:
// ProjectA is assumed to be your "main" MVC application
public class CustomFooController : ProjectA.Controllers.FooController
{
[Route("Foo/Bar")]
public ActionResult Bar()
{
return Content("Bar");
}
}
此处的属性路由非常重要,因为您不希望现有路由混淆两个控制器或忽略它们。
注册属性路由
由于您通过ProjectB部分中的[Route]
属性使用属性路由,因此您需要确保在ProjectA项目的RouteConfig.cs
内明确设置它,以便它可以通过Routes.MapMvcAttributeRoutes()
方法正确识别它,如下所示:
public static void RegisterRoutes(RouteCollection routes)
{
// This is important to set up your Route Attributes
routes.MapMvcAttributeRoutes();
// Route declarations omitted for brevity
}
同样,如果您使用的是区域,那么您也希望在相应的AreaRegistration.cs
文件中对其进行配置:
public override void RegisterArea(AreaRegistrationContext context)
{
// Wire up any attribute based routing
context.Routes.MapMvcAttributeRoutes();
// Area routing omitted for brevity
}
确定路线范围
最后,您要确保做的最后一件事是正确的"范围"您在主ProjectA应用程序的RouteConfig.cs
内优先处理主命名空间的路线:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Foo", action = "Index", id = UrlParameter.Optional },
// This will prioritize your existing Controllers so they work as expected
namespaces: new[] { "ProjectA.Controllers"}
);
}
获取
的参考资料您提到使用构建事件将DLL从ProjectB项目复制到您的主ProjectA项目中,在这种情况下应该没问题。您基本上需要一些方式来访问它,并且在大多数情况下,如下所示的简单xcopy
应该没问题:
xcopy /E /Y /S "$(ProjectName).dll" "$(SolutionDir)\ProjectA\Bin\"
全部放在一起
如果您已正确连接所有这些步骤,则应该能够清理/重建现有解决方案。执行此操作后,请仔细检查以确保在ProjectA bin
目录中具有相应的DLL:
如果有,那么您就在正确的轨道上,并且应该能够运行您的主应用程序并导航到~/Foo
以查看以下内容:
同样,导航到~/Foo/Bar
应该选择在其他控制器中定义的相应属性路由并提供适当的内容: