ASP.net MVC маршрутизация с необязательным первым параметром - PullRequest
10 голосов
/ 29 ноября 2011

Мне нужно предоставить следующие функциональные возможности для одного из веб-сайтов.

http://www.example.com/[sponsor]/{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)
    {
    }

Ответы [ 4 ]

15 голосов
/ 29 ноября 2011

В вашем случае 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

может соответствовать обоим маршрутам: первый будет иметь спонсора = а, контроллера = b и действия = с; второй будет иметь контроллер = 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.

9 голосов
/ 15 января 2014

В моем случае я решил эту проблему, используя следующие два маршрутизатора:

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);
  }
}
4 голосов
/ 29 ноября 2011

В дополнение к добавлению второго маршрута перед маршрутом по умолчанию, как сказал Сергей в своем ответе, вы также должны добавить RouteConstraint к исходному маршруту, чтобы убедиться, что токен {sponsor} является именем действующего спонсора. .

Вы можете использовать RouteConstraint в этом ответе: Пользовательская маршрутизация Asp.Net и пользовательская маршрутизация и добавление категории перед контроллером

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

0 голосов
/ 25 июля 2017

я покажу вам в простом примере, вам не нужно изменять в 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();
        }

Результаты

localhost: 2345 / Имя / имя контроллера / имя действия / идентификатор (необязательно)

...