Asp.net mvc 2 如何在ASP.NET MVC中实现动态控制器和动作方法?

Asp.net mvc 2 如何在ASP.NET MVC中实现动态控制器和动作方法?,asp.net-mvc-2,asp.net-mvc-routing,asp.net-mvc-controller,Asp.net Mvc 2,Asp.net Mvc Routing,Asp.net Mvc Controller,在Asp.net MVC中,url结构如下所示 {controller}/{action}/{id} 例如,对于每个“控制器”,都有一个BlogController 但是我的url的{controller}部分不是预先确定的,而是在运行时动态确定的。如何创建一个“动态控制器”,将任何内容映射到同一个控制器,然后该控制器基于该值确定要做什么 与{action}相同,如果我的url的{action}部分也是动态的,有没有办法对这个场景进行编程 您需要编写自己的IControllerFactory(或

在Asp.net MVC中,url结构如下所示

{controller}/{action}/{id}

例如,对于每个“控制器”,都有一个BlogController

但是我的url的{controller}部分不是预先确定的,而是在运行时动态确定的。如何创建一个“动态控制器”,将任何内容映射到同一个控制器,然后该控制器基于该值确定要做什么


与{action}相同,如果我的url的{action}部分也是动态的,有没有办法对这个场景进行编程

您需要编写自己的
IControllerFactory
(或者从
DefaultControllerFactory
)然后向
ControllerBuilder
注册它!如果自定义控制器不存在,则需要重写
DefaultControllerFactory
,以查找自定义控制器。然后需要编写一个
iactionvoker
来处理动态动作名称

控制器工厂的外观如下所示:

公共类DynamicControllerFactory:DefaultControllerFactory
{
专用只读阅读器Vicelocator定位器;
公共动态控制器工厂(IServiceLocator定位器)
{
_定位器=定位器;
}
受保护的覆盖类型GetControllerType(字符串controllerName)
{
var controllerType=base.GetControllerType(controllerName);
//如果找不到具有匹配名称的控制器,请返回我们的动态控制器
返回控制器类型??类型(DynamicController);
}
受保护的覆盖IController GetControllerInstance(类型controllerType)
{
var controller=base.GetControllerInstance(controllerType)作为控制器;
var actionInvoker=_Locator.GetInstance();
if(actionInvoker!=null)
{
controller.ActionInvoker=ActionInvoker;
}
返回控制器;
}
}
然后,您的操作调用程序将如下所示:

公共类DynamicActionInvoker:ControllerActionInvoker
{
专用只读阅读器Vicelocator定位器;
公共动态记录器(IServiceLocator定位器)
{
_定位器=定位器;
}
受保护的覆盖操作描述符查找操作(ControllerContext ControllerContext,
ControllerDescriptor ControllerDescriptor,字符串actionName)
{
//首先尝试匹配现有操作名称
var action=base.FindAction(controllerContext、controllerDescriptor、actionName);
如果(操作!=null)
{
返回动作;
}
//@ray247这剩下的你可能会自己写。。。
var actionFinders=_Locator.GetAllInstances();
如果(actionFinders==null)
{
返回null;
}
返回操作查找程序
.Select(f=>f.FindAction(controllerContext、controllerDescriptor、actionName))
.其中(d=>d!=null)
.FirstOrDefault();
}
}
您可以看到更多这段代码。这是我和同事在编写完全动态的MVC管道方面的一次旧的初稿尝试。你可以自由使用它作为参考,并复制你想要的

编辑


我想我应该包括一些关于代码的背景知识。我们试图围绕域模型动态构建MVC层。因此,如果您的域包含产品类,您可以导航到
products\all
以查看所有产品的列表。如果要添加产品,请导航到
product\add
。您可以转到
product\edit\1
编辑产品。我们甚至尝试过允许您编辑实体上的属性。因此
product\editprice\1?value=42
会将product#1的price属性设置为42。(我的路径可能有点偏离,我再也记不起确切的语法了。)希望这有帮助

再仔细思考一下,与我的另一个答案相比,您可能有一种更简单的方法来处理动态动作名称。您仍然需要覆盖默认的控制器工厂。我想你可以这样定义你的路线:

routes.MapRoute("Dynamic", "{controller}/{command}/{id}", new { action = "ProcessCommand" });
然后在您的默认/动态控制器上

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

我在.Core中使用它,但我将分享它的MVC版本,之后我将分享核心版本

                case OwnerType.DynamicPage:
                    var dp = mediator.Handle(new Domain.DynamicPages.DynamicPageDtoQuery { ShopId = ShopId, SeoId = seoSearchDto.Id }.AsSingle());
                    if (dp != null)
                    {
                        return GetDynamicPage(dp.Id);
                    }
                    break;
//一些代码

    private ActionResult GetDynamicPage(int id)
    {
        var routeObj = new
        {
            action = "Detail",
            controller = "DynamicPage",
            id = id
        };

        var bController = DependencyResolver.Current.GetService<DynamicPageController>();
        SetControllerContext(bController, routeObj);
        return bController.Detail(id);
    }
private ActionResult GetDynamicPage(int-id)
{
var routeObj=new
{
action=“Detail”,
controller=“DynamicPage”,
id=id
};
var bController=DependencyResolver.Current.GetService();
SetControllerContext(B控制器,路由BJ);
返回b控制器详细信息(id);
}
//及

private void SetControllerContext(ControllerBase controller, object routeObj)
{
    RouteValueDictionary routeValues = new RouteValueDictionary(routeObj);

    var vpd = RouteTable.Routes["Default"].GetVirtualPath(this.ControllerContext.RequestContext, routeValues);



    RouteData routeData = new RouteData();

    foreach (KeyValuePair<string, object> kvp in routeValues)
    {
        routeData.Values.Add(kvp.Key, kvp.Value);
    }

    foreach (KeyValuePair<string, object> kvp in vpd.DataTokens)
    {
        routeData.DataTokens.Add(kvp.Key, kvp.Value);
    }


    routeData.Route = vpd.Route;
    if (routeData.RouteHandler == null)
        routeData.RouteHandler = new MvcRouteHandler();


    controller.ControllerContext = new ControllerContext(this.ControllerContext.HttpContext, routeData, controller);
}
private void SetControllerContext(ControllerBase-controller,object-routeObj)
{
RouteValueDictionary routeValues=新的RouteValueDictionary(routeObj);
var vpd=RouteTable.Routes[“Default”].GetVirtualPath(this.ControllerContext.RequestContext,RouteValue);
RoutedData RoutedData=新RoutedData();
foreach(路由值中的KeyValuePair kvp)
{
RoutedData.Values.Add(kvp.Key,kvp.Value);
}
foreach(vpd.DataTokens中的KeyValuePair kvp)
{
routeData.DataTokens.Add(kvp.Key,kvp.Value);
}
RoutedData.Route=vpd.Route;
if(routeData.RouteHandler==null)
routeData.RouteHandler=新的MvcRouteHandler();
controller.ControllerContext=新的ControllerContext(this.ControllerContext.HttpContext,routeData,controller);
}

Hello@Ryan。我已尝试从实现您的DynamicControllerFactory和DynamicActionInvoker。在运行时,我被要求提供DynamicControllerFactory的默认构造函数。然后,我添加了一个空实现。但从未调用参数化构造函数,也从未设置_locater值。因此,在调用GetControllerInstance期间,由于null定位器,未设置actionInvoker。h在哪里