MVC5: приоритет маршрутизации атрибутов среди контроллеров

Я использую маршрутизацию атрибутов из MVC5 в своих контроллерах.

Вопрос:

Есть ли способ управлять приоритетом маршрутизации атрибутов среди контроллеров?

Рассмотрим следующее

[Route("home/{action=index}/{username?}")]
public class HomeController : Controller
{
    [Route("home/index/{username?}", Order = 1)]
    [Route("home/{username?}", Order = 2)]
    [Route("{username?}", Order = 3)]
    public ActionResult Index()
    {
        // ... bunch of stuff
    }
}

Основываясь на приведенном выше коде, метод действия HomeController.Index() следует вызывать с помощью следующих запросов:

  • домен/
  • домен/{имя пользователя}
  • домен/дом/
  • домен/дом/{имя пользователя}
  • домен/дом/индекс/
  • домен/дом/индекс/{имя пользователя}

Второй контролер:

[Authorize(Roles = "Member")]
[Route("profile/{action=index}")]
public class ProfileController : Controller
{
    [Route("profile")]
    public ActionResult Index()
    {

    }
}

ProfileController.Index() следует вызывать с помощью следующего запроса.

  • домен/профиль
  • домен/профиль/индекс

Эта проблема

Из примеров, если я отправляю domain/profile в URL, возникает исключение неоднозначности. Кажется, что между domain/{username} и domain/profile есть неясность.

Теперь, если бы я использовал маршрутизацию на основе соглашений, это сработало бы (выигрывает первое совпадение). Но можно ли это сделать в маршрутизации атрибутов MVC5? потому что я обнаружил, что сторонняя библиотека поддерживает приоритет среди контроллеров

https://github.com/mccalltd/AttributeRouting/wiki/Controlling-Route-Precedence

routes.MapAttributeRoutes(config =>
{
    config.AddRoutesFromController<ProfileController>();
    config.AddRoutesFromController<HomeController>();
});

person Yorro    schedule 16.02.2014    source источник


Ответы (1)


Нет, в ASP.Net MVC 5.2.3 невозможно установить приоритет маршрутов контроллера друг над другом. Если несколько совпадений, то порядок действий игнорируется и создается исключение.

Я проверил это, загрузив исходный код с https://aspnetwebstack.codeplex.com/SourceControl/latest и проверка функции GetControllerTypeFromDirectRoute (ниже). Ни один из вызовов, сделанных из этой функции, не делает ничего для определения приоритетов маршрутов, они просто обнаруживаются и сообщаются. Как видите, GetControllerTypeFromDirectRoute просто выдает множественное совпадение.

Совсем не здорово, но, надеюсь, это сэкономит кому-то время.

Я добавил маршрут вручную, чтобы избежать этой проблемы.

 private static Type GetControllerTypeFromDirectRoute(RouteData routeData)
    {
        Contract.Assert(routeData != null);

        var matchingRouteDatas = routeData.GetDirectRouteMatches();

        List<Type> controllerTypes = new List<Type>();
        foreach (var directRouteData in matchingRouteDatas)
        {
            if (directRouteData != null)
            {
                Type controllerType = directRouteData.GetTargetControllerType();
                if (controllerType == null)
                {
                    // We don't expect this to happen, but it could happen if some code messes with the 
                    // route data tokens and removes the key we're looking for. 
                    throw new InvalidOperationException(MvcResources.DirectRoute_MissingControllerType);
                }

                if (!controllerTypes.Contains(controllerType))
                {
                    controllerTypes.Add(controllerType);
                }
            }
        }

        // We only want to handle the case where all matched direct routes refer to the same controller.
        // Handling the multiple-controllers case would put attribute routing down a totally different
        // path than traditional routing.
        if (controllerTypes.Count == 0)
        {
            return null;
        }
        else if (controllerTypes.Count == 1)
        {
            return controllerTypes[0];
        }
        else
        {
            throw CreateDirectRouteAmbiguousControllerException(controllerTypes);
        }
    }
person Ryan O'Neill    schedule 15.08.2016