Динамически регистрировать маршруты для действий MVC - PullRequest
0 голосов
/ 12 октября 2018

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

Но я продолжаю попадать в такие ситуации:

 public PartialViewResult GetAssetHistory(string assetCode, string mode)

 public PartialViewResult GetAssetData(string assetCode)

 public PartialViewResult GetAssetData2(string assetCode, string mode, int assetParam)

Я не хочу жестко кодировать маршрут

Asset/{action}/{assetCode}/{mode}/{assetParam}

Было бы намного лучше, если бы я мог просто иметь все маршруты или все контроллеры с атрибутом, настроенным для динамического создания маршрутов, так что первыйзначение маршрута отображается на первый параметр (например, assetCode), а значение второго маршрута отображается на второй параметр действия (например, mode) и т. д.

Я понимаю, что это, вероятно, потребует отражения, но есть ликакая-либо причина, почему это может быть очень плохо, или не должно быть сделано, или не может быть сделано?

Бонусные баллы за пример этого в RouteConfig.cs

Ответы [ 2 ]

0 голосов
/ 12 октября 2018

Вы можете сделать это путем реализации IRouteHandler .

  1. Создание пользовательского IRouteHandler
  2. Пользовательский IRouteHandler определит контроллер, действие, параметры и т. Д.
  3. Затем пользовательский IRouteHandler просто передаст запросштатный мвчэндлер.
  4. Теперь MvcHandler знает, какой контроллер и действие обработают запрос.

Пользовательский IRouteHandler будет просто выглядеть так:

public sealed class UrlRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        var routeData = requestContext.RouteData.Values;
        var url = routeData["urlRouteHandler"] as string;

        // The class UrlHandler will have all the code for figuring things out
        var route = UrlHandler.GetRoute(url);

        routeData["url"] = route.Url;
        routeData["controller"] = route.Controller;
        routeData["action"] = route.Action;
        // other stuff to add

        // Now let MvcHandler process the request.
        return new MvcHandler(requestContext);
    }
}

Зарегистрируйте обработчик вRouteConfig.cs:

routes.MapRoute(
            "IUrlRouteHandler",
            "{*urlRouteHandler}").RouteHandler = new UrlRouteHandler();

Большая часть тяжелой работы была проделана здесь этим хорошим парнем.Вы можете просто следовать этому.Единственное различие между тем, что вы хотите сделать, и тем, что было сделано в этой статье, заключается в следующем: вы хотите выяснить вещи из URL по соглашению, он вычисляет вещи, используя URL, хранящиеся в базе данных.

Полный текстИсходный код статьи находится на GitHub .

0 голосов
/ 12 октября 2018

Обновление

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

  • Использование настраиваемого атрибута для определения действий, которые следует использовать для создания динамического маршрута

[AttributeUsage(AttributeTargets.Method)]
public class DynamicUrlAttribute : Attribute
{
}

  • Украсьте свои действия с помощью пользовательского атрибута

public class SampleController : Controller
{
    [DynamicUrl]
    public ActionResult Index(int param2)
    {
        return View(param2);
    }

    [DynamicUrl]
    public ActionResult MultipleParams(int param1, int param2)
    {
        return View(new { param1, param2 });
    }
}

  • Создание маршрутов с помощьюof отражения

public static class Extensions
{
    /// <summary>
    /// Detect all the actions whose route should be generated dynamically
    /// </summary>
    /// <returns>List of actions</returns>
    private static IEnumerable<MethodInfo> GetTypesWithHelpAttribute()
    {
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            foreach (Type type in assembly.GetTypes())
            {
                foreach (var method in type.GetMethods())
                {
                    if (method.GetCustomAttributes(typeof(DynamicUrlAttribute), 
                                            true).Length > 0)
                    {
                        yield return method;
                    }
                }
            }
        }
    }

    /// <summary>
    /// Get the list of routes to add to the Route Table
    /// </summary>
    /// <returns>List of routes</returns>
    public static List<Route> GetRoutes()
    {
        List<Route> routes = new List<Route>();

        foreach (var action in GetTypesWithHelpAttribute())
        {
            string controllerName = action.DeclaringType.Name.Replace("Controller","");
            string actionName = action.Name;
            List<string> parameters = new List<string>();
            int index = 0;
            foreach (var parameterInfo in action.GetParameters())
            {
                parameters.Add(GetParamName(action, index++));
            }
            string parameterSection = action.GetParameters().Length > 0 ?
                    parameters.Aggregate("", (a, b) => $"{a}/{{{b}}}") 
                    : "";
            string finalRoute = $"dynamic/{controllerName}/{actionName}{parameterSection}";
            routes.Add(new Route(
                url: finalRoute,
                defaults: new RouteValueDictionary( 
                    new { 
                        controller = controllerName, 
                        action = actionName }),
                routeHandler: new MvcRouteHandler()
            ));
        }
        return routes;
    }

    /// <summary>
    /// Return the name of the parameter by using reflection
    /// </summary>
    /// <param name="method">Method information</param>
    /// <param name="index">Parameter index</param>
    /// <returns>Parameter name</returns>
    public static string GetParamName(System.Reflection.MethodInfo method, int index)
    {
        string retVal = string.Empty;

        if (method != null && method.GetParameters().Length > index)
            retVal = method.GetParameters()[index].Name;

        return retVal;
    }
}

  • Добавить обнаруженные маршруты в коллекцию маршрутов

    public static void RegisterRoutes(RouteCollection routes)
    {
        foreach (var route in Extensions.GetRoutes())
        {
            routes.Add(route);
        }
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

Для этого кода выбудет иметь следующие два действительных URL-маршрута

  1. / dynamic / Sample / Index / 2
  2. / dynamic / Sample / MultipleParams / 1/2

Оригинал (недействительно)

Представьте себе обратное.Допустим, у нас есть представление с этим содержимым

@Url.Action("Action","Controller", 
    new { 
        assetCode = "code", 
        mode = "mode", 
        assetParam = "assetParam", 
        someOtherProperty = "someOtherProperty" 
    })

Теперь, какой URL вы хотите создать?

  • / Контроллер / Действие / Код
  • / Контроллер / Действие / Код / Режим
  • / Контроллер / Действие / Код / Режим / assetParam
  • / Контроллер / Действие / Код / Mode / assetParam / someOtherProperty (еще хуже, потому что одиндаже не существует)
  • / Controller / Action / someOtherProperty / code / assetParam / mode (что еще хуже, это может быть возможный URL, так как нет никакой информации о порядке, в котором URL долженбыть сгенерированным)

Когда вы определяете 3 маршрута, для инфраструктуры ясно, какой URL должен быть создан.Если бы это было как-то динамично, для фреймворка будет невозможно правильно сгенерировать действительный соответствующий URL.То есть, если вы не начнете заполнять свои контроллеры и действия настраиваемыми атрибутами, и перед тем, как начать это делать, имеет смысл фактически использовать RouteAttribute и / или определять фактические маршруты в таблице маршрутов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...