如何解决在 ASP.NET Core RazorPages 中更改 cshtml 文件的名称
我的环境:带有 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
?
解决方法
加载应用程序时,框架会为您加载一组 PageRouteModel
,这些 SelectorModel
是从 razor 页面文件夹自动生成的(按照惯例)。每个这样的模型都包含一组 AttributeRouteModel
,每个模型都有一个 AttributeRouteModel.Template
。您需要做的只是通过从自动生成的值中删除后缀部分来修改 IPageRouteModelConvention
。
您可以创建自定义 PageRouteModel
来定位每个 AttributeRouteModel.Template
。但是,您无法确保路线不会重复(因为修改 IPageRouteModelProvider
后,它可能会与其他一些现有路线重复)。除非您必须管理一组共享的路由模板。相反,您可以创建自定义 PageRouteModel
。它在一处提供所有 Index.cshtml
,以便您可以修改、添加或删除任何内容。这种方式非常方便,您可以支持 2 个剃刀页面,其中一个页面的优先级高于另一个页面(例如:您有 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,"");
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,"");
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);
}
}
}
)。
这里是详细代码:
IPageRouteModelProvider
在 Startup.ConfigureServices
中注册 services.AddSingleton<IPageRouteModelProvider>(new SuffixedNamePageRouteModelProvider("generated"));
:
import React from "react";
import {
View,StyleSheet,Text,ImageBackground,Image,Button,TouchableOpacity,} from "react-native";
import { LinearGradient } from "expo-linear-gradient";
import colors from "../config/colors";
import { withNavigation } from "react-navigation";
export default function HomePageScreen({ navigation }) {
return (
<ImageBackground
style={styles.background}
source={require("../assets/background.jpg")}
>
<Image style={styles.logo} source={require("../assets/logo2.png")} />
{/* the create button */}
<LinearGradient
colors={[colors.primary,colors.secondary]}
start={{ x: 0,y: 0 }}
end={{ x: 1,y: 0 }}
style={styles.createButton}
>
<TouchableOpacity
style={styles.touch}
onPress={() => navigation.navigate("Create Project")}
>
<Text style={styles.buttonText}>Create</Text>
</TouchableOpacity>
</LinearGradient>
{/* the search button */}
<LinearGradient
colors={[colors.primary,y: 0 }}
style={styles.searchButton}
>
<TouchableOpacity
style={styles.touch}
onPress={() => navigation.navigate("Search Projects")}
>
<Text style={styles.buttonText}>Search</Text>
</TouchableOpacity>
</LinearGradient>
</ImageBackground>
);
}
const styles = StyleSheet.create({
background: {
width: "100%",height: "100%",alignItems: "center",justifyContent: "center",},logo: {
height: 275,width: 275,position: "absolute",top: 60,createButton: {
height: 70,width: 325,bottom: 150,borderRadius: 999,touch: {
height: 70,textAlignVertical: "center",searchButton: {
height: 70,bottom: 50,buttonText: {
color: "white",fontSize: 28,fontWeight: "bold",alignSelf: "center",});
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。