在 ASP.NET Core Razor 页面中更改 cshtml 文件的名称
Posted
技术标签:
【中文标题】在 ASP.NET Core Razor 页面中更改 cshtml 文件的名称【英文标题】:Change name of cshtml file in ASP.NET Core RazorPages 【发布时间】:2021-05-19 12:58:10 【问题描述】:我的环境:带有 RazorPages 的 ASP.NET Core 5、Webpack 5。
在引用 svg 文件的剃须刀页面 (.cshtml
) 中,我想内联它们。这是 Webpack 可以做的事情(通过插件),但我不确定如何集成这两个技术栈。
我可以编写模板化的 cshtml 文件,并通过 webpack 填充它们:
ContactUs.cshtml.cs
ContactUs.cshtml <------ read by webpack
ContactUs.generated.cshtml <------ generated by webpack
但是在构建时如何强制 msbuild / aspnet 使用生成的文件 (ContactUs.generated.cshtml
) 而不是模板文件 (ContactUs.cshtml
)?
我怀疑答案是使用IPageRouteModelConvention
,但我不确定如何使用。
(一个肮脏的解决方法是改用文件名ContactUs.template.cshtml
和ContactUs.cshtml
,但我更喜欢上面的东西,因为“生成”更清晰。)
更新
为了简化问题:
编译器会查找Foo.cshtml.cs
和Foo.cshtml
。
我如何告诉它寻找 Foo.cshtml.cs
和 Foo.generated.cshtml
?
【问题讨论】:
问题不在于编译器或 Razor Pages 所期望的名称。它是由您用来生成额外文件的任何内容生成的名称。 那是需要改变的。你是如何生成这些文件的?带有cshtml
扩展名的文件是页面本身,而不仅仅是页面的一部分。生成的文件包含什么?您能否将它们转换为部分页面并将它们包含在实际页面中?
@PanagiotisKanavos 同意 - 你指的是我上面提到的解决方法,它有效。但我更喜欢使用IPageRouteModelConvention
以某种方式更改约定,我只是不知道如何。从旧的 T4 时代开始,一个名为“foo.generated.bar”的文件总是被认为是在源代码控制之外生成的——所以我想在这里复制这个范例。我敢肯定这是有可能的。
【参考方案1】:
加载应用程序时,框架会为您加载一组PageRouteModel
s,这是从剃刀页面文件夹自动生成的(按照惯例)。每个这样的模型都包含一组SelectorModel
,每个模型都有一个AttributeRouteModel
。您需要做的只是修改 AttributeRouteModel.Template
,从自动生成的值中删除后缀部分。
您可以创建一个自定义IPageRouteModelConvention
来定位每个PageRouteModel
。但是,这样您无法确保路由不被复制(因为修改AttributeRouteModel.Template
后,它可能会与其他一些现有路由重复)。除非您必须管理一组共享的路线模板。相反,您可以创建自定义 IPageRouteModelProvider
。它在一个地方提供所有PageRouteModel
s,以便您可以修改和添加或删除任何。这种方式非常方便,您可以支持 2 个剃须刀页面,其中一个页面的优先级高于另一个页面(例如:您有 Index.cshtml
和 Index.generated.cshtml
并且您希望它选择 Index.generated.cshtml
。如果生成的视图不是存在,将使用默认的Index.cshtml
)。
所以这里是详细代码:
public class SuffixedNamePageRouteModelProvider : IPageRouteModelProvider
public SuffixedNamePageRouteModelProvider(string pageNameSuffix, int order = 0)
_pageNameSuffixPattern = string.IsNullOrEmpty(pageNameSuffix) ? "" : $"\\.Regex.Escape(pageNameSuffix)$";
Order = order;
readonly string _pageNameSuffixPattern;
public int Order get;
public void OnProvidersExecuted(PageRouteModelProviderContext context)
public void OnProvidersExecuting(PageRouteModelProviderContext context)
if(_pageNameSuffixPattern == "") return;
var suffixedRoutes = context.RouteModels.Where(e => Regex.IsMatch(e.ViewEnginePath, _pageNameSuffixPattern)).ToList();
var overriddenRoutes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var route in suffixedRoutes)
//NOTE: this is not required to help it pick the right page we want.
//But it's necessary for other related code to work properly (e.g: link generation, ...)
//we need to update the "page" route data as well
route.RouteValues["page"] = Regex.Replace(route.RouteValues["page"], _pageNameSuffixPattern, "");
var overriddenRoute = Regex.Replace(route.ViewEnginePath, _pageNameSuffixPattern, "");
var isIndexRoute = overriddenRoute.EndsWith("/index", StringComparison.OrdinalIgnoreCase);
foreach (var selector in route.Selectors.Where(e => e.AttributeRouteModel?.Template != null))
var template = Regex.Replace(selector.AttributeRouteModel.Template, _pageNameSuffixPattern, "");
if (template != selector.AttributeRouteModel.Template)
selector.AttributeRouteModel.Template = template;
overriddenRoutes.Add($"/template.TrimStart('/')");
selector.AttributeRouteModel.SuppressLinkGeneration = isIndexRoute;
//Add another selector for routing to the same page from another path.
//Here we add the root path to select the index page
if (isIndexRoute)
var defaultTemplate = Regex.Replace(overriddenRoute, "/index$", "", RegexOptions.IgnoreCase);
route.Selectors.Add(new SelectorModel()
AttributeRouteModel = new AttributeRouteModel() Template = defaultTemplate
);
//remove the overridden routes to avoid exception of duplicate routes
foreach (var route in context.RouteModels.Where(e => overriddenRoutes.Contains(e.ViewEnginePath)).ToList())
context.RouteModels.Remove(route);
在Startup.ConfigureServices
注册IPageRouteModelProvider
:
services.AddSingleton<IPageRouteModelProvider>(new SuffixedNamePageRouteModelProvider("generated"));
【讨论】:
谢谢!我得到一个错误:AmbiguousMatchException: The request matched multiple endpoints. Matches: /Foo/Index.generated /Index
。它对你有用吗?
另外,也许做类似to this的事情更容易?
是的——你确实是国王^2!
@Ionix 实际上我应该感谢您,您的回复帮助我更好地改进了代码,这实际上可能对其他人和我自己也有帮助。像这样高级的东西需要一个问题来解决,我一个人无法想到你遇到的问题,所以我需要解决问题,这个过程将帮助我更深入地挖掘知识并更多地了解框架。如果您对代码有任何可能的问题,请随时在此处告诉我,以便我提供帮助并使其变得更好。关于我的名字,King 是我的英文名(翻译自越南语):)
你太谦虚了——这需要对netcore平台有深入的了解,这是大多数人所没有的。我希望有一天我能拥有这样的技能。是的,你是所有语言的编码之王。太感谢了! :)以上是关于在 ASP.NET Core Razor 页面中更改 cshtml 文件的名称的主要内容,如果未能解决你的问题,请参考以下文章
Asp.net core razor pages 加载部分页面