Razor Page Library:开发独立通用RPL(内嵌wwwroot资源文件夹)

Demo路径:https://github.com/yanshengjie/RPL.Demo

1. Introduction

Razor Page Library 是ASP.NET Core 2.1引入的新类库项目,属于新特性之一,用于创建通用页面公用类库。也就意味着可以将多个Web项目中通用的Web页面提取出来,封装成RPL,以进行代码重用。
官方文档Create reusable UI using the Razor Class Library project in ASP.NET Core中,仅简单介绍了如何创建RPL,但要想开发出一个独立通用的RPL远远没有那么简单,容我娓娓道来。

2. Hello RPL

老规矩,从Hello World 开始,我们创建一个Demo项目。
记住开始之前请确认已安装.NET Core 2.1 SDK!!!
我们这次使用命令行来创建项目:

>dotnet --version2.1.300>dotnet new razorclasslib --name RPL.CommonUI
已成功创建模板“Razor Class Library”。正在处理创建后操作...正在 RPL.CommonUI\RPL.CommonUI.csproj 上运行 "dotnet restore"...正在还原 F:\Coding\Demo\RPL.CommonUI\RPL.CommonUI.csproj 的包...正在生成 MSBuild 文件 F:\Coding\Demo\RPL.CommonUI\obj\RPL.CommonUI.csproj.nuge
t.g.props。正在生成 MSBuild 文件 F:\Coding\Demo\RPL.CommonUI\obj\RPL.CommonUI.csproj.nuge
t.g.targets。  F:\Coding\Demo\RPL.CommonUI\RPL.CommonUI.csproj 的还原在 1.34 sec 内完成。还原成功。
>dotnet new mvc --name RPL.Web
已成功创建模板“ASP.NET Core Web App (Model-View-Controller)”。
此模板包含非 Microsoft 的各方的技术,有关详细信息,请参阅 https://aka.ms/aspnetc
ore-template-3pn-210。正在处理创建后操作...正在 RPL.Web\RPL.Web.csproj 上运行 "dotnet restore"...正在还原 F:\Coding\Demo\RPL.Web\RPL.Web.csproj 的包...正在生成 MSBuild 文件 F:\Coding\Demo\RPL.Web\obj\RPL.Web.csproj.nuget.g.props
。正在生成 MSBuild 文件 F:\Coding\Demo\RPL.Web\obj\RPL.Web.csproj.nuget.g.target
s。  F:\Coding\Demo\RPL.Web\RPL.Web.csproj 的还原在 2 sec 内完成。还原成功。
>dotnet new sln --name RPL.Demo
已成功创建模板“Solution File”。
>dotnet sln RPL.Demo.sln add RPL.CommonUI/RPL.CommonUI.csproj
已将项目“RPL.CommonUI\RPL.CommonUI.csproj”添加到解决方案中。
>dotnet sln RPL.Demo.sln add RPL.Web/RPL.Web.csproj
已将项目“RPL.Web\RPL.Web.csproj”添加到解决方案中。

创建完毕后,双击RPL.Demo.sln打开解决方案,如下图:

640?wx_fmt=png

  1. 修改Page1.cshtml,body内添加<h1>This is from CommonUI.Page1</h1>

  2. RPL.Web添加引用项目【RPL.CommonUI】

  3. 设置RPL为启动项目。

  4. CTRL+F5运行。

我们观察到RPL.CommonUI中预置了一个Razor Page,因为Razor Page是基于文件系统路由,所以直接https://localhost:<port>/myfeature/page1即可访问。
640?wx_fmt=png

到这一步,我们就可以笃定RPL正确生效。

3. Keep Going

以上只是简单的HTML页面,如果要想加以润色,就需要写CSS来处理。
两种处理方式:

  1. 使用内联样式

  2. 引用外部样式文件

内联样式,很简单,就不加以赘述。
我们来定义样式文件来处理。仿照RPL.Web项目,创建一个wwwroot根目录,然后再添加一个css文件夹,再添加一个demo.css的样式文件。

h1 {    color: red;
}

然后将demo.css引用添加到page1.cshtml中。

<head><meta name="viewport" content="width=device-width" /><link rel="stylesheet" href="~/css/demo.css" /><title>Page1</title></head>

CTRL+F5重新运行,运行结果如下图:
640?wx_fmt=png

可以清晰的看到,定义的样式并未生效。从浏览器F12 Developer Tool中可以清晰的看到,无法请求demo.css样式文件。
到这里,也就抛出了本文所要解决的问题:如何开发独立通用的RPL?
如果RPL中无法引用项目中定义一些静态资源文件(CSS、JS、Image等),那RPL将无法有效的组织View。

4. Analyze

要想访问RPL中的静态资源文件,首先我们要弄明白.NET Core Web项目中wwwroot文件夹的资源是如何访问的。
这一切得从应用程序启动说起,为了方便查阅,使用Code Map将相关代码显示如下:
640?wx_fmt=png

从中可以看出在构建WebHost的业务逻辑中会去初始化IHostingEnvironment对象。该对象主要用来描述应用程序运行的web宿主环境的相关信息,主要包含以下几个属性:

string EnvironmentName { get; set; }string ApplicationName { get; set; }string WebRootPath { get; set; }
IFileProvider WebRootFileProvider { get; set; }string ContentRootPath { get; set; }
IFileProvider ContentRootFileProvider { get; set; }

从上图的注释代码中可以看到,其初始化逻辑正是去指定WebRootPathWebRootFileProvider
如果我们在应用程序未手动通过webHostBuilder.UseWebRoot("your web root path");指定自定义的Web Root路径,那么将会默认指定为wwwroot文件夹。
同时注意下面这段代码:

hostingEnvironment.WebRootFileProvider = newPhysicalFileProvider(hostingEnvironment.WebRootPath);

其指定的IFileProvider的类型为PhysicalFileProvider
到这里,是不是就豁然开朗了,Web 应用启动时,指定的WebRootFileProvider仅仅映射了Web应用的wwwroot目录,自然是访问不了我们RPL项目指定的wwwroot目录啊。

到这里,其实我们离问题就很近了。但是只要指定了WebRootFileProvider就可以访问WebRoot目录的资源了吗?并不是。

我们知道,ASP.NET Core是通过由一系列中间件组装而成的请求管道来处理请求的。不管是View视图也好,还是静态资源文件也好,都是通过Http Request来请求的。HTTP Request流入请求管道后,根据请求类型,不同的中间件负责处理不同的请求。那对于静态资源文件,ASP.NET Core中是借助StaticFileMiddleware中间件来处理的。这也就是为什么在启动类StartupConfigure方法中需要指定app.UseStaticFiles();来启用StaticFileMiddleware中间件。

在ASP.NET Core 官方文档中Static files in ASP.NET Core,介绍了如何访问自定义目录的静态资源文件。

如果需要访问自定义路径目录的资源,需要添加类似以下代码:

app.UseStaticFiles(new StaticFileOptions{FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),RequestPath = "/StaticFiles"});

但这似乎并不能满足我们的需求。Why?看标题,开发独立通用的RPL。怎么理解独立通用?也就意味着RPL中的资源文件最好能够通过程序集打包。这样才能完全独立。否则,在发布RPL时,还需要输出静态资源文件,显然增加了使用的难度。而如何将资源文件打包进程序集呢?——内嵌资源。

5. Embedded Resource

一个程序集主要由两种类型的文件构成,它们分别是承载IL代码的托管模块文件和编译时内嵌的资源文件。那在.NET Core中如何定义内嵌资源呢?

  1. 编辑RPL.CommonUI.csproj文件,添加wwwroot为内嵌资源。

      <ItemGroup><EmbeddedResource Include="wwwroot\**\*" /></ItemGroup>
  2. 添加GenerateEmbeddedFilesManifest节点,指定生成内嵌资源清单。

    <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
  3. 添加Microsoft.Extensions.FileProviders.EmbeddedNuget包引用。

修改完后的RPL.CommonUI.csproj,如下所示:

<Project Sdk="Microsoft.NET.Sdk.Razor"><PropertyGroup><TargetFramework>netstandard2.0</TargetFramework><GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest></PropertyGroup><ItemGroup><PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.0" /><PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.1.0" /></ItemGroup><ItemGroup><EmbeddedResource Include="wwwroot\**\*" /></ItemGroup></Project>

我们用ildasm.exe反编译RPL.CommonUI.dll,查看下其程序集清单:

640?wx_fmt=png

从图中可以看出内嵌的demo.css文件,是以{程序集名称}.{文件路径}命名的。

那内嵌资源如何访问呢?可以借助EmbeddedFileProvider,我们仿照上面的例子,在Startup.csConfigure方法中添加以下代码:

app.UseStaticFiles();var dllPath = Path.Join(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "RPL.CommonUI.dll");
app.UseStaticFiles(new StaticFileOptions
{FileProvider = new ManifestEmbeddedFileProvider(Assembly.LoadFrom(dllPath), "wwwroot")
});

CTRL+F5,运行。Perfect!
640?wx_fmt=png

当然这也不是最好的解决方案,因为你肯定不想所有调用这个RPL的地方,添加这么几句代码,因为这段代码有很强的侵入性,且不可隔离变化。

5. Final Solution

  • 编辑RPL.CommonUI.csproj文件,添加wwwroot为内嵌资源。

      <ItemGroup><EmbeddedResource Include="wwwroot\**\*" /></ItemGroup>
  • 添加GenerateEmbeddedFilesManifest节点,指定生成内嵌资源清单。

    <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
  • 添加Microsoft.AspNetCore.StaticFilesMicrosoft.Extensions.FileProviders.EmbeddedNuget包引用。

修改完后的RPL.CommonUI.csproj,如下所示:

<Project Sdk="Microsoft.NET.Sdk.Razor"><PropertyGroup><TargetFramework>netstandard2.0</TargetFramework><GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest></PropertyGroup><ItemGroup><PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.0" /><PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.0" /><PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.1.0" /></ItemGroup><ItemGroup><EmbeddedResource Include="wwwroot\**\*" /></ItemGroup></Project>
  • 接下来添加CommonUIConfigureOptions.cs,定义如下:

640?wx_fmt=png

  • 然后添加CommonUIServiceCollectionExtensions.cs,代码如下:

640?wx_fmt=png

  • 修改RPL.Web启动类startup.cs,在services.AddMvc()之前添加services.AddCommonUI();即可。

  • CTRL+F5重新运行,我们发现H1被成功设置为红色,检查发现demo.css也能正确被请求,检查network也可以看到其Request URL为:https://localhost:44379/css/demo.css
    640?wx_fmt=png
    640?wx_fmt=png

  1. Static files in ASP.NET Core

  2. File Providers in ASP.NET Core

  3. ManifestEmbeddedFileProvider Class

  4. Make it easier to use static assets that are part of a RCL project

  5. .NET Core的文件系统[4]:由EmbeddedFileProvider构建的内嵌(资源)文件系统

相关文章: 

  • 用ASP.NET Core 2.1 建立规范的 REST API -- HATEOAS

  • 在ASP.NET Core中使用brotli压缩

  • ASP.NET Core2.1 你不得不了解的GDPR

  • .NET Core 2.1改进了性能,并提供了新的部署选项

  • Entity Framework Core 2.1带来更好的SQL语句生成方案

原文地址: https://www.cnblogs.com/sheng-jie/p/9165547.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/321167.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Problem H Rock Paper Scissors,FFT

题目 题目链接 题意 给出两段石头剪刀布的顺序SS和T" role="presentation" style="position: relative;">TT&#xff0c;其中TT要短一些,现在让你把T" role="presentation" style="position: relative;">TT往SS的…

CF1066F-Yet another 2D Walking【贪心】

正题 题目链接:https://www.luogu.com.cn/problem/CF1066F 题目大意 平面上有nnn个点&#xff0c;每个点在max(x,y)max(x,y)max(x,y)层&#xff0c;走第kkk层的点之前一定要先走前面层的点&#xff0c;求走完所有点的最短路。 解题思路 对于每一层来说&#xff0c;我们可以将…

【最短路】【SPFA】城市问题(ssl 1761)

城市问题 ssl 1761 题目大意&#xff1a; 求一个点到其它点的最短路 原题&#xff1a; Description 设有n个城市&#xff0c;依次编号为0&#xff0c;1&#xff0c;2&#xff0c;……&#xff0c;n-1&#xff08;n<100&#xff09;&#xff0c;另外有一个文件保存n个城…

.NET Core微服务之基于Ocelot实现API网关服务

一、啥是API网关&#xff1f;API 网关一般放到微服务的最前端&#xff0c;并且要让API 网关变成由应用所发起的每个请求的入口。这样就可以明显的简化客户端实现和微服务应用程序之间的沟通方式。以前的话&#xff0c;客户端不得不去请求微服务A&#xff08;假设为Customers&am…

P3157 动态逆序对 ,树状数组套动态开点线段树

题目 洛谷题目链接 题解 在求整体的逆序对的数量时&#xff0c;很好办&#xff0c;直接用树状数组处理即可&#xff0c;不过在这时&#xff0c;我们还需要处理出一个数组pa[]pa[]pa[]&#xff0c;其中pa[i]pa[i]pa[i]代表在区间[1,i)[1,i)[1,i)中满足aj>aia_j>a_iaj​…

【DP】猫咪的进化

猫咪的进化 题目大意&#xff1a; 有n个实数&#xff0c;每一个实数可以选&#xff0c;可以不选&#xff0c;也可以选择它的平方&#xff0c;但如果选择了它的平方&#xff0c;就不能选择下一个数或下一个数的平方&#xff0c;求选出来的数的和最大是多少 原题&#xff1a; …

[8.21NOIP模拟赛]决战【tarjan】

正题 题目大意 nnn个点mmm条边的联通图&#xff0c;去掉一个点使得其变为一棵树 求能去掉哪些点 解题思路 首先去掉后就是一棵n−1n-1n−1个节点的树&#xff0c;也就是有n−2n-2n−2条边&#xff0c;这样我们就需要去掉m−n2m-n2m−n2条边&#xff0c;也就是去掉入度为m−n2…

[译]RabbitMQ教程C#版 - 发布订阅

先决条件本教程假定RabbitMQ已经安装&#xff0c;并运行在localhost标准端口&#xff08;5672&#xff09;。如果你使用不同的主机、端口或证书&#xff0c;则需要调整连接设置。从哪里获得帮助如果您在阅读本教程时遇到困难&#xff0c;可以通过邮件列表联系我们。1.发布/订阅…

P2468 [SDOI2010]粟粟的书架 动态规划,主席树,二分答案

题目 洛谷题目链接 题解 题目的数据范围非常奇怪&#xff0c;一半是200∗200200∗200的矩阵&#xff0c;另一半是1∗500001∗50000的矩阵&#xff0c;显然是一道二合一的题目&#xff0c;但是不一样的地方也就在与数据结构的选择不一样&#xff0c;而我们解这道题使用的算法…

nssl1511-我的世界【堆,贪心】

正题 题目大意 nnn个点的一棵树&#xff0c;给每一个点一个权值&#xff0c;每个点的依靠点是与它相连的权值最小的点&#xff0c;要求每个点最多只有一个依赖点。 求字典序最小的方案 解题思路 首先最小的一定是叶子结点&#xff0c;然后他的父节点指向他&#xff0c;因为它…

【SPFA】【最短路/次短路】GF打Dota

GF打Dota 题目大意&#xff1a; 求一个点到另一个点的最短路或次短路 原题&#xff1a; 题目描述 众所周知&#xff0c;GF同学喜欢打dota&#xff0c;而且打得非常好。今天GF和Spartan同学进行了一场大战。现在GF拿到一张地图&#xff0c;地图上一共有n个地点&#xff0c;…

用ASP.NET Core 2.1 建立规范的 REST API -- 缓存和并发

本文所需的一些预备知识可以看这里: 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 和 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 (2) 准备项目建立Richardson成熟度2级的POST、GET、PUT、PATCH、DELETE的RESTful API请看这里&#xff1a;用ASP.NET Core …

2017 SEERC Divide and Conquer 树上差分

题目 题目大意&#xff1a;给出两颗树的复合图(即这张图是由两颗树拼起来的)&#xff0c;询问最小割掉多少条边&#xff0c;可以使得图不联通&#xff0c;并输出方案数。 分析 我觉得这是一道很难的题目&#xff0c;因为比较难想&#xff0c;前提结论比较多。 首先我们需要…

P2414-[NOI2011]阿狸的打字机【AC自动机,树状数组】

正题 题目链接:https://www.luogu.com.cn/problem/P2414 题目大意 一个子串表示操作有 往凹槽里打一个字母删除最后一个字母将凹槽中的字母打印到一个新的行里&#xff08;原来的不会消失&#xff09; 然后每次询问两个数字(x,y)(x,y)(x,y)表示询问第xxx行的字串在第yyy行的…

青蛙跳荷叶

青蛙跳荷叶 题目大意&#xff1a; 有n个点&#xff0c;从1开始到跳完这些点&#xff0c;且每次的距离不能相等&#xff0c;一个点不能到多次 原题&#xff1a; 题目描述 从前&#xff0c;有一个小青蛙决定去荷叶上练习跳跃.现在有n个荷叶排成一排&#xff0c;小青蛙一开始…

基于 Consul 实现 MagicOnion(GRpc) 服务注册与发现

0.简介0.1 什么是 ConsulConsul是HashiCorp公司推出的开源工具&#xff0c;用于实现分布式系统的服务发现与配置。这里所谓的服务&#xff0c;不仅仅包括常用的 Api 这些服务&#xff0c;也包括软件开发过程当中所需要的诸如 Rpc、Redis、Mysql 等需要调用的资源。简而言之 Con…

2017 ACM Jordanian Collegiate J.Efficiency Test 动态规划、类倍增

题目 题目链接 题解及代码 #include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N 1e57; int f[2*N][55],a[2*N],sum[2*N],ans[2*N],pb[2*N]; int T,n,k; #define pr(x) cout<<#x<<":"&…

P3041-[USACO12JAN]Video Game G【AC自动机,dp】

正题 题目链接:https://www.luogu.com.cn/problem/P3041 题目大意 输入nnn个只有ABCABCABC的字符串&#xff0c;求一个长度为LLL的字符串中最多包含多少个子串是nnn个字符串中的一个 解题思路 考虑ACACAC自动机是如何进行匹配的&#xff0c;对于下一个字符&#xff0c;如果有…

【DFS】排排坐

排排坐 题目大意&#xff1a; 有n个方块&#xff0c;有一些是黑色&#xff0c;有一些是白色&#xff0c;可以点击一个方块使它和它旁边的方块反转颜色&#xff08;黑变白&#xff0c;白变黑&#xff09;&#xff0c;问最少要点多少次才能将方块 们 变成目标的方块们&#xff…

用ASP.NET Core 2.1 建立规范的 REST API -- 保护API和其它

预备知识: 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 (2) 准备项目建立成熟度2级的 API请看这里&#xff1a;用ASP.NET Core 2.0 建立规范的 REST API -- GET 和 POST, 用ASP.NET Core 2.0 建立规范的 REST AP…