ASP .NET MVC 专区注册

ASP .NET MVC Area registration

我的 "Admin" 区域注册没有什么问题,它存储在 "Admin" 区域文件夹中的 AdminAreaRegistration.cs 中。我的路线如下所示:

        context.MapRoute(
            "Admin_News",
            "Admin/News",
            new { controller = "News", action = "Index" }
        );

        context.MapRoute(
            "Admin_Pages",
            "Admin/Pages",
            new { controller = "Pages", action = "Index" }
        );

        context.MapRoute(
            "Admin_Galleries",
            "Admin/Galleries",
            new { controller = "Galleries", action = "Index" }
        );

        context.MapRoute(
            "Admin_Categories",
            "Admin/Categories",
            new { controller = "Categories", action = "Index" }
        );

        context.MapRoute(
            "Admin_Products",
            "Admin/Products",
            new { controller = "Products", action = "Index" }
        );

        context.MapRoute(
            "Admin_Files",
            "Admin/Files",
            new { controller = "Files", action = "Index" }
        );

        context.MapRoute(
            "Admin_Orders",
            "Admin/Orders",
            new { controller = "Orders", action = "Index" }
        );

        context.MapRoute(
            "Admin_Codes",
            "Admin/Codes",
            new { controller = "Codes", action = "Index" }
        );

        context.MapRoute(
            "Admin_Login",
            "Admin/Login",
            new { controller = "Login", action = "Index" }
        );

        context.MapRoute(
            "Admin_Panel",
            "Admin",
            new { controller = "Index", action = "Index" }
        );

        context.MapRoute(
            "Admin_Default",
            "Admin/{controller}/{action}/{param}",
            new { param = UrlParameter.Optional }
        );

问题是:当我在 post 上登录时,我使用

return Redirect("~/Admin");

一切正常,直到我想点击 link(生成良好)

<li><a href="@Url.RouteUrl("Admin_Categories")">Categories</a></li> ==
<li><a href="~/Admin/Categories">Categories</a></li>

然后我应该被重定向到 Categories 控制器的 Index 操作,但我被重定向到 Login 控制器的 Index 操作。知道为什么会这样吗?

此致!

编辑 1:

好吧,我已经将 Admin_Categories 路线更改为这条路线:

context.MapRoute(
    "Admin_Categories",
    "Admin/Categories/{action}",
     new { controller = "Categories" }
);

它似乎有效,但现在 url 正在生成动作名称,如果是 Index 动作,我不会这样:

<li><a href="@Url.RouteUrl("Admin_Categories")">Categories</a></li> ==
<li><a href="~/Admin/Categories/Index">Categories</a></li>

如何从 url 中删除操作名称?

编辑 2

好的,所以我的浏览器以某种方式将类别控制器索引操作视图缓存为登录控制器索引操作视图。清除浏览器缓存后问题解决了一段时间。我为所有视图使用了以下缓存属性(仅对需要参数的视图使用了 VarByParam):

[OutputCache(CacheProfile = "OneDayCache")]

但即使清除缓存也无法解决问题。我仍然被重定向到登录控制器索引操作...有什么想法吗?

编辑 3

我使用了那些 AreaRoutes:

context.MapRoute(
    "Admin_Categories",
    "Admin/Categories",
    new { controller = "Categories", action = "Index", param = UrlParameter.Optional },
    new[] { "AMBIT_CMS_MVC.Areas.Admin.Controllers" }
);

context.MapRoute(
    "Admin_Default",
    "Admin/{controller}/{action}/{param}",
    new { controller = "Index", action = "Index", param = UrlParameter.Optional },
    new[] { "AMBIT_CMS_MVC.Areas.Admin.Controllers" }
    );

我用它来创建路线 url:

@Url.RouteUrl("Admin_Categories")

但仍然无法正常工作。管理路由在 Global.asax 中注册,没有任何路由可以覆盖这些...

编辑 4

我发现我的问题是缓存。 Chrome 以某种方式将我的 /Admin/Categories 位置缓存为 /Admin/Login,所以当我点击 url 时,/Admin/Categories 缓存将其重定向到 /Admin/Login.

我使用了 OutputCache 属性,但它似乎无法正常工作。

[OutputCache(CacheProfile = "OneDayCache", VaryByCustom = "Url")]
public ActionResult Index(){...}

VaryByCustom 设置在 Global.asax:

public override string GetVaryByCustomString(HttpContext context, string arg)
    {
        if (arg.Equals("Url"))
        {
            string url = !string.IsNullOrWhiteSpace(context.Request.Url.AbsoluteUri) ? context.Request.Url.AbsoluteUri : string.Empty;
            return "Url=" + url;
        }
        return base.GetVaryByCustomString(context, arg);
    }

http://localhost:50945/Admin/Categories
HTTP/1.1 302 Found
Cache-Control: private, max-age=86400
Content-Type: text/html; charset=utf-8
Expires: Thu, 09 Feb 2017 20:24:19 GMT
Last-Modified: Wed, 08 Feb 2017 20:24:19 GMT
Location: /Admin/Login
Server: Microsoft-IIS/10.0
X-AspNetMvc-Version: 5.2
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?TTpcUHJvamVrdHlcQU1CSVQtQ01TLU1WQ1xBTUJJVCBDTVMgTVZDXEFkbWluXENhdGVnb3JpZXM=?=
X-Powered-By: ASP.NET
Date: Wed, 08 Feb 2017 20:24:19 GMT
Content-Length: 439

也许这个 VaryByCustom 不工作。有什么解决办法吗?

你试过用路由属性装饰你的控制器class吗?

[Area("Admin")]
[Route("Categories")]
public class CategoriesController : Controller

这对我遇到的类似问题很有用,不过我使用的是 ASPNET Core,您使用的是哪个版本的 MVC?

我觉得你的路由代码没问题。您确定在登录方法中您已通过正确身份验证吗?只需尝试从您的 "Categories" 控制器中删除 [Authorize] 标签,看看授权是否是问题所在。

致您的第一次编辑:

第三个参数注册默认值。您缺少默认值 action.

将您的路线更改为此路线,它会起作用:

context.MapRoute(
    "Admin_Categories",
    "Admin/Categories/{action}",
     new { controller = "Categories", action = "Index" }
);

更好的解决方案:

为什么不简单地删除所有内容而是这个:

context.MapRoute(
    "Admin_Default",
    "Admin/{controller}/{action}/{param}",
    new { param = UrlParameter.Optional }
);

这意味着请求 /Admin/Foo/Bar 得到这样的解决:

  • Admin-区域
  • 中找到FooController
  • 调用Bar-方法就可以了。

然后简单地使用它来生成 URL 的

@Url.Action("ActionName", "ControllerName", new { Area = "AreaName" })

你可能想要这个:

context.MapRoute(
    "Admin_Default",
    "Admin/{controller}/{action}/{param}",
    new { controller = "Index", action = "Index", id = UrlParameter.Optional }
);

如果你打电话给

@Url.Action("Index", "ControllerName", new { Area = "AreaName" })

生成的 Url 将是 /AreaName/ControllerName 而不是 /AreaName/ControllerName/Index

如果你打电话给

@Url.Action("Index", "Index", new { Area = "AreaName" })

生成的 Url 将是 /AreaName 而不是 /AreaName/Index/Index

你应该一起使用这个 AreaRegistration:

public class AdminAreaRegistration : AreaRegistration 
{
    public override string AreaName 
    {
        get 
        {
            return "Admin";
        }
    }

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

只在确实需要时才创建新路线。然后不要忘记在 MapRoute.

的第三个参数中设置默认值

另请注意,如果您已经在同一控制器的视图中,则编写操作就足够了:

@Url.Action("SomeAction")

如果你在同一区域的视图中,但想调用另一个控制器,你可以这样写:

@Url.Action("SomeAction", "SomeController")

这是 MVC 中区域功能的基本实现:

在你的 AdminAreaRegistration.cs:

context.MapRoute(
    "admin_default",
    "admin/{controller}/{action}/{id}",
    new { action = "Index", id = UrlParameter.Optional }
);

用以下方式装饰您的控制器:

[Area("Admin")]
public class MyController : Controller

另外不要忘记在 global.asax 中添加以下代码行,在你的 Application_Start() 方法中(在所有内容之上):

AreaRegistration.RegisterAllAreas();

在视图中使用:

Url.Action("Index", "Categories", new { Area = "Admin" })

这种方式应该没问题。已测试!