c# - 覆盖/扩展 MVC Controller /区域

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

我目前正在处理一个 MVC 项目,我正在尝试弄清楚如何在一个区域内扩展现有 Controller 的路由,特别是从另一个项目。

例如,我有一个 Controller ,其区域如下所示:

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

基本上,我希望 Controller 的功能几乎就像我在使用 partial 关键字一样(这样我就可以调用原始或新操作中的任何操作)。

主要问题

我真正想要完成的是,我有一个包含多个区域的主项目和包含各种客户端文件夹的解决方案的另一个区域。我希望能够从本质上扩展我的主项目的基本 Controller ,并在这些客户端文件夹中添加特定于客户端的操作,以便它们可以在主项目中使用。我已经对某些 MVC View 执行此操作,但我希望我也可以使用 Controller 来完成它。

我尝试过的

  • 我尝试在类的两个声明中使用 partial 关键字,但由于它们位于不同的项目/程序集中,我认为这行不通。
  • 我定义了一个构建事件,它将自定义 DLL 移动到主 MVC 项目的 bin 目录中,但这似乎没有按预期工作。
  • 我已经尝试了各种继承方法,希望新类能够被采用,但这些都没有用(收到重复的 Controller 声明错误)。
  • 我读过有关尝试使用自定义 ControllerFactory 的文章,但我不确定如何实现它。
  • 我已经尝试在 AreaRegistration 部分定义自定义命名空间路由参数来获取新 Controller ,如下例所示。

路由示例(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
  • 设置属性路由以访问自定义 Controller ,以避免与主项目的路由冲突。
  • 创建了一个构建事件,在从新的自定义项目构建时将自定义 DLL 移动到主项目中(这样它就可以访问)。

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

最佳答案

Controller 继承

使用继承作为Chris评论部分中提到的可能也是解决此问题的最佳方式。如果您已经从另一个基 Controller 类派生,例如示例中的 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");
    }
}

这里的属性路由非常重要,因为您不希望现有路由混淆或忽略您的两个 Controller 。

注册属性路由

由于您在 ProjectB 部分中通过 [Route] 属性使用属性路由,因此您需要确保在 RouteConfig.cs 中明确设置它您的 ProjectA 项目,以便它可以通过 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:

enter image description here

如果存在,那么您就在正确的轨道上,应该能够运行您的主应用程序并导航到 ~/Foo 以查看以下内容:

enter image description here

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

enter image description here

关于c# - 覆盖/扩展 MVC Controller /区域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37658902/

相关文章:

c# - 删除我的 ASP.NET 应用程序母版页

c# - .NET 中角色的权限

c# - 使用 c# mvc4 阅读 rss 提要

c# - 找不到重载方法

c# - 为什么匿名类不能有 lambda 属性,但它可以有 Func<> 属性?

c# - 用属性覆盖属性

c# - 从 EF 中的集合中删除项目 - 奇怪的问题

c# - 如何在 C# 中为此创建多维列表?

asp.net - ASP .NET MVC 在工作期间进行身份验证和保持用户身份验证的最佳实践

c# - 如何模拟这个 MVC Controller