通过实现IViewLocationExpander接口可自定义Razor视图查找路径,如根据theme参数动态调整。PopulateValues提取上下文值用于缓存键,ExpandViewLocations插入新视图路径。注册后支持多主题、多语言或模块化结构,提升视图加载灵活性。

在 ASP.NET Core 中,视图位置扩展器(View Location Expanders)允许你自定义 Razor 视图的查找路径。默认情况下,MVC 会按照约定在 Views/[Controller]/[Action].cshtml 或 Pages/[Page].cshtml 等位置查找视图。但通过实现 IViewLocationExpander 接口,你可以动态修改这些查找规则,比如支持多语言、主题切换或模块化结构。
实现 IViewLocationExpander 接口
要创建自定义视图位置扩展器,需实现 IViewLocationExpander 接口中的两个方法:ExpandViewLocations 和 PopulateValues。
下面是一个示例:根据路由参数或查询字符串中的“theme”值来改变视图查找路径:
public class ThemeViewLocationExpander : IViewLocationExpander
{
// 将上下文中的信息提取为键值对,用于缓存键生成
public void PopulateValues(ViewLocationExpanderContext context)
{
var theme = context.ActionContext.HttpContext.Request.Query["theme"].ToString();
if (string.IsNullOrEmpty(theme))
{
theme = context.ActionContext.RouteData.Values["theme"]?.ToString();
}
context.Values["theme"] = theme ?? "default";
}
// 自定义视图查找路径
public IEnumerable ExpandViewLocations(
ViewLocationExpanderContext context,
IEnumerable viewLocations)
{
if (context.Values.TryGetValue("theme", out var theme) && !string.IsNullOrEmpty(theme))
{
// 在原有路径前插入主题专属路径
var themeLocation = $"/Themes/{theme}/Views/{{1}}/{{0}}.cshtml";
var layoutLocation = $"/Themes/{theme}/Views/Shared/{{0}}.cshtml";
return new[] { themeLocation, layoutLocation }.Concat(viewLocations);
}
return viewLocations;
}
}
注册视图位置扩展器
实现完成后,需要将其注册到 MVC 的配置中。可以在 Program.cs 或 Startup.cs 中进行注册:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews(options =>
{
options.ViewLocationExpanders.Add(new ThemeViewLocationExpander());
});
或者使用工厂模式注册,以便支持依赖注入:
builder.Services.Configure(options => { options.ViewLocationExpanders.Add(new ThemeViewLocationExpander()); });
实际效果示例
假设请求地址为:/Home/Index?theme=dark,则 MVC 会优先查找以下路径:
/Themes/dark/Views/Home/Index.cshtml/Themes/dark/Views/Shared/_Layout.cshtml- 再回退到默认路径如
/Views/Home/Index.cshtml
这样就可以实现无需复制代码即可切换界面主题。
基本上就这些。只要理解 PopulateValues 用于决定缓存键,ExpandViewLocations 用于提供额外路径,就能灵活控制视图加载逻辑。常见用途包括多站点共享视图、A/B 测试、插件式架构等场景。










