ASP.NET MVC 包罗万象的路由

发布于 2024-11-26 15:32:03 字数 416 浏览 2 评论 0原文

我已经在 StackOverflow 上阅读了一些关于此问题的帖子,但无法使其正常工作。我在 Global.asax 的 RegisterRoutes 末尾有这个。

routes.MapRoute(
            "Profile",
            "{*url}",
            new { controller = "Profile", action = "Index" }
            );

基本上我想要实现的目标是让 mydomain.com/Username 指向我的会员个人资料页面。我必须如何设置我的控制器和 RegisterRoutes 才能使其工作?

目前 mydomain.com/somethingthatisnotacontrollername 出现 404 错误。

I have read a few threads on StackOverflow about this, but cannot get it to work. I have this at the end of my RegisterRoutes in Global.asax.

routes.MapRoute(
            "Profile",
            "{*url}",
            new { controller = "Profile", action = "Index" }
            );

Basically what I'm trying to achieve is to have mydomain.com/Username point to my member profilepage. How would I have to set up my controller and RegisterRoutes in order for this to work?

Currently mydomain.com/somethingthatisnotacontrollername gets a 404-error.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

岁月无声 2024-12-03 15:32:03

适用于您的情况但不推荐的解决方案

您的应用程序中有一组预定义的控制器(通常少于 10 个),因此您可以对控制器名称进行限制,然后将其他所有内容路由到用户配置文件:

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional },
    new { controller = "Home|Admin|Reports|..." }
);
routes.MapRoute(
    "Profile",
    "{username}/{action}",
    new { controller = "Profile", action = "Details" }
);

但这在以下情况下不起作用如果某些用户名与您的控制器名称相同。从经验端的实证数据来看,这种可能性很小,但也不是0%的机会。当用户名与某些控制器相同时,它自动意味着它将由第一条路由处理,因为约束不会使其失败。

推荐的解决方案

最好的方法是将 URL 请求设置为:

www.mydomain.com/profile/username

为什么我建议这样做?因为这将使它变得更加简单和清晰,并且允许有几个不同的个人资料页面:

  • 详细信息www.mydomain.com/profile/username
  • 设置www.mydomain.com/profile/username/ settings
  • messages www.mydomain.com/profile/username/messages
  • 等。

这种情况下的路由定义如下:

routes.MapRoute(
    "Profile",
    "Profile/{username}/{action}",
    new { controller = "Profile", action = "Details" }
);
routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

Solution that works for your case but is not recommended

You have a predefined set of controllers (usually less than 10) in your application so you can put a constraint on controller name and then route everything else to user profile:

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional },
    new { controller = "Home|Admin|Reports|..." }
);
routes.MapRoute(
    "Profile",
    "{username}/{action}",
    new { controller = "Profile", action = "Details" }
);

But this will not work in case some username is the same as your controller name. It's a small possibility based on experience end empirical data, but it's not 0% chance. When username is the same as some controller it automatically means it will get handled by the first route because constraints won't fail it.

Recommended solution

The best way would be to rather have URL requests as:

www.mydomain.com/profile/username

Why do I recommend it to be this way? Becasue this will make it much simpler and cleaner and will allow to have several different profile pages:

  • details www.mydomain.com/profile/username
  • settings www.mydomain.com/profile/username/settings
  • messages www.mydomain.com/profile/username/messages
  • etc.

Route definition in this case would be like this:

routes.MapRoute(
    "Profile",
    "Profile/{username}/{action}",
    new { controller = "Profile", action = "Details" }
);
routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
慕巷 2024-12-03 15:32:03

拥有与 mydomain.com/Username 匹配的内容实际上并不起作用,因为路由引擎无法区分

mydomain.com/someusername

mydomain.com/controllername

什么 可能是,如果您的用户名方案具有一组唯一的属性,即 9 位数字的序列,您可以定义一个路由来检查看起来像用户名的内容。

routes.MapRoute("",
        "UserRoute",
        "{username}",
        new { controller = "Profile", action = "Index"},
         new { {"username", @"\d{9}"}}
       );

关键点是,您需要为路由引擎提供某种方法来区分用户名和标准控制器操作

您可以找到有关约束的更多信息 此处

having something that matches to mydomain.com/Username isn't really going to work because there is no way for the routing engine to distinguish between

mydomain.com/someusername

and

mydomain.com/controllername

What might be possible is, if your username scheme has a unique set of properties, i.e. is a sequence of 9 digits, you could define a route to check for something that looks like a username.

routes.MapRoute("",
        "UserRoute",
        "{username}",
        new { controller = "Profile", action = "Index"},
         new { {"username", @"\d{9}"}}
       );

The key point tho, is that you need to provide some way for the routing engine to differentiate between a username and a standard controller action

You can find out more about constraints here

陈独秀 2024-12-03 15:32:03

我的项目有这样的要求。我所做的是创建一个如下所示的路由约束:

public class SeoRouteConstraint : IRouteConstraint
{
    public static HybridDictionary CacheRegex = new HybridDictionary();
    private readonly string _matchPattern = String.Empty;
    private readonly string _mustNotMatchPattern;

    public SeoRouteConstraint(string matchPattern, string mustNotMatchPattern)
    {
        if (!string.IsNullOrEmpty(matchPattern))
        {
            _matchPattern = matchPattern.ToLower();
            if (!CacheRegex.Contains(_matchPattern))
            {
                CacheRegex.Add(_matchPattern, new Regex(_matchPattern));
            }
        }

        if (!string.IsNullOrEmpty(mustNotMatchPattern))
        {
            _mustNotMatchPattern = mustNotMatchPattern.ToLower();
            if (!CacheRegex.Contains(_mustNotMatchPattern))
            {
                CacheRegex.Add(_mustNotMatchPattern, new Regex(_mustNotMatchPattern));
            }
        }
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        var matchReg = string.IsNullOrEmpty(_matchPattern) ? null : (Regex)CacheRegex[_matchPattern];
        var notMatchReg = string.IsNullOrEmpty(_mustNotMatchPattern) ? null : (Regex)CacheRegex[_mustNotMatchPattern];

        var paramValue = values[parameterName].ToString().ToLower();

        return IsMatch(matchReg, paramValue) && !IsMatch(notMatchReg, paramValue);
    }

    private static bool IsMatch(Regex reg, string str)
    {
        return reg == null || reg.IsMatch(str);
    }
}

然后在注册路由方法中:

routes.MapRoute("",
    "UserRoute",
    "{username}",
    new { controller = "Profile", action = "Index"},
     new { username = new SeoRouteConstraint(@"\d{9}", GetAllControllersName())}
   );

GetAllControllersName 方法将返回项目中以 | 分隔的所有控制器名称。 :

private static string _controllerNames;
private static string GetAllControllersName()
{
    if (string.IsNullOrEmpty(_controllerNames))
    {
        var controllerNames = Assembly.GetAssembly(typeof(BaseController)).GetTypes().Where(x => typeof(Controller).IsAssignableFrom(x)).Select(x => x.Name.Replace("Controller", ""));

        _controllerNames = string.Join("|", controllerNames);
    }
    return _controllerNames;
}

I had a requirement like this for my project. What i did was creating a route constraint like below:

public class SeoRouteConstraint : IRouteConstraint
{
    public static HybridDictionary CacheRegex = new HybridDictionary();
    private readonly string _matchPattern = String.Empty;
    private readonly string _mustNotMatchPattern;

    public SeoRouteConstraint(string matchPattern, string mustNotMatchPattern)
    {
        if (!string.IsNullOrEmpty(matchPattern))
        {
            _matchPattern = matchPattern.ToLower();
            if (!CacheRegex.Contains(_matchPattern))
            {
                CacheRegex.Add(_matchPattern, new Regex(_matchPattern));
            }
        }

        if (!string.IsNullOrEmpty(mustNotMatchPattern))
        {
            _mustNotMatchPattern = mustNotMatchPattern.ToLower();
            if (!CacheRegex.Contains(_mustNotMatchPattern))
            {
                CacheRegex.Add(_mustNotMatchPattern, new Regex(_mustNotMatchPattern));
            }
        }
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        var matchReg = string.IsNullOrEmpty(_matchPattern) ? null : (Regex)CacheRegex[_matchPattern];
        var notMatchReg = string.IsNullOrEmpty(_mustNotMatchPattern) ? null : (Regex)CacheRegex[_mustNotMatchPattern];

        var paramValue = values[parameterName].ToString().ToLower();

        return IsMatch(matchReg, paramValue) && !IsMatch(notMatchReg, paramValue);
    }

    private static bool IsMatch(Regex reg, string str)
    {
        return reg == null || reg.IsMatch(str);
    }
}

Then in the register route method:

routes.MapRoute("",
    "UserRoute",
    "{username}",
    new { controller = "Profile", action = "Index"},
     new { username = new SeoRouteConstraint(@"\d{9}", GetAllControllersName())}
   );

The method GetAllControllersName will return all the controller name in your project separated by | :

private static string _controllerNames;
private static string GetAllControllersName()
{
    if (string.IsNullOrEmpty(_controllerNames))
    {
        var controllerNames = Assembly.GetAssembly(typeof(BaseController)).GetTypes().Where(x => typeof(Controller).IsAssignableFrom(x)).Select(x => x.Name.Replace("Controller", ""));

        _controllerNames = string.Join("|", controllerNames);
    }
    return _controllerNames;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文