ASP.NET MVC универсальная маршрутизация - PullRequest
6 голосов
/ 27 июля 2011

Я прочитал об этом в нескольких потоках на StackOverflow, но не могу заставить его работать. У меня есть это в конце моего RegisterRoutes в Global.asax.

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

По сути, я пытаюсь добиться того, чтобы mydomain.com/Username указывал на страницу моего профиля. Как мне настроить мой контроллер и RegisterRoutes, чтобы это работало?

В настоящее время mydomain.com/somethingthatisnotacontrollername получает ошибку 404.

Ответы [ 3 ]

6 голосов
/ 27 июля 2011

Решение, которое подходит для вашего случая, но не рекомендуется

В вашем приложении есть предопределенный набор контроллеров (обычно меньше 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
  • сообщения 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 }
);
2 голосов
/ 27 июля 2011

наличие чего-то, совпадающего с mydomain.com/Username, на самом деле не сработает, потому что у механизма маршрутизации нет возможности различить

mydomain.com / someusername

и

mydomain.com / controllername

Возможно, возможно, если ваша схема имени пользователя имеет уникальный набор свойств, то есть последовательность из 9 цифр, вы можете определитьЧтобы найти что-то, похожее на имя пользователя, необходимо указать route.

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

Ключевым моментом является то, что вам нужно предоставить механизму маршрутизации возможность различать имя пользователя и стандартное действие контроллера

Вы можете узнать больше об ограничениях здесь

1 голос
/ 27 июля 2011

У меня было такое требование для моего проекта. Я создал ограничение маршрута, как показано ниже:

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;
}
...