Подтвердить что ты не робот

Как добиться динамического контроллера и метода действий в ASP.NET MVC?

В Asp.net MVC структура URL-адреса похожа на

http://example.com/ {controller}/{action}/{id}

Для каждого "контроллера", скажем http://example.com/blog, есть BlogController.

Но часть {controller} URL-адреса не определяется заранее, но она динамически определяется во время выполнения, как мне создать "динамический контроллер", который отображает что-либо на тот же контроллер, который затем основывается на значении и определяет, что делать?

То же самое с {action}, если часть {action} моего url также динамична, есть ли способ запрограммировать этот сценарий?

4b9b3361

Ответ 1

Абсолютно! Вам нужно переопределить DefaultControllerFactory, чтобы найти настраиваемый контроллер, если он не существует. Затем вам нужно написать IActionInvoker для обработки имен динамических действий.

Ваш контроллер factory будет выглядеть примерно так:

public class DynamicControllerFactory : DefaultControllerFactory
{
    private readonly IServiceLocator _Locator;

    public DynamicControllerFactory(IServiceLocator locator)
    {
        _Locator = locator;
    }

    protected override Type GetControllerType(string controllerName)
    {
        var controllerType = base.GetControllerType(controllerName);
            // if a controller wasn't found with a matching name, return our dynamic controller
        return controllerType ?? typeof (DynamicController);
    }

    protected override IController GetControllerInstance(Type controllerType)
    {
        var controller = base.GetControllerInstance(controllerType) as Controller;

        var actionInvoker = _Locator.GetInstance<IActionInvoker>();
        if (actionInvoker != null)
        {
            controller.ActionInvoker = actionInvoker;
        }

        return controller;
    }
}

Тогда ваш action invoker будет выглядеть следующим образом:

public class DynamicActionInvoker : ControllerActionInvoker
{
    private readonly IServiceLocator _Locator;

    public DynamicActionInvoker(IServiceLocator locator)
    {
        _Locator = locator;
    }

    protected override ActionDescriptor FindAction(ControllerContext controllerContext,
                                                   ControllerDescriptor controllerDescriptor, string actionName)
    {
            // try to match an existing action name first
        var action = base.FindAction(controllerContext, controllerDescriptor, actionName);
        if (action != null)
        {
            return action;
        }

// @ray247 The remainder of this you'd probably write on your own...
        var actionFinders = _Locator.GetAllInstances<IFindAction>();
        if (actionFinders == null)
        {
            return null;
        }

        return actionFinders
            .Select(f => f.FindAction(controllerContext, controllerDescriptor, actionName))
            .Where(d => d != null)
            .FirstOrDefault();
    }
}

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

Edit

Я подумал, что я должен добавить некоторые сведения о том, что делает этот код. Мы пытались динамически строить слой MVC вокруг модели домена. Поэтому, если ваш домен содержит класс Product, вы можете перейти к products\alls, чтобы просмотреть список всех продуктов. Если вы хотите добавить продукт, перейдите к product\add. Вы можете перейти к product\edit\1 для редактирования продукта. Мы даже пробовали такие вещи, как позволить вам редактировать свойства объекта. Таким образом, product\editprice\1?value=42 установит свойство цены продукта с №1 до 42. (Мои пути могут быть немного неактивными, я больше не могу вспомнить точный синтаксис.) Надеюсь, что это поможет!

Ответ 2

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

routes.MapRoute("Dynamic", "{controller}/{command}/{id}", new { action = "ProcessCommand" });

Затем на вашем стандартном/динамическом контроллере у вас будет

public ActionResult ProcessCommand(string command, int id)
{
   switch(command)
   {
      // whatever.
   }
}

Ответ 3

Вам нужно написать свой собственный IControllerFactory (или, возможно, получить из DefaultControllerFactory), а затем зарегистрировать его с помощью ControllerBuilder.