MVC Area 技術的使用 - 同名 Controller 處理方法

 

打鐵趁熱,繼續利用上一個 Project 來了解同名 Controller 的處理方法。

 

一、處理頂層 Controller 同名問題

先在 MyArea 底下改成與頂層同名的 HomeController

 

View 的部份也要修改一下成 MyArea/Views/Home

 

先來看頂層的index.cshtml,按F5執行如下圖,出現同名Controller問題

 

因為網站初始會先顯示該首頁之前,就會拿頂層的 HomeController 去跟其他 Controller 比對發現有同名 Controller。

此時於頂層的 RouteConfig.cs 限制一下命名空間「namespaces: new string[] { "WebApplication1.Controllers" }」,

表示此 routing 規則限用於 WebApplication1.Controllers 命名空間

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace WebApplication1
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

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

頂層的 HomeController 同名問題即可解決。

 

二、處理 Area 層 Controller 同名問題

接下來繼續發覺問題,

於頂層的 _Layout.cshtml 裡新增一個連到 MyArea/Home/Index 的超連結,

_Layout.cshtml 的內容為

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                    <li>@Html.ActionLink("MyAreaHome", "Index", new { controller = "Home", area = "MyArea" })</li>
                </ul>
            </div>
        </div>
    </div>
    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>
        </footer>
    </div>

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>
</html>

 

我們故意要把問題顯現出來,將 Area 層的 MyAreaAreaRegistration.cs 的內容

using System.Web.Mvc;

namespace WebApplication1.Areas.MyArea
{
    public class MyAreaAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get
            {
                return "MyArea";
            }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "MyArea_default",
                "MyArea/{controller}/{action}/{id}",
                new { action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

改成

using System.Web.Mvc;

namespace WebApplication1
{
    public class MyAreaAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get
            {
                return "MyArea";
            }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "MyArea_default",
                "MyArea/{controller}/{action}/{id}",
                new { action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

繼續 F5 執行並點選「MyAreaHome」超連結

 

假設路由的命名空間都在 WebApplication1 之下,此時會出現 MyArea 的 HomeController 同名問題

也是一樣修改方法,於 MyAreaAreaRegistration.cs 檔,限制一下命名空間,修改程式碼如下

using System.Web.Mvc;

namespace WebApplication1
{
    public class MyAreaAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get
            {
                return "MyArea";
            }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "MyArea_default",
                "MyArea/{controller}/{action}/{id}",
                new { action = "Index", id = UrlParameter.Optional },
                namespaces: new string[] { "WebApplication1.Areas.MyArea.Controllers" }
            );
        }
    }
}

問題即可解決。

 

三、路由的命名空間限制

接下來再做一點變化,

1、在 MyArea/Controllers 底下再新增一個資料夾「NewFolder1」。

2、NewFolder1 資料夾裡再新增一個名為 DefaultController.cs 檔。

3、再新增對應的View。

經由上圖看 DefaultController.cs 裡面的內容,發現命名空間又多了一層NewFolder1,

執行後觀察卻發現找不到該網頁,原因是路由的命名空間限制問題。

 

請於 MyAreaAreaRegistration.cs 裡也允許使用 WebApplication1.Areas.MyArea.Controllers.NewFolder1 命名空間

using System.Web.Mvc;

namespace WebApplication1
{
    public class MyAreaAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get
            {
                return "MyArea";
            }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "MyArea_default",
                "MyArea/{controller}/{action}/{id}",
                new { action = "Index", id = UrlParameter.Optional },
                namespaces: new string[] { "WebApplication1.Areas.MyArea.Controllers", "WebApplication1.Areas.MyArea.Controllers.NewFolder1" }
            );
        }
    }
}

即可成功找到該網頁。