具体来说,控制器类名称是否必须具有Controller
后缀,如果您愿意,您可以更改项目中的文件夹结构,而不会破坏任何东西吗?
是否有其他可以覆盖的约定,以及如何覆盖?
具体来说,控制器类名称是否必须具有Controller
后缀,如果您愿意,您可以更改项目中的文件夹结构,而不会破坏任何东西吗?
是否有其他可以覆盖的约定,以及如何覆盖?
只要您了解框架的运作方式,大多数约定都是可延展的。让我们解决两个最大的约定:
用于从路由实例化控制器的“{controller}/{action}/”魔术关键字
框架首先在控制器目录中搜索视图的方式,然后在共享目录中。
MvcRouteHandler
默认情况下,您创建的每个路由都与一个对象的实例相关联。当路由匹配时,调用该处理程序来处理传入请求。下面是 MvcHandler 的 ProcessRequest 的样子:
protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
this.AddVersionHeader(httpContext);
string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
IControllerFactory controllerFactory = this.ControllerBuilder.GetControllerFactory();
IController controller = controllerFactory.CreateController(this.RequestContext, requiredString);
if (controller == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[] { controllerFactory.GetType(), requiredString }));
}
try
{
controller.Execute(this.RequestContext);
}
finally
{
controllerFactory.ReleaseController(controller);
}
}
注意硬编码的字符串“controller”。好吧,如果您想编写自己的控制器查找逻辑,您可以将这个处理程序替换为您想要的任何路由。只需做这样的事情(无耻的博客插件):
routes.Add("ImagesRoute",
new Route("graphics/{filename}", new ImageRouteHandler()));
现在当路由匹配时,它会调用你自己的逻辑,你可以为所欲为。顺便说一句,用于查找带有“Controller”后缀的 XXXXController 类的反射是DefaultControllerFactory
对象的一部分,在上面的处理程序中调用,并且该工厂是可替换的。
因此,控制器选择是一种可以覆盖的约定。当您return View()
从任何控制器方法执行“”时,它会如何查找视图?那么这是WebFormViewEngine
框架的默认视图引擎的构造函数:
public WebFormViewEngine()
{
base.MasterLocationFormats = new string[] { "~/Views/{1}/{0}.master", "~/Views/Shared/{0}.master" };
base.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.aspx", "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.aspx", "~/Views/Shared/{0}.ascx" };
base.PartialViewLocationFormats = base.ViewLocationFormats;
}
因此,如果您不喜欢查看控制器目录然后共享的约定 - 您可以轻松扩展WebFormViewEngine
(或使用完全不同的视图引擎)并将其放入 global.asax 中:
ViewEngines.Engines.Add(new MyViewEngine());
MVC 框架令人惊奇的事情之一是它的真正灵活性。你可以用你自己的逻辑替换它的几乎任何部分——所有代码都可以用来查看他们做了什么。