ASP.net MVC маршрутизации с дополнительным первым параметром
Мне нужно предоставить следующие функции для одного из веб-сайтов.
http://www.example.com/ [спонсор]/{controller}/{action}
В зависимости от [спонсора] веб-страница должна быть настроена.
Я попробовал комбинацию регистрации маршрутов с помощью Application_Start и Session_Start, но не смог заставить ее работать.
public static void RegisterRoutes(RouteCollection routes, string sponsor)
{
if (routes[sponsor] == null)
{
routes.MapRoute(
sponsor, // Route name
sponsor + "/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
}
Кроме того, должно выполняться поведение по умолчанию без [спонсор].
Может кто-то, пожалуйста, сообщите мне, если технически возможно иметь необязательный первый параметр в URL MVC3. Если да, просьба поделиться им. Спасибо.
Обновленный код
После внесения изменений, предложенных Сергеем Кудрявцевым, код работает, когда задано значение.
Если имя не указано, то MVC не направляет контроллер/действие.
Обратите внимание, что это работает только для домашнего контроллера (оба и не для спонсоров). Для других контроллеров/действий, даже если указан параметр спонсора, он не маршрутизируется.
Пожалуйста, предложите, что нужно изменить.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"SponsorRoute",
"{sponsor}/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"NonSponsorRoute",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional, sponsor = string.Empty }
);
}
Метод действий
public ActionResult Index(string sponsor)
{
}
Ответы
Ответ 1
В вашем случае sponsor
не следует рассматривать как постоянную часть URL-адреса, а как переменную часть.
В Global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
...
routes.MapRoute(
"SponsorRoute",
"{sponsor}/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"NonSponsorRoute",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional, sponsor=string.Empty }
);
...
}
В ваших контроллерах, например, HomeController.cs:
namespace YourWebApp.Controllers
{
public class HomeController : Controller
{
public ActionResult Index(string sponsor)
{
// Here you can do any pre-processing depending on sponsor value, including redirects etc.
}
...
}
}
Обратите внимание, что тип этого параметра всегда будет System.String
, а имя компонента шаблона маршрута {sponsor}
должно точно соответствовать имени параметра действия string sponsor
в ваших контроллерах.
UPD: добавлен второй маршрут для не спонсорского дела.
Обратите внимание, что такая настройка осложнит вашу логику, потому что вы можете путать разные URL-адреса, например URL
http://www.example.com/a/b/c
может быть сопоставлен обоими маршрутами: первый будет иметь спонсор = a, controller = b и action = c; второй - контроллер = a, action = b и id = c.
Эту ситуацию можно избежать, если вы укажете более строгие требования к URL-адресам - например, вы можете захотеть, чтобы идентификаторы были только численными. Ограничения указаны в четвертом параметре функции routes.MapRoute()
.
Другим подходом для устранения неоднозначности является указание отдельных маршрутов для всех ваших контроллеров (как правило, у вас не будет много их в вашем приложении) до родового маршрута для спонсоров.
UPD:
Самый простой, но наименее поддерживаемый способ различать спонсорские и не спонсорские маршруты - это указать маршруты, специфичные для контроллера, например:
public static void RegisterRoutes(RouteCollection routes)
{
...
routes.MapRoute(
"HomeRoute",
"Home/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional, sponsor=string.Empty }
);
routes.MapRoute(
"AccountRoute",
"Account/{action}/{id}", // URL with parameters
new { controller = "Account", action = "Index", id = UrlParameter.Optional, sponsor=string.Empty }
);
...
routes.MapRoute(
"SponsorRoute",
"{sponsor}/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
...
}
Обратите внимание, что здесь все маршруты, специфичные для контроллера, должны быть добавлены до SponsorRoute.
Более сложный, но более чистый способ реализует RouteConstraints для имен спонсоров и контроллеров, как описано в ответе от @counsellorben.
Ответ 2
В моем случае я решил эту проблему, используя следующие два маршрутизатора:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "MultiCulture",
url: "{culture}/{controller}/{action}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { culture = new CultureConstraint(CultureFactory.All.Select(item => item.UrlPrefix).ToArray()) }
).RouteHandler = new MultiCultureMvcRouteHandler();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
}
}
Где класс CultureConstraint
выглядит следующим образом:
public class CultureConstraint : IRouteConstraint
{
private readonly string[] values;
public CultureConstraint(params string[] values)
{
this.values = values;
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary routeValues, RouteDirection routeDirection)
{
string value = routeValues[parameterName].ToString();
return this.values.Contains(value);
}
}
И MultiCultureMvcRouteHandler
:
public class MultiCultureMvcRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
{
var culture = CultureManager.GetCulture(requestContext.RouteData);
if (culture != null)
{
var cultureInfo = new CultureInfo(culture.Name);
Thread.CurrentThread.CurrentUICulture = cultureInfo;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureInfo.Name);
}
return base.GetHttpHandler(requestContext);
}
}
Ответ 3
В дополнение к добавлению второго маршрута до маршрута по умолчанию, как сказал Сергей в своем ответе, вы также должны добавить RouteConstraint
к первоначальному маршруту, чтобы обеспечить, чтобы токен {sponsor}
был именем действительного спонсора.
Вы можете использовать RouteConstraint в этом ответе: Пользовательская маршрутизация Asp.Net и настраиваемая маршрутизация и добавление категории перед контроллером
Помните, что вы также должны применять правило, согласно которому имя спонсора не может быть таким же, как любое имя вашего контроллера.
Ответ 4
я покажу вам в простом примере, что вам не нужно менять Route.config.cs
только вам нужно сделать в Route.config.cs просто вставить
Дополнительные параметры URI. Значения по умолчанию и по умолчанию
Route.config.cs
routes.MapMvcAttributeRoutes();
контроллер
[Route("{Name}/Controller/ActionName")]
public ActionResult Details(string Name)
{
// some code here
return View();
}
Результаты
локальный: 2345/Имя/controllername/ActionName/идентификатор (необязательно)