【问题标题】:ASP.NET MVC 4 route username / action issueASP.NET MVC 4 路由用户名/操作问题
【发布时间】:2013-02-14 15:54:23
【问题描述】:

我目前正在开发一个 asp.net mvc 4 应用程序,我需要以下类型的 url:

需要路由的网址

  1. http://www.mysite.com/foo/user1
  2. http://www.mysite.com/foo/edit
  3. http://www.mysite.com/foo/delete/1
  4. http://www.mysite.com/bar/user1
  5. http://www.mysite.com/bar/edit
  6. http://www.mysite.com/bar/delete/1

我遇到的问题是当前 {username} 被视为一项操作,因此为了解决我实施以下路线的问题,但这意味着每次我想实施一个新操作,或者有一个需要 {username} 的控制器,我将不得不更新我的路线:

仅显示 Foo 路线

routes.MapRoute("FooSomeAction", "foo/someaction", new { controller = "Food", action = "SomeAction" });            
routes.MapRoute("FooDelete", "foo/delete/{id}", new { controller = "Food", action = "Delete" });            


routes.MapRoute(
    "FooProfile",
    "foo/{username}",
    new { controller = "Foo", action = "Index", username = "" }
);


// Default route
routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

2 个问题

1) 有没有什么方法可以在不对所有路由进行硬编码的情况下实现上述网址?

2) 处理某人使用的用户名恰好与控制器或操作名称相同的情况的最佳方法是什么?

DotnetShadow

【问题讨论】:

  • 据我所知,您的第二个问题是不可能的。那里也有行动有什么不好?
  • 在里面也有动作有什么不好? – 对不起,你这是什么意思?
  • 抱歉,如果我含糊其辞,我的意思是您可以在链接中同时包含动作和控制器名称吗? /User/Edit/User1 之类的东西?

标签: asp.net-mvc asp.net-mvc-4 routes asp.net-mvc-routing


【解决方案1】:

您可以创建一个自定义路由约束来检查用户名是否存在于控制器的可能操作中。如果它找到一个动作匹配,它会失败并使用你的默认路由(例如编辑)。出于性能原因,您可能希望缓存该列表,但我将其留给您。

    private static List<Type> GetSubClasses<T>()
    {
        return Assembly.GetCallingAssembly().GetTypes().Where(
            type => type.IsSubclassOf(typeof(T))).ToList();
    }

    public static  List<string> GetActionNames(string controllerName)
    {
        controllerName = controllerName + "Controller";
        var controller = GetSubClasses<Controller>().FirstOrDefault(c => c.Name == controllerName);

        var names = new List<string>();
        if (controller != null)
        {
            var methods = controller.GetMethods(BindingFlags.Public | BindingFlags.Instance);
            foreach (var info in methods)
            {
                if (info.ReturnType == typeof(ActionResult))
                {
                    names.Add(info.Name);
                }
            }

        }
        return names;
    }


    public class UsernameNotAction : IRouteConstraint
    {
        public bool Match
            (
                HttpContextBase httpContext,
                Route route,
                string parameterName,
                RouteValueDictionary values,
                RouteDirection routeDirection
            )
        {
            int i = 0;
            var username = values["username"];
            var actionList =  GetActionNames(values["controller"].ToString());

            return !actionList.Any(a => a.ToUpper() == username.ToString().ToUpper());
        }
    }


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

        routes.MapRoute(
            "FooProfile",
            "{controller}/{username}",
            new { controller = "Home", action = "Index2", username = "" },
            new { IsParameterAction = new UsernameNotAction() }
        );
        // Default route
        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

【讨论】:

  • 这是一个非常有趣的解决方案。您肯定不想在每次导航时都进行数据库调用,但他可以在会话中存储用户名列表。我不确定我是否喜欢它,但我会为原创性和一个很酷的想法 +1。
  • Good Stuff Mark,我实际上是在考虑某种约束,但我也担心性能。感谢您的替代方法
  • 它实际上并不是在进行数据库调用——它是在使用反射测试动作是否在控制器中(实际上可能对性能更差,但谁知道呢)
  • 啊,我刚刚看了描述。我明白了,所以你基本上会做 User.Identity.Username 并检查动作/控制器。非常聪明。
  • 其实很聪明 我想知道这种方法是否已经被其他人使用过,显然你必须使用它或者知道如何将它写下来:-P
【解决方案2】:

这不是您真正想要的答案,抱歉。

1) 没有办法以这种方式路由。除了您所做的之外,没有什么可以将这些路线彼此区分开来。我不得不质疑为什么这甚至是必要的,我相信你有充分的理由,但这对我来说毫无意义。您仍在使用 Index 操作,所以为什么不直接使用 /foo/index/username。我能想到的,是你出于某种原因无法控制网址。

2) 如果使用默认路由,没有问题。用你的路由,有问题。您唯一真正的选择是让您的控制器和操作名称保留字(防止用户在数据库中使用这些用户名创建)。

对不起,我真的帮不了你。

【讨论】:

  • 关于 1) 将索引作为操作的好点,我猜 /foo/username 看起来更干净 基本上我的想法是,如果您公开查看某人的个人资料,我会: /profile/username /朋友/用户名/画廊/用户名,但如果我在自己的个人资料中,我会做 /profile/edit/1 /friends/list /gallery/delete/1 如果这有意义吗?
  • 我明白你想要做什么,但适用于所有情况的 83.57% 的默认路由是控制器/操作/视图。如果你想打破这种模式,你就是在为自己创造工作,所以问问自己,付出所有努力与收获是否值得。国际海事组织。
  • 另外,人们不应该通过修改 url 来浏览您的网站,这些将通过 actionlinks 来实现,真的,有人会查看 url 或关心它的样子吗? mysite/viewusers/index/bob1111 vs mysite/viewusers/bob1111,谁会真正关心? :)
  • 我同意 actionlinks 是人们浏览网站的方式,它更多的是关于最初的公共个人资料页面。如果您从访问网站的人的角度来考虑,通常您会使用 www.mysite.com 而不是 www.mysite.com/index.html 但我同意您的说法,是的,14.43% 不值得
【解决方案3】:

你不能那样做,除非你把每一条路线都安排好,这不是最好的办法。

在其中包含 Action 名称有什么问题?

【讨论】:

  • 在其中包含控制器名称有什么问题? - 这是什么意思?
  • 我的意思是动作名称 通过做mysite.com/bar/user1 这将映射到控制器:栏和动作 user1 你想点击控制器:栏动作:索引,但这不是 MVC 路由的工作方式你需要做类似mysite.com/bar/ActionName/user1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-13
  • 2011-11-30
  • 2013-06-07
相关资源
最近更新 更多