ASP.NET MVC Маршрутизация с контроллером по умолчанию - PullRequest
14 голосов
/ 11 ноября 2009

Для сценария у меня есть приложение ASP.NET MVC с URL-адресами, которые выглядят следующим образом:

http://example.com/Customer/List
http://example.com/Customer/List/Page/2
http://example.com/Customer/List
http://example.com/Customer/View/8372
http://example.com/Customer/Search/foo/Page/5

Эти URL достигаются следующими маршрутами в Global.asax.cs

routes.MapRoute(
    "CustomerSearch"
    , "Customer/Search/{query}/Page/{page}"
    , new { controller = "Customer", action = "Search" }
);

routes.MapRoute(
    "CustomerGeneric"
    , "Customer/{action}/{id}/Page/{page}"
    , new { controller = "Customer" }
);

//-- Default Route
routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Customer", action = "Index", id = "" }
);

Все это прошло хорошо, пока не появилось новое требование, и он хочет удалить ключевое слово «Клиент» из URL, чтобы URL выглядели так:

http://example.com/List
http://example.com/List/Page/2
http://example.com/List
http://example.com/View/8372
http://example.com/Search/foo/Page/5

Редактировать: исправлены примеры ссылок, благодаря @ haacked.

Я попытался добавить новый MapRoutes, чтобы взять только {action}, и для контроллера по умолчанию было установлено значение Customer. например, /

routes.MapRoute(
    "CustomerFoo"
    , "{action}"
    , new { controller = "Customer", action = "Index" }
);

Кажется, это работает, однако теперь все ссылки, сгенерированные Html.ActionLink (), странные и больше не подходят для URL.

Итак, это достижимо? Я приближаюсь в правильном направлении?

Ответы [ 3 ]

16 голосов
/ 23 ноября 2009

не смешивайте правило вроде: "{action}/{id}" с правилом, которое "{controller}/{action}/{id}" ... особенно, когда id в последнем имеет значение по умолчанию, т.е. является необязательным.

В этом случае у вас нет ничего, что позволяло бы маршрутизации знать, какой из них подходит.

Обходной путь, если это то, что вам нужно, заключается в добавлении ограничения (см. this ) к действию в предыдущем наборе значений, то есть List, View. Конечно, с этими типами правил у вас не может быть контроллера с тем же именем действия.

Также помните, что если вы зададите действие и идентификатор по умолчанию в правиле "{action}/{id}", оно будет использоваться при переходе по маршруту вашего сайта.

10 голосов
/ 22 ноября 2009

Почему первый URL в новом списке все еще имеет "Customer". Я предполагаю, что это опечатка, а вы имели в виду:

У меня работают следующие маршруты:

routes.MapRoute(
    "CustomerSearch"
    , "Search/{query}/Page/{page}"
    , new { controller = "Customer", action = "Search" }
);

routes.MapRoute(
    "CustomerGeneric"
    , "{action}/{id}/Page/{page}"
    , new { controller = "Customer" }
);

//-- Default Route
routes.MapRoute(
    "Default",
    "{action}/{id}",
    new { controller = "Customer", action = "Index", id = "" }
);

Как вы генерируете свои ссылки. Поскольку Controller больше не присутствует в URL-адресе вашего маршрута (иначе, у вас нет «{controller}» в URL-адресе маршрута), но это значение по умолчанию, вам нужно обязательно указать контроллер при создании маршрутов.

Таким образом, вместо

Html.ActionLink("LinkText", "ActionName")

сделать

Html.ActionLink("LinkText", "ActionName", "Customer")

Почему? Предположим, у вас были следующие маршруты.

routes.MapRoute(
    "Default",
    "foo/{action}",
    new { controller = "Cool" }
);

routes.MapRoute(
    "Default",
    "bar/{action}",
    new { controller = "Neat" }
);

Какой маршрут вы имели в виду, когда звонили?

<%= Html.ActionLink("LinkText", "ActionName") %>

Вы можете различить, указав контроллер, и мы выберем тот, чье значение по умолчанию соответствует указанному.

3 голосов
/ 19 сентября 2011

Вы можете создать маршрут, который ограничен только действиями в вашем Customer контроллере .

public static class RoutingExtensions {
    ///<summary>Creates a route that maps URLs without a controller to action methods in the specified controller</summary>
    ///<typeparam name="TController">The controller type to map the URLs to.</typeparam>
    public static void MapDefaultController<TController>(this RouteCollection routes) where TController : ControllerBase {
        routes.MapControllerActions<TController>(typeof(TController).Name, "{action}/{id}", new { action = "Index", id = UrlParameter.Optional });
    }
    ///<summary>Creates a route that only matches actions from the given controller.</summary>
    ///<typeparam name="TController">The controller type to map the URLs to.</typeparam>
    public static void MapControllerActions<TController>(this RouteCollection routes, string name, string url, object defaults) where TController : ControllerBase {
        var methods = typeof(TController).GetMethods()
                                         .Where(m => !m.ContainsGenericParameters)
                                         .Where(m => !m.IsDefined(typeof(ChildActionOnlyAttribute), true))
                                         .Where(m => !m.IsDefined(typeof(NonActionAttribute), true))
                                         .Where(m => !m.GetParameters().Any(p => p.IsOut || p.ParameterType.IsByRef))
                                         .Select(m => m.GetActionName());

        routes.Add(name, new Route(url, new MvcRouteHandler()) {
            Defaults = new RouteValueDictionary(defaults) { { "controller", typeof(TController).Name.Replace("Controller", "") } },
            Constraints = new RouteValueDictionary { { "action", new StringListConstraint(methods) } }
        });
    }

    private static string GetActionName(this MethodInfo method) {
        var attr = method.GetCustomAttribute<ActionNameAttribute>();
        if (attr != null)
            return attr.Name;
        return method.Name;
    }

    class StringListConstraint : IRouteConstraint {
        readonly HashSet<string> validValues;
        public StringListConstraint(IEnumerable<string> values) { validValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase); }

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
            return validValues.Contains(values[parameterName]);
        }
    }

    #region GetCustomAttributes
    ///<summary>Gets a custom attribute defined on a member.</summary>
    ///<typeparam name="TAttribute">The type of attribute to return.</typeparam>
    ///<param name="provider">The object to get the attribute for.</param>
    ///<returns>The first attribute of the type defined on the member, or null if there aren't any</returns>
    public static TAttribute GetCustomAttribute<TAttribute>(this ICustomAttributeProvider provider) where TAttribute : Attribute {
        return provider.GetCustomAttribute<TAttribute>(false);
    }
    ///<summary>Gets the first custom attribute defined on a member, or null if there aren't any.</summary>
    ///<typeparam name="TAttribute">The type of attribute to return.</typeparam>
    ///<param name="provider">The object to get the attribute for.</param>
    ///<param name="inherit">Whether to look up the hierarchy chain for attributes.</param>
    ///<returns>The first attribute of the type defined on the member, or null if there aren't any</returns>
    public static TAttribute GetCustomAttribute<TAttribute>(this ICustomAttributeProvider provider, bool inherit) where TAttribute : Attribute {
        return provider.GetCustomAttributes<TAttribute>(inherit).FirstOrDefault();
    }
    ///<summary>Gets the custom attributes defined on a member.</summary>
    ///<typeparam name="TAttribute">The type of attribute to return.</typeparam>
    ///<param name="provider">The object to get the attribute for.</param>
    public static TAttribute[] GetCustomAttributes<TAttribute>(this ICustomAttributeProvider provider) where TAttribute : Attribute {
        return provider.GetCustomAttributes<TAttribute>(false);
    }
    ///<summary>Gets the custom attributes defined on a member.</summary>
    ///<typeparam name="TAttribute">The type of attribute to return.</typeparam>
    ///<param name="provider">The object to get the attribute for.</param>
    ///<param name="inherit">Whether to look up the hierarchy chain for attributes.</param>
    public static TAttribute[] GetCustomAttributes<TAttribute>(this ICustomAttributeProvider provider, bool inherit) where TAttribute : Attribute {
        if (provider == null) throw new ArgumentNullException("provider");

        return (TAttribute[])provider.GetCustomAttributes(typeof(TAttribute), inherit);
    }
    #endregion
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...