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
的请求网址将返回ContentFromCms("Suppliers/Acme");
(将url作为参数发送会更好但不需要,并且无参数方法我从请求中得到它会很好。
目前我可以想到两种可能的方法来实现这一目标:
创建一个新的约束,它反映在一个控制器上,看它是否有一个给定名称的动作,并在{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);
答案 0 :(得分:2)
你接近很好。作为旁注:
替换
controllerDescriptor.ControllerType.GetInterface("Kingsweb.Controllers.IWikiController") != null
带
typeof(Kingsweb.Controllers.IWikiController).IsAssignableFrom(controllerDescriptor.ControllerType)
这是更强类型的方式,然后通过字符串传递接口的名称:如果明天更改命名空间怎么办?...