You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何重写RazorViewEngine使其递归查找EditorTemplate?

扩展RazorViewEngine实现EditorTemplates递归查找

这个需求其实挺常见的——默认的RazorViewEngine只会在Shared/EditorTemplates根目录下查找模板,不会遍历子文件夹。不过我们可以通过自定义ViewEngine子类,重写视图查找逻辑来实现递归查找的功能,具体步骤如下:

1. 创建自定义RazorViewEngine子类

我们需要重写FindPartialView方法(因为EditorTemplate本质上是PartialView的一种),在方法里递归遍历Shared/EditorTemplates的所有子文件夹,生成所有可能的模板路径并逐一检查:

using System.Collections.Generic;
using System.IO;
using System.Web.Mvc;

public class RecursiveEditorTemplateRazorViewEngine : RazorViewEngine
{
    protected override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
    {
        // 判断当前是否在查找EditorTemplate(MVC内部会给模板名加上EditorTemplates/前缀)
        if (partialViewName.StartsWith("EditorTemplates/"))
        {
            var templateName = partialViewName.Substring("EditorTemplates/".Length);
            var editorTemplatesRoot = controllerContext.HttpContext.Server.MapPath("~/Views/Shared/EditorTemplates");
            
            // 递归获取EditorTemplates下的所有子文件夹
            var subFolders = GetAllSubFolders(editorTemplatesRoot);
            
            // 构建所有可能的模板查找路径
            var viewLocations = new List<string>();
            // 先添加默认的根目录路径(保持原有优先级)
            viewLocations.Add($"~/Views/Shared/EditorTemplates/{templateName}.cshtml");
            viewLocations.Add($"~/Views/Shared/EditorTemplates/{templateName}.vbhtml");
            
            // 添加所有子文件夹的路径
            foreach (var folder in subFolders)
            {
                // 转换为MVC识别的虚拟路径格式
                var relativePath = folder.Substring(editorTemplatesRoot.Length).Replace("\\", "/");
                viewLocations.Add($"~/Views/Shared/EditorTemplates{relativePath}/{templateName}.cshtml");
                viewLocations.Add($"~/Views/Shared/EditorTemplates{relativePath}/{templateName}.vbhtml");
            }
            
            // 遍历路径,查找存在的模板
            foreach (var location in viewLocations)
            {
                if (FileExists(controllerContext, location))
                {
                    var view = CreatePartialView(controllerContext, location);
                    return new ViewEngineResult(view, this);
                }
            }
            
            // 如果所有路径都找不到,返回包含所有查找路径的结果(和基类行为一致)
            return new ViewEngineResult(viewLocations);
        }
        
        // 非EditorTemplate的查找请求,交给基类处理
        return base.FindPartialView(controllerContext, partialViewName, useCache);
    }
    
    // 递归遍历获取所有子文件夹的私有方法
    private List<string> GetAllSubFolders(string rootPath)
    {
        var folders = new List<string>();
        try
        {
            foreach (var folder in Directory.GetDirectories(rootPath))
            {
                folders.Add(folder);
                // 递归遍历子文件夹的子文件夹
                folders.AddRange(GetAllSubFolders(folder));
            }
        }
        catch (DirectoryNotFoundException)
        {
            // 如果EditorTemplates目录不存在,直接返回空列表,避免抛出异常
        }
        return folders;
    }
}

2. 注册自定义ViewEngine

在Global.asax.cs的Application_Start方法中,移除默认的RazorViewEngine,替换为我们自定义的实现:

protected void Application_Start()
{
    // 移除默认的RazorViewEngine
    var defaultRazorEngine = ViewEngines.Engines.OfType<RazorViewEngine>().FirstOrDefault();
    if (defaultRazorEngine != null)
    {
        ViewEngines.Engines.Remove(defaultRazorEngine);
    }
    
    // 添加自定义的递归查找ViewEngine
    ViewEngines.Engines.Add(new RecursiveEditorTemplateRazorViewEngine());
    
    // 其他初始化代码...
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);
}

关键逻辑说明

  • 优先级保持:我们依然优先查找Shared/EditorTemplates根目录下的模板,只有根目录找不到时才会去子文件夹查找,符合MVC原有的模板覆盖逻辑。
  • 动态路径生成:通过递归遍历物理目录,动态生成所有子文件夹的虚拟路径,不需要硬编码任何子文件夹名称。
  • 异常处理:捕获DirectoryNotFoundException,避免因Shared/EditorTemplates目录不存在导致的程序崩溃。
  • 兼容原有逻辑:非EditorTemplate的视图/部分视图查找请求,依然交给基类处理,不会影响项目中其他视图的正常工作。

内容的提问来源于stack exchange,提问作者Junior

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:14:54