Заполнитель (такой как {category}
) действует как переменная - он может содержать любое значение. Структура должна быть в состоянии понять, что означают параметры в URL. Вы можете сделать это один из трех способов:
- Предоставлять их в определенном порядке, и для определенного числа сегментов
- поместить их в строке запроса, так что вы имеете имя пар/значение, чтобы определить, что они
- сделать ряд маршрутов с буквальным сегментов предоставить имена, чтобы определить, какие параметры
Вот пример опции # 3. Это немного связано с использованием параметров строки запроса, но это, безусловно, возможно, если вы предоставляете какой-то идентификатор для каждого сегмента маршрута.
IEnumerable Расширение
Это добавляет поддержку LINQ для возможности получить все возможные перестановки значений параметров.
using System;
using System.Collections.Generic;
using System.Linq;
public static class IEnumerableExtensions
{
// Can be used to get all permutations at a certain level
// Source: http://stackoverflow.com/questions/127704/algorithm-to-return-all-combinations-of-k-elements-from-n#1898744
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int k)
{
return k == 0 ? new[] { new T[0] } :
elements.SelectMany((e, i) =>
elements.Skip(i + 1).Combinations(k - 1).Select(c => (new[] { e }).Concat(c)));
}
// This one came from: http://stackoverflow.com/questions/774457/combination-generator-in-linq#12012418
private static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source, TSource item)
{
if (source == null)
throw new ArgumentNullException("source");
yield return item;
foreach (var element in source)
yield return element;
}
public static IEnumerable<IEnumerable<TSource>> Permutations<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
throw new ArgumentNullException("source");
var list = source.ToList();
if (list.Count > 1)
return from s in list
from p in Permutations(list.Take(list.IndexOf(s)).Concat(list.Skip(list.IndexOf(s) + 1)))
select p.Prepend(s);
return new[] { list };
}
}
RouteCollection Расширение
Продолжим метод MapRoute
расширения, добавив возможность добавить набор маршрутов, чтобы соответствовать всем возможным перестановкам URL.
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Routing;
public static class RouteCollectionExtensions
{
public static void MapRoute(this RouteCollection routes, string url, object defaults, string[] namespaces, string[] optionalParameters)
{
MapRoute(routes, url, defaults, null, namespaces, optionalParameters);
}
public static void MapRoute(this RouteCollection routes, string url, object defaults, object constraints, string[] namespaces, string[] optionalParameters)
{
if (routes == null)
{
throw new ArgumentNullException("routes");
}
if (url == null)
{
throw new ArgumentNullException("url");
}
AddAllRoutePermutations(routes, url, defaults, constraints, namespaces, optionalParameters);
}
private static void AddAllRoutePermutations(RouteCollection routes, string url, object defaults, object constraints, string[] namespaces, string[] optionalParameters)
{
// Start with the longest routes, then add the shorter ones
for (int length = optionalParameters.Length; length > 0; length--)
{
foreach (var route in GetRoutePermutations(url, defaults, constraints, namespaces, optionalParameters, length))
{
routes.Add(route);
}
}
}
private static IEnumerable<Route> GetRoutePermutations(string url, object defaults, object constraints, string[] namespaces, string[] optionalParameters, int length)
{
foreach (var combination in optionalParameters.Combinations(length))
{
foreach (var permutation in combination.Permutations())
{
yield return GenerateRoute(url, permutation, defaults, constraints, namespaces);
}
}
}
private static Route GenerateRoute(string url, IEnumerable<string> permutation, object defaults, object constraints, string[] namespaces)
{
var newUrl = GenerateUrlPattern(url, permutation);
var result = new Route(newUrl, new MvcRouteHandler())
{
Defaults = CreateRouteValueDictionary(defaults),
Constraints = CreateRouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
};
if ((namespaces != null) && (namespaces.Length > 0))
{
result.DataTokens["Namespaces"] = namespaces;
}
return result;
}
private static string GenerateUrlPattern(string url, IEnumerable<string> permutation)
{
string result = url;
foreach (string param in permutation)
{
result += "/" + param + "/{" + param + "}";
}
System.Diagnostics.Debug.WriteLine(result);
return result;
}
private static RouteValueDictionary CreateRouteValueDictionary(object values)
{
IDictionary<string, object> dictionary = values as IDictionary<string, object>;
if (dictionary != null)
{
return new RouteValueDictionary(dictionary);
}
return new RouteValueDictionary(values);
}
}
Использование
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
url: "Home/CategoryProducts",
defaults: new { controller = "Home", action = "CategoryProducts" },
namespaces: null,
optionalParameters: new string[] { "category", "manufacturer", "attribute" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Это добавляет полный набор маршрутов, чтобы соответствовать модели URL:
Home/CategoryProducts/category/{category}/manufacturer/{manufacturer}/attribute/{attribute}
Home/CategoryProducts/category/{category}/attribute/{attribute}/manufacturer/{manufacturer}
Home/CategoryProducts/manufacturer/{manufacturer}/category/{category}/attribute/{attribute}
Home/CategoryProducts/manufacturer/{manufacturer}/attribute/{attribute}/category/{category}
Home/CategoryProducts/attribute/{attribute}/category/{category}/manufacturer/{manufacturer}
Home/CategoryProducts/attribute/{attribute}/manufacturer/{manufacturer}/category/{category}
Home/CategoryProducts/category/{category}/manufacturer/{manufacturer}
Home/CategoryProducts/manufacturer/{manufacturer}/category/{category}
Home/CategoryProducts/category/{category}/attribute/{attribute}
Home/CategoryProducts/attribute/{attribute}/category/{category}
Home/CategoryProducts/manufacturer/{manufacturer}/attribute/{attribute}
Home/CategoryProducts/attribute/{attribute}/manufacturer/{manufacturer}
Home/CategoryProducts/category/{category}
Home/CategoryProducts/manufacturer/{manufacturer}
Home/CategoryProducts/attribute/{attribute}
Теперь, когда вы используете следующий URL:
Home/CategoryProducts/category/c_50_ShowcasesDisplays
Действие CategoryProducts
на HomeController
. Значение параметра вашей категории будет c_50_ShowcasesDisplays
.
Он также будет строить соответствующий URL при использовании ActionLink
, RouteLink
, Url.Action
или UrlHelper
.
@Html.ActionLink("ShowcasesDisplays", "CategoryProducts", "Home",
new { category = "c_50_ShowcasesDisplays" }, null)
// Generates URL /Home/CategoryProducts/category/c_50_ShowcasesDisplays
Только последний параметр может быть помечен как «UrlParameter.Optional» (иначе механизм маршрутизации не может совпадать с каким). Для того, чтобы ваша текущая реализация работала, вам нужно будет использовать http: // localhost: 50877/Home/CategoryProducts? Category = c_50_ShowcasesDisplays' –
спасибо за ответ, но я хочу использовать сегмент вместо строки запроса –
Тогда вы будете требуется несколько маршрутов и методов. –