MVC 5子控制器加载父控制器视图问题及更优方案咨询
解决MVC 5子控制器继承基控制器时视图查找范围受限的问题
我之前也碰到过一模一样的情况——子控制器继承基控制器后,调用视图只会死磕自己的视图目录,完全忽略基控制器的视图文件夹,确实挺闹心的。你提到的修改父控制器Action的方法(比如硬编码视图路径)虽然能解决,但确实不够优雅,这里给你两个更优的方案:
方案一:自定义全局视图引擎(推荐全局复用场景)
这个方法能让所有继承基控制器的子控制器自动优先查找基控制器的视图目录,不用在每个Action里重复写路径。
- 新建一个继承自
RazorViewEngine的自定义视图引擎类:
public class BaseControllerViewEngine : RazorViewEngine { public BaseControllerViewEngine() { // 把基控制器的视图目录添加到默认查找路径的最前面 var baseViewLocations = new[] { "~/Views/Base/{0}.cshtml", "~/Views/Base/{0}.vbhtml" }; // 合并原有路径,确保默认的子控制器视图路径依然生效 ViewLocationFormats = baseViewLocations.Concat(ViewLocationFormats).ToArray(); PartialViewLocationFormats = baseViewLocations.Concat(PartialViewLocationFormats).ToArray(); } }
如果你的项目里有多个基控制器,还可以重写FindView方法,动态获取当前控制器的父类名称来拼接路径,灵活性拉满:
protected override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) { var controllerType = controllerContext.Controller.GetType(); // 提取基控制器的名称(自动去掉末尾的Controller后缀) var baseControllerName = controllerType.BaseType.Name.Replace("Controller", ""); var baseViewPath = $"~/Views/{baseControllerName}/{viewName}.cshtml"; // 先检查基控制器视图目录是否存在目标视图 if (FileExists(controllerContext, baseViewPath)) { return new ViewEngineResult(CreateView(controllerContext, baseViewPath, masterName), this); } // 找不到再走默认的视图查找逻辑 return base.FindView(controllerContext, viewName, masterName, useCache); }
- 在
Global.asax的Application_Start方法里注册这个视图引擎:
protected void Application_Start() { // 清除默认视图引擎,替换成自定义的 ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new BaseControllerViewEngine()); // 其他项目初始化代码... }
方案二:在子控制器中重写View方法(适合局部场景)
如果只是个别子控制器需要这个功能,不想全局修改,可以在目标子控制器里重写View方法,让它先检查基控制器的视图目录:
public class ChildController : BaseController { protected override ViewResult View(string viewName, string masterName, object model) { // 拼接基控制器的视图路径 var baseControllerName = typeof(BaseController).Name.Replace("Controller", ""); var baseViewPath = $"~/Views/{baseControllerName}/{viewName}.cshtml"; // 检查服务器上是否存在该视图文件 if (System.IO.File.Exists(Server.MapPath(baseViewPath))) { return base.View(baseViewPath, masterName, model); } // 不存在则使用默认的视图查找逻辑 return base.View(viewName, masterName, model); } }
这两个方案都比硬编码路径灵活得多:全局视图引擎适合整个项目的基控制器视图复用,重写View方法则针对单个子控制器,你可以根据自己的项目场景自由选择。
内容的提问来源于stack exchange,提问作者DespeiL
相关产品推荐
相关产品推荐

