- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章ASP.NET Core MVC/WebApi基础系列1由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
>前言 。
最近发表的EF Core貌似有点多,可别误以为我只专攻EF Core哦,私下有时间也是一直在看ASP.NET Core的内容,所以后续会穿插讲EF Core和ASP.NET Core,别认为你会用ASP.NET Core就自认为你很了解ASP.NET Core,虽说是基础系列但也是也有你不知道的ASP.NET Core.
UseStaticFiles、UseDefaultFiles、UseDirectoryBrowser、UseFileServer 。
当我们创建默认.NET Core Web应用程序时,.NET Core默认为我们注入了StaticFiles从而可使用wwwroot目录下的静态文件,请注意这里注入StaticFiles是基于wwwroot目录下的静态文件,此时我们如下通过使用UseDefaultFiles启用默认静态文件.
1
2
|
app.UseDefaultFiles();
app.UseStaticFiles();
|
在此之前呢,我们在wwwroot目录下创建了四个静态HTML文件,如下:
根据官方文档说明,我们创建如上四个静态html,同时也会根据如上顺序在wwwroot目录下查找静态html,查找到了default.htm,所以此时如上显示对应内容,若我们删除第一个html,则会查找default.html,以此类推。要是我们将注入顺序颠倒会这样呢?如下:
1
2
|
app.UseStaticFiles();
app.UseDefaultFiles();
|
此时会出现页面404找不到页面,这是为何呢?官方文档强调必须将注入默认文件放在注入静态文件前面,主要是因为注入默认文件只是进行URL重写,告诉路由我要到wwwroot目录下查找静态文件,但是实际上提供静态文件的是StaticFiles,所以这也是为什么必须将注入默认文件放在注入静态文件前面。但是如果我们非要将注入默认文件放在注入静态文件前面,我们该如何做呢?接下来通过使用UseFileServer,UseFileServer是UseDefaultFiles和UseStaticFiles的组合体,既然是组合体,我们将UseFileServer放在第一位不就这个问题了吗,我们来试试,如下:
1
2
3
|
app.UseFileServer();
app.UseStaticFiles();
app.UseDefaultFiles();
|
结果将会呈现默认静态html,这里我就不再演示了,有兴趣的童鞋可自行研究。接下来我们再来看看启用目录浏览,启用目录浏览和我们在IIS上启用目录浏览一样,如下:
1
2
3
4
|
app.UseDirectoryBrowser();
app.UseFileServer();
app.UseStaticFiles();
app.UseDefaultFiles();
|
这里就不用我再多说,那么问题来了:要是我们将启用目录浏览放到使用MVC路由后面会怎样呢?此时启用目录浏览会覆盖MVC路由?不会,可自行验证.
1
2
3
4
5
6
7
8
|
app.UseMvc(routes =>
{
routes.MapRoute(
name:
"default"
,
template:
"{controller=Home}/{action=Index}/{id?}"
);
});
app.UseDirectoryBrowser();
|
自定义默认文件目录 。
关于修改默认文件名称等基础,官方文档有详细说明,这里就不再演示,浪费篇幅,接下来我们来重点讲解不一样的。比如默认启用静态文件,是放在wwwroot根目录下,要是我们想将静态文件放在所给第一张图中dist文件夹下呢?此时我们应该如何做呢?因为.NET Core默认将wwwroot目录作为静态文件目录,所以此时我们需要改变其目录到wwwroot目录下的dist目录,通过使用UseWebRoot方法,将Web静态目录更改到wwwroot下的dist目录,当然同时启用默认文件(UseDefaultFiles)如下:
1
|
.UseWebRoot(Path.Combine(Directory.GetCurrentDirectory(),
"wwwroot"
,
"dist"
))
|
。
那么问题又来了,此时假设我想将默认静态文件放在外部即项目根目录,此时我们应该如何做呢?比如访问如下静态html文件.
此时我们可利用UseDefaultFiles方法的重载,将目录更换到项目根目录下的OutDefaultHtml目录,如下:
1
2
3
4
5
6
7
8
|
var fileProvider =
new
PhysicalFileProvider(Path.Combine(env.ContentRootPath,
"OutDefaultHtml"
));
app.UseDefaultFiles(
new
DefaultFilesOptions()
{
FileProvider = fileProvider,
DefaultFileNames =
new
[] {
"OutDefault.html"
}
});
|
因为我们更换了查找静态html的目录,同时最终提供默认文件的是UseStaticFiles,所以我们也需要通过UseStaticFiles方法的重载切换目录不再是wwwroot,如下:
1
2
3
4
|
app.UseStaticFiles(
new
StaticFileOptions()
{
FileProvider = fileProvider
});
|
除了上述通过联合使用UseDefaultFiles和UseStaticFiles之外,是否还有更简洁的方式呢?当然是有的,当默认静态文件放在wwwroot目录下不再满足我们的需求时,我们需要自定义默认静态文件所放置目录时,推荐使用二者的联合体即UseFileServer。上述我们可修改成如下:
1
2
3
4
5
6
|
var fileProvider =
new
PhysicalFileProvider(Path.Combine(env.ContentRootPath,
"OutDefaultHtml"
));
var fileServerOptions =
new
FileServerOptions();
fileServerOptions.DefaultFilesOptions.DefaultFileNames =
new
[] {
"OutDefault.html"
};
fileServerOptions.FileProvider = fileProvider;
app.UseFileServer(fileServerOptions);
|
UseStaticFiles详解 。
在大部分情况下,我们都将静态文件放在wwwroot目录下,但是有那么百分之十的情况下会将静态文件放在项目根目录,那么此时使用默认注入的UseStaticFiles方法就不再适用,此时我们需要用到其重载方法。比如我们要访问如下图中的mvc_course.gif,我们该如何做呢?
上面已经讲过,需要使用UseStaticFiles方法的重载,第一个参数将目录切换到静态文件所在目录,第二个参数是虚拟路径用来访问静态文件,为了不对外暴露实际物理路径,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
app.UseStaticFiles(
new
StaticFileOptions()
{
FileProvider =
new
PhysicalFileProvider(Path.Combine(env.ContentRootPath,
"OutStaticFiles"
)),
RequestPath =
"/outfiles"
});
或者
//app.UseStaticFiles(new StaticFileOptions()
//{
// FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "OutStaticFiles")),
// RequestPath = new PathString("/outfiles")
//});
|
该重载方法还有一个委托参数OnPrepareResponse,这个主要用来缓存静态文件,接下来我们来重点讲讲,其实本文都是重点,哈哈,简单的大家直接去看官网吧.
1
2
3
4
5
6
7
8
9
10
|
app.UseStaticFiles(
new
StaticFileOptions()
{
FileProvider =
new
PhysicalFileProvider(Path.Combine(env.ContentRootPath,
"OutStaticFiles"
)),
RequestPath =
"/outfiles"
,
OnPrepareResponse = ctx =>
{
const
int
cacheControll = 60;
ctx.Context.Response.Headers[
"Cache-Control"
] =
"public,max-age="
+ cacheControll;
}
});
|
在官方文档上是进行如上设置,但实际上官方文档APi已经过时,对于请求头的设置直接有HeaderNames这样一个枚举来进行设置,不再通过字符串的形式来设置,这样不容易出错且方便,上述对于请求头中缓存控制的设置有如下两种方式皆可.
在响应头中添加缓存控制有什么实际作用?此时就要谈到缓存控制的原理了。上述缓存控制设置的过期时间为60秒。当第一次请求时返回200,在此间隙即60秒内反复刷新都会是200,同时从浏览器缓存中读取,一旦过了60秒,再刷新此时会再去读取服务器上的图片,发现图片未发生改变返回304未修改。那么问题来了,如果我们在此间隙内修改了图片的内容,然后再刷新图片的内容是否会发生改变呢?答案是:不会,只要在缓存间隙时间内,即使我们修改了图片的内容,再刷新还是显示原来的图片(除非进行ctrl+F5强制刷新才行)。好了讲了这么多,我们继续拓展一下,再来看看ASP.NET Core中TagHelper特性:asp-append-version特性。该特性和缓存控制原理是一样的么,接下来我们来谈谈asp-append-version以及其原理.
asp-append-version详解及其原理 。
我们以wwwroot目录下images文件下的图片为例,然后在页面上访问图片加上asp-append-version看看,如下:
1
|
<img src=
"~/images/mvc_course.gif"
asp-append-version=
"true"
/>
|
。
此时响应返回链接地址为:http://localhost:63277/images/mvc_course.gif?v=y3F-lvD7XoqGqLIWq_WsuFN9POPSjit1Au6_0iRrgwE,我们从如上图也可看到,此时在图片后面类似加了一个版本号v,我们反复刷新版本号后面的字符串一直未变,那么这个类似于哈希码的值是怎么得来的呢?基于请求URL和图片内容计算出哈希码即版本号。也就说只要我们更改了图片的内容,当刷新或者再次访问此页面时内容相应会进行对应更新,这也就是我们所说的缓存击穿,相对于缓存控制而言,只要在缓存间隙时间内修改了图片内容,除非进行强制刷新,否则图片依然显示旧的图片,而asp-append-version特性则是你变,我变,你不变,我一成不变。是不是就这么简单呢?接下来我们访问一下项目根目录下的图片看看,通过UseStaticFiles重载访问外部图片,同时加上asp-append-version特性.
1
|
<img src=
"/outfiles/mvc_course.gif"
asp-append-version=
"true"
/>
|
WOW,看到了什么没有,发现了什么没有,至此我们可以得出结论:asp-append-version特性实现图片缓存只是针对于WebRoot目录下的静态文件,而外部静态文件则无效.
那么既然问题已经很凸出了,asp-append-version主要是针对于WebRoot目录下的静态文件,而WebRoot里面只有wwwroot,所以我们可以称之为只对wwwroot目录下的静态文件才生效,所以我们是否可以尝试将外部文件目录也置于WebRoot目录呢?从而实现对外部静态文件的缓存呢?我们下面来做尝试,在Startup.cs中默认注入UseStaticFiles,我们搁置不变,这样对默认针对wwwroot下的样式、脚本、文件都不会发生任何改变,我们只是再来注入一个UseStaticFiles而已,如下:
1
2
3
4
5
6
7
8
9
10
11
|
var compositeProvider =
new
CompositeFileProvider
(
env.WebRootFileProvider,
new
PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),
"OutStaticFiles"
))
);
env.WebRootFileProvider = compositeProvider;
app.UseStaticFiles(
new
StaticFileOptions()
{
FileProvider = compositeProvider,
RequestPath =
"/outfiles"
});
|
如上针对默认的WebRoot即wwwroot保持不变,我们在此基础上添加外部目录从而作为复合FileProvider作为WebRoot,这样一切都未变。我们再来进行如下访问.
1
|
<img src=
"/mvc_course.gif"
asp-append-version=
"true"
/>
|
如上是针对OutStaticFiles作为WebRoot目录访问其静态文件,断不可加上outfiles虚拟路径,这样就当做是外部静态文件,从而不会有版本号出现,结果如下:
我们如何自定义实现对外部文件也添加类似于asp-append-version特性版本号的效果呢? 上述我们已经明确讲解到asp-append-version本质原理则是基于请求URL和请求图片内容来计算版本号从而实现缓存,关于缓存我们大可借助IMemoryCache接口来进行缓存,请求的路径我们可以通过请求上下文获取到,同时也可通过环境变量拿到请求静态文件所在目录,所以接下来我们只需要实现视图的扩展方法即可.
视图扩展方法通过指向IRazorPage接口,然后参数则是我们的文件路径,ASP.NET Core有了依赖注入让我们甚为欢喜,我们通过视图中的视图上下文拿到请求上下文。然后拿到已经注入的IMemoryCache和IHostingEnviroment接口,关于文件版本号,ASP.NET Core给我们提供了FileVersionProvider类,如下:
我们将参数传递到FileVersionProvider构造函数中去,最后将得到的文件版本号添加到我们请求的文件路径尾巴上,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
static
class
RazorPageExtension
{
public
static
string
AddAppendVersion(
this
IRazorPage page,
string
path)
{
var context = page.ViewContext.HttpContext;
var memoryCache = context.RequestServices.GetService(
typeof
(IMemoryCache))
as
IMemoryCache;
var hostingEnviroment = context.RequestServices.GetService(
typeof
(IHostingEnvironment))
as
IHostingEnvironment;
var fileversionProvider =
new
FileVersionProvider(hostingEnviroment.WebRootFileProvider, memoryCache, context.Request.Path);
return
fileversionProvider.AddFileVersionToPath(path);
}
}
|
。
我们利用上述自定义实现的Razor视图扩展方法来访问图片从而得到版本号试试,如下:
1
|
<img src=
"@this.AddAppendVersion("
/mvc_course.gif
")"
|
总结 。
本文详细讲解了ASP.NET Core MVC中静态文件以及缓存控制、asp-append-version本质原理,同时讲解了缓存控制和asp-append-version区别所在。默认情况下,asp-append-version只针对wwwroot有效,因为在WebRoot里面只存在wwwroot,要想对外部文件有效,可将外部文件所在目录也作为WebRoot来使用.
。
最后此篇关于ASP.NET Core MVC/WebApi基础系列1的文章就讲到这里了,如果你想了解更多关于ASP.NET Core MVC/WebApi基础系列1的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我想为我的 ABP 项目中的特定应用程序服务关闭自动 WebAPI 生成服务。 最佳答案 RemoteService 属性可用于将类标记为远程服务或禁用固有地实现 IRemoteService 接口(
我无法从 postman 访问 webapi 错误是下一个: 如您所见,没有授权。 valuescontroller.cs 是: namespace CVService.Controllers {
我无法从 postman 访问 webapi 错误是下一个: 如您所见,没有授权。 valuescontroller.cs 是: namespace CVService.Controllers {
我有以下 Controller ,它应该接受用户名和密码作为 POST 中的有效负载。如果我将其更改为 HttpGet 就可以了。 [RoutePrefix("api")] public class
使用以下路线: routes.MapHttpRoute( name: "Set", routeTemplate: "api/set/{id}",
我正在使用 AngularJS,我正在尝试将 json 从我的服务发送到 webAPI Controller 。当我通过发送时,我在 webApi 函数的参数中收到 null。 我的功能服务是: an
据我了解,如果我有一个 ASP.NET WebApi 方法,其签名如下所示...... public HttpResponseMessage PostCustomer(Customer custome
我遇到了一个解决方案问题,我使用 Visual Studio SPA 模板中的部分在具有 Oauth 身份验证的 WebApi 中拥有帐户 Controller 。 app.UseOAuthBea
我按照此处的说明将 webApi.HelpPage 区域和 View 添加到使用 structureMap 的现有项目中 - 但是在访问/Help url 时: StructureMap Except
我有一个 WebAPI。如何返回并打开网页。例如,我想打开 CNN.com 页面。 [HttpGet] public HttpResponseMessage Get()
我想知道是否有人可以澄清这一点。我发现用法令人困惑。 链接和视频都没有回答我的问题 我知道像这样的链接 asp.net core middleware vs filters 甚至还有关于它的视频 但是
运行以下最新版本(在撰写本文时): Visual Studio 2019 16.4.5 .NET 核心 SDK 3.1.102 x64 测试的浏览器: 谷歌浏览器 80.0.3987.122 火狐 7
想法是,将有一个外部实体 (SharePoint) 调用我的 WebAPI 并传入 PDF 文件以及有关该 PDF 文件的一些额外元数据信息。我被困在如何构造 Web API 方法的签名上。这是我到目
我有一个 WebApi 服务处理来自简单表单的上传,如下所示: 但是,我不知道如何使用 HttpClient API 模拟同一
嗨,我是 Angular 的新手,现在我从一个示例登录页面开始,该页面传递包含用户名和密码的 userEntity。userEntity 是一个对象/实体是 webapi。 问题:当我为登录按钮单击
我有一个 AngularJS + MVC + WebAPI,我正在尝试:- 使用标准(个人账户)进行MVC认证;- 使用相同的用户和密码进行基于 WebAPI 的身份验证。 问题,AngularJS
Web API 的版本存在一些混淆。看看这个 Web API at NuGet , Microsoft ASP.NET Web API 2.2 5.2.3 什么?这里是没有提到 2.2 的描述 我的猜
我正在开发一个 Web 应用程序,该应用程序将 Owin 托管用于 MVC 和 WebApi 2。 我最近将 Microsoft Mvc/WebApi 包从 5.2.2 版升级到 5.2.3 版,将
随着Web技术的发展,现在各种框架,前端的,后端的,数不胜数。全栈工程师的压力越来越大。 现在的前端的框架,既可以做各种Web,又可以做各种APP,前端框架更新换代越来越快,越来越多。 传统的模
1. WebAPI 背景知识 1.1 什么是 WebAPI JS 分成三个大的部分: ECMAScript: 基础语法部分 DOM API: 操作页面结构 BOM API: 操作浏览器 WebAPI
我是一名优秀的程序员,十分优秀!