asp.net – ASP MVC中的后备路由,如果操作不存在

MVC {controller} / {action} / {id}中的默认路由在很大程度上非常有用,因为如果传入的URL不包含参数但是还有一种方法可以设置默认值控制器上不存在操作时的默认操作?

我想要实现的是能够让控制器具有几个特定的​​操作,然后是它自己的catchall,它使用url从基本CMS获取内容.

例如,产品控制器将类似于:

public class ProductsController: Controller{
    public ActionResult ProductInfo(int id){...}
    public ActionResult AddProduct(){...}
    public ActionResult ContentFromCms(string url){...} 
}

如果默认路由将处理/ Products / ProductInfo / 54等,但/ Products / Suppliers / Acme的请求URL将返回ContentFromCms(“Suppliers / Acme”); (将url作为参数发送会更好但不需要,并且我从Request获取它的无参数方法会很好).

目前,我可以想到两种可能的方法来实现这一目标:

创建一个新的约束,它反映在一个控制器上,看它是否确实有一个给定名称的动作,并在{controller} / {action} / {id}路由中使用它,这样我就可以拥有一个像{controller}这样的更通用的捕获} / {* URL}.

覆盖控制器上的HandleUnknownAction.

第一种方法似乎是一种相当迂回的检查方式,而对于第二种方法,我不知道MVC和路由的内部是否足以知道如何继续.

更新

没有任何回复,但我想我会留下我的解决方案,以防任何人在将来发现这一点,或者让人们建议改进/更好的方式

对于想要拥有自己的捕获器的控制器,我给了他们一个接口

interface IHasDefaultController
{
    public string DefaultRouteName { get; }
    System.Web.Mvc.ActionResult DefaultAction();
}

然后我从ControllerActionInvoker派生并覆盖了FindAction.这将调用基础FindAction,如果基数返回null并且控制器触发我使用默认actionname再次调用FindAction的接口.

protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
    {
        ActionDescriptor foundAction = base.FindAction(controllerContext, controllerDescriptor, actionName);
        if (foundAction == null && controllerDescriptor.ControllerType.GetInterface("Kingsweb.Controllers.IWikiController") != null)
        {
            foundAction = base.FindAction(controllerContext, controllerDescriptor, "WikiPage");
        }
        return foundAction;
    }

由于我也想要路由参数,我还在控制器上默认的Actionresult开头替换RouteData

ControllerContext.RouteData = Url.RouteCollection[DefaultRouteName].GetRouteData(HttpContext);

最佳答案 你接近很好.作为旁注:

更换

controllerDescriptor.ControllerType.GetInterface("Kingsweb.Controllers.IWikiController") != null

typeof(Kingsweb.Controllers.IWikiController).IsAssignableFrom(controllerDescriptor.ControllerType)

这是更强类型的方式,然后通过字符串传递接口的名称:如果你明天更改命名空间怎么办?

点赞