覆盖/扩展MVC控制器/区域 [英] Overriding / Extending an MVC Controller / Area

查看:73
本文介绍了覆盖/扩展MVC控制器/区域的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在从事MVC项目,并且试图弄清楚如何扩展区域内现有Controller的路由,特别是从另一个项目扩展.

I'm currently working on an MVC project and I'm trying to figure out how I might go about extending the routes of an existing Controller within an Area, specifically from another project.

例如,我有一个控制器,其区域如下图所示:

For instance, I have a Controller with an area that looks like the following :

namespace MyProject.Areas.Foo.Controllers
{
    [Authorize]
    public class FooController : ApplicationController
    {
          //code
    }
}

我想做的是,能够在一个单独的项目中定义另一个Controller,可以像这样扩展它:

And what I would like to do, is be able to define another Controller, within a separate project that could extend this like so :

namespace MyOtherProject.Areas.Foo.Custom.Controllers
{
    public class FooController : ApplicationController
    {
          public string Bar()
          {
               return "Bar";
          }
    }
}

基本上,我希望控制器几乎可以像使用partial关键字那样运行(以便我可以调用原始操作或新操作中的任何操作).

Basically, I would like the controllers to almost function as if I was using the partial keyword (so that I could call any of the actions in the original or the new one).

主要问题

我真正要完成的工作是,我有一个包含多个区域的主项目,而我的解决方案的另一个区域具有多个客户端文件夹.我希望能够从本质上扩展我的主项目的基本控制器,并在这些客户端文件夹中添加特定于客户端的操作,以便可以在主项目中使用它们.我已经使用某些MVC视图进行了此操作,但我希望也可以使用控制器来完成此操作.

What I am really trying to accomplish is that I have a main project with several areas and another area of my solution with various client folders. I want to be able to essentially extend the base controllers for my main project and add client-specific actions within these client folders so that they can be used in the main project. I'm already doing this with certain MVC Views, but I was hoping I could accomplish it with controllers as well.

我尝试过的事情

  • 我尝试在类的两个声明上使用partial关键字,但是由于它们位于不同的项目/程序集中,所以我认为这不起作用.
  • 我定义了一个构建事件,该事件会将自定义DLL移到主MVC项目的bin目录中,但似乎没有按预期工作.
  • 我尝试了各种继承方法,希望可以使用新类,但是这些类不起作用(收到重复的控制器声明错误).
  • 我已经读过有关尝试使用自定义ControllerFactory的信息,但是我不确定如何实现它.
  • 我尝试在AreaRegistration部分中定义自定义名称空间路由参数,以选择新的控制器,如下例所示.
  • I tried using the partial keyword on both declarations of the class, but since they are in different projects / assemblies, I don't think that works.
  • I defined a build event that would move the custom DLL into the bin directory of the main MVC project, but that didn't seem to work as expected.
  • I've tried various approaches for inheritance, hoping the new class would get picked up, but those didn't work (received the duplicate controller declaration error).
  • I've read about trying to use a custom ControllerFactory but I wasn't sure how to implement it.
  • I've tried defining custom namespace routing parameters in the AreaRegistration section to pick up the new controller like the following example.

路由示例(区域注册)

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)
    }
);

更新

我尝试了一种方法在此看到,其中涉及一些通过简单地通过继承来处理的注释讨论:

I attempted an approach seen here as per some of the comments discussion that involved simply handling this via inheritance :

// 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";
        }
    }
}

所以我当前的步骤如下:

So my current steps are as follows :

  • 从另一个项目/解决方案中的主项目中的基础FooController继承.
  • 设置属性路由以访问自定义控制器,以避免与主项目的路由冲突.
  • 创建了一个构建事件,该事件将在从新的自定义项目构建(因此可以访问)时将自定义DLL移到主项目中.
  • Inherited from the base FooController in the main project within another project / solution.
  • Set up attribute routing to access the custom controller to avoid conflicting routes from the main project.
  • Created a Build Event that moves the custom DLL into the main project when built (so it will be accessible) from the new custom project.

这似乎没有什么区别.我尝试转到Foo/Bar网址,但它只是抛出了404,好像根本看不到它. CustomFooController.cs文件位于它自己的单独项目中,只是一个类文件,而不是MVC项目.这样对吗?我需要在主项目中设置路由规则吗?

This didn't seem to make any difference. I tried going to the Foo/Bar url but it just threw a 404 as if it didn't see it at all. The CustomFooController.cs file is in it's own separate project and is just a class file and not an MVC project. Is this correct? Do I need to set the routing rules in the main project?

推荐答案

控制器继承

在评论部分中提到将继承用作 Chris 可能也是解决此问题的最佳方法.如果您已经从另一个基本控制器类(例如您的示例中的ApplicationController)派生,则尤其如此:

Using inheritance as Chris mentioned in the comments section will likely be the best way of going about this as well. This is especially true if you are already deriving from another base controller class like ApplicationController in your example :

// ProjectA is assumed to be your "main" MVC application
public class CustomFooController :  ProjectA.Controllers.FooController
{
    [Route("Foo/Bar")]
    public ActionResult Bar()
    {
        return Content("Bar");
    }
}

此处的属性路由非常重要,因为您不希望现有路由混淆两个控制器或忽略它们.

The attribute routing here is extremely important as you don't want your existing routes to confuse your two controllers or overlook them.

注册属性路由

由于您是通过ProjectB部分中的[Route]属性使用属性路由的,因此,您需要确保在ProjectA项目的RouteConfig.cs中明确设置它,以便它可以通过Routes.MapMvcAttributeRoutes()方法如下所示:

Since you are using attribute routing via the [Route] attribute within your ProjectB section, you'll want to ensure that you explicitly set it within the RouteConfig.cs of your ProjectA project so that it can properly identify it through the Routes.MapMvcAttributeRoutes() method as seen below :

public static void RegisterRoutes(RouteCollection routes)
{
    // This is important to set up your Route Attributes
    routes.MapMvcAttributeRoutes();

    // Route declarations omitted for brevity
}

同样,如果您使用的是Areas,则还要在相应的AreaRegistration.cs文件中进行配置:

Likewise, if you are using Areas, you'll want to configure this within the respective AreaRegistration.cs file as well :

public override void RegisterArea(AreaRegistrationContext context) 
{
    // Wire up any attribute based routing
    context.Routes.MapMvcAttributeRoutes();

    // Area routing omitted for brevity
}

作用域路线

最后,您要确保做的最后一件事是正确地监视"您的路由,以便在主ProjectA应用程序的RouteConfig.cs中对主名称空间进行优先级排序:

Finally, the last thing you'll want to make sure to do is properly "scope" your routes to prioritize your main namespace within the RouteConfig.cs of your main ProjectA application :

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"}
    );
}

获取参考文献

您提到使用Build Event将DLL从ProjectB项目复制到主ProjectA项目中,在这种情况下应该可以.基本上,您将需要使用某种方式进行访问,并且在大多数情况下,像下面这样的简单xcopy就可以了:

You mentioned using a Build Event to copy over the DLL from your ProjectB project into your main ProjectA project, which should be fine in this case. You will basically need some way to access it and a simply xcopy like the following should be fine in most scenarios :

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

全部组合

如果正确连接了所有这些步骤,则应该能够清理/重建现有的解决方案.这样做之后,请仔细检查以确保您在ProjectA bin目录中具有适当的DLL:

If you have wired up all of these steps correctly, you should be able to Clean / Rebuild your existing solution. After doing so, double-check to ensure that you have the appropriate DLL within your ProjectA bin directory :

如果在那里,那么您就走对了,应该能够运行您的主应用程序并导航到~/Foo来查看以下内容:

If that is there, then you are on the right track and should be able to run your main application and navigate to ~/Foo to see the following :

同样,导航到~/Foo/Bar应该选择在您的其他Controller中定义的适当属性路由,并提供适当的内容:

Likewise, navigating to ~/Foo/Bar should pick up the appropriate attribute route that was defined in your other Controller and serve the proper content :

这篇关于覆盖/扩展MVC控制器/区域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆