ASP.NET MVC 4路由用户名/操作问题

时间:2013-02-28 12:42:55

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

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

需要路由的网址

  
      
  1. http://www.mysite.com/foo/user1< ------- {username}
  2.   
  3. http://www.mysite.com/foo/edit
  4.   
  5. http://www.mysite.com/foo/delete/1
  6.   
  7. http://www.mysite.com/bar/user1< ------- {username}
  8.   
  9. http://www.mysite.com/bar/edit
  10.   
  11. http://www.mysite.com/bar/delete/1
  12.   

我遇到的问题是当前{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

3 个答案:

答案 0 :(得分:3)

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

    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 :(得分:2)

这不是你要找的答案,抱歉。

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

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

抱歉,我真的无法帮助你。

答案 2 :(得分:1)

你不能这样做,除非你路由每一条路线,这不是最好的方式。

在其中包含动作名称有什么不妥?