ASP.NET Core应用针对静态文件请求的处理[4]: DirectoryBrowserMiddleware中间件如何呈现目录结构
和StaticFileMiddleware中间件一样,DirectoryBrowserMiddleware中间本质上还是定义了一个请求地址与某个物理目录之间的映射关系,而目标目录体现为一个FileProvider对象。当这个中间件接收到匹配的请求后,会根据请求地址解析出对应目录的相对路径,并利用这个FileProvider获取目录的内容。目录的内容最终会以一个HTML文档的形式被定义,而此HTML最终会被这个中间件作为响应的内容,“目录浏览器”的实现原理就这么简单。 [本文已经同步到《ASP.NET Core框架揭秘》之中]
目录
一、DirectoryBrowserMiddleware
二、DirectoryFormatter
三、具体请求处理逻辑
四、自定义DirectoryFormatter
一、DirectoryBrowserMiddleware
接下来我们来看看DirectoryBrowserMiddleware的定义。如下面的代码片段所示,DirectoryBrowserMiddleware的第二个构造函数具有四个参数,其中第二个参数是代表当前执行环境的HostingEnvironment。作为第三个参数的是一个HtmlEncoder对象,当目标目录被呈现为一个HTML文档的时候,它被用于实现针对HTML的编码,如果没有显式指定(调用第一个构造函数),默认的HtmlEncoder(HtmlEncoder.Default)会被使用。至于第四个类型为IOptions<DirectoryBrowserOptions>的参数,则承载了针对DirectoryBrowserMiddleware的配置选项,DirectoryBrowserOptions与前面介绍的StaticFileOptions一样,它们都是SharedOptionsBase的子类。
1: public class DirectoryBrowserMiddleware
2: {
3: public DirectoryBrowserMiddleware(RequestDelegate next, IHostingEnvironment env, IOptions<DirectoryBrowserOptions> options)
4: public DirectoryBrowserMiddleware(RequestDelegate next, IHostingEnvironment hostingEnv, HtmlEncoder encoder, IOptions<DirectoryBrowserOptions> options);
5: public Task Invoke(HttpContext context);
6: }
7:
8: public class DirectoryBrowserOptions : SharedOptionsBase
9: {
10: public IDirectoryFormatter Formatter { get; set; }
11:
12: public DirectoryBrowserOptions();
13: public DirectoryBrowserOptions(SharedOptions sharedOptions);
14: }
二、DirectoryFormatter
DirectoryBrowserMiddleware中间件的目的很明确,就是将目录下的内容(文件和子目录)格式化成一种可读的形式响应给客户端,针对目录内容的响应最终实现在一个DirectoryFormatter对象上。DirectoryFormatter是我们对所有实现了IDirectoryFormatter接口的类型与对应对象的统称,DirectoryBrowserOptions的Formatter属性设置和返回的就是这个一个对象。
如下面的代码片段所示,IDirectoryFormatter接口仅仅包含一个GenerateContentAsync方法。当实现这个方法的时候,我们可以利用第一个类型为HttpContext的参数获取当前请求上下文的信息。该方法的另一个参数返回一组FileInfo的集合,每个FileInfo代表目标下的某个以文件或者子目录。
1: public interface IDirectoryFormatter
2: {
3: Task GenerateContentAsync(HttpContext context, IEnumerable<IFileInfo> contents);
4: }
我们知道默认情况下请求目录的内容在页面上是以一个表格的形式被呈现的,包含这个表格的HTML文档是默认使用的DirectoryFormatter生成的,它是一个类型为HtmlDirectoryFormatter的对象。如下面的代码片段所示,我们在构造一个HtmlDirectoryFormatter对象的时候需要指定一个HtmlEncoder对象,该对象最初来源于构造DirectoryBrowserMiddleware时指定的那个HtmlEncoder对象。
1: public class HtmlDirectoryFormatter : IDirectoryFormatter
2: {
3: public HtmlDirectoryFormatter(HtmlEncoder encoder);
4: public virtual Task GenerateContentAsync(HttpContext context, IEnumerable<IFileInfo> contents);
5: }
三、具体请求处理逻辑
既然最复杂的工作(呈现目录内容)都已经交给DirectoryFormatter来完成了,DirectoryBrowserMiddleware自身的工作其实就没有多少了。为了更好的说明这个中间件在处理请求是具体做了些什么,我们采用一种比较好理解的方式对DirectoryBrowserMiddleware类型进行了重新定义,具体的实现体现在如下所示的代码片段中。
1: public class DirectoryBrowserMiddleware
2: {
3: private RequestDelegate _next;
4: private DirectoryBrowserOptions _options;
5:
6: public DirectoryBrowserMiddleware(RequestDelegate next, IHostingEnvironment env, IOptions<DirectoryBrowserOptions> options) : this(next, env, HtmlEncoder.Default,options)
7: { }
8:
9: public DirectoryBrowserMiddleware(RequestDelegate next, IHostingEnvironment env, HtmlEncoder encoder, IOptions<DirectoryBrowserOptions> options)
10: {
11: _next = next;
12: _options = options.Value;
13: _options.FileProvider = _options.FileProvider ?? env.WebRootFileProvider;
14: _options.Formatter = _options.Formatter ?? new HtmlDirectoryFormatter(encoder);
15: }
16:
17: public async Task Invoke(HttpContext context)
18: {
19: //只处理GET和HEAD请求
20: if (!new string[] { "GET", "HEAD" }.Contains(context.Request.Method, StringComparer.OrdinalIgnoreCase))
21: {
22: await _next(context);
23: return;
24: }
25:
26: //检验当前路径是否与注册的请求路径相匹配
27: PathString path = new PathString(context.Request.Path.Value.TrimEnd('/') + "/");
28: PathString subpath;
29: if (!path.StartsWithSegments(_options.RequestPath, out subpath))
30: {
31: await _next(context);
32: return;
33: }
34:
35: //检验目标目录是否存在
36: IDirectoryContents directoryContents = _options.FileProvider.GetDirectoryContents(subpath);
37: if (!directoryContents.Exists)
38: {
39: await _next(context);
40: return;
41: }
42:
43: //如果当前路径不以"/"作为后缀,会响应一个针对“标准”URL的重定向
44: if (!context.Request.Path.Value.EndsWith("/"))
45: {
46: context.Response.StatusCode = 302;
47: context.Response.GetTypedHeaders().Location = new Uri(path.Value + context.Request.QueryString);
48: return;
49: }
50:
51: //利用DirectoryFormatter响应目录内容
52: await _options.Formatter.GenerateContentAsync(context, directoryContents);
53: }
54: }
如上面的代码片段所示,当DirectoryBrowserMiddleware最终利用注册的DirectoryFormatter来响应目标目录的内容之前,它会做一系列的前期工作。比如它会验证当前请求是否是GET或者HEAD请求,以及当前的URL是否与注册的请求路径相匹配,在匹配的情况下还需要验证目标目录是否存在。除此之外,这个中间件要求访问目录的请求路劲必须以字符“/”作为后缀,否则会在目前的路径上添加这个后缀并针对最终的路径发送一个重定向。所以我们利用浏览器发送针对某个目录的请求的时候,URL明明没有指定“/”作为后缀,这个后缀会自动给我们加上,这就是重定向的作用。
四、自定义DirectoryFormatter
由于目录的内容在浏览器中的呈现方式完全由DirectoryFormatter完成,如果实现在HtmlDirectoryFormatter的默认呈现方式不能满足需求(比如我们需要这个页面与现有网站保持相同的风格),这可以通过注册一个自定义的DirectoryFormatter来完成。接下来我们通过一个简单的实例来演示如何定义这么一个DirectoryFormatter。我们将自定义的DirectoryFormatter命名为ListDirectoryFormatter,应为它仅仅将所有文件或者子目录显示为一个简单的列表。
1: public class ListDirectoryFormatter : IDirectoryFormatter
2: {
3: public async Task GenerateContentAsync(HttpContext context, IEnumerable<IFileInfo> contents)
4: {
5: context.Response.ContentType = "text/html";
6: await context.Response.WriteAsync("<html><head><title>Index</title><body><ul>");
7: foreach (var file in contents)
8: {
9: string href = $"{context.Request.Path.Value.TrimEnd('/')}/{file.Name}";
10: await context.Response.WriteAsync($"<li><a href='{href}'>{file.Name}</a></li>");
11: }
12: await context.Response.WriteAsync("</ul></body></html>");
13: }
14: }
15:
16: public class Program
17: {
18: public static void Main()
19: {
20: new WebHostBuilder()
21: .UseContentRoot(Directory.GetCurrentDirectory())
22: .UseKestrel()
23: .Configure(app => app.UseDirectoryBrowser(new DirectoryBrowserOptions {Formatter = new ListDirectoryFormatter()}))
24: .Build()
25: .Run();
26: }
27: }
如上面的代码片段,ListDirectoryFormatter最终响应的是一个完整的HTML文档,它的主体部分只包含一个通过<ul>…</ul>表示的无序列表。列表元素(<li>)是一个针对文件或者子目录的链接。在调用扩展方法UseDirectoryBrowser注册DirectoryBrowserMiddleware中间件的时候,我们为将一个ListDirectoryFormatter对象设置为DirectoryBrowserOptions的Formatter属性。目录内容最终将会采用如图9所示的形式呈现在浏览器上。

ASP.NET Core应用针对静态文件请求的处理[1]: 以Web的形式发布静态文件
ASP.NET Core应用针对静态文件请求的处理[2]: 条件请求与区间请求
ASP.NET Core应用针对静态文件请求的处理[3]: StaticFileMiddleware中间件如何处理针对文件请求
ASP.NET Core应用针对静态文件请求的处理[4]: DirectoryBrowserMiddleware中间件如何呈现目录结构
ASP.NET Core应用针对静态文件请求的处理[5]: DefaultFilesMiddleware中间件如何显示默认页面
ASP.NET Core应用针对静态文件请求的处理[4]: DirectoryBrowserMiddleware中间件如何呈现目录结构的更多相关文章
- ASP.NET Core应用针对静态文件请求的处理[5]: DefaultFilesMiddleware中间件如何显示默认页面
DefaultFilesMiddleware中间件的目的在于将目标目录下的默认文件作为响应内容.我们知道,如果直接请求的就是这个默认文件,那么前面介绍的StaticFileMiddleware中间件会 ...
- ASP.NET Core应用针对静态文件请求的处理[3]: StaticFileMiddleware中间件如何处理针对文件请求
我们通过<以Web的形式发布静态文件>和<条件请求与区间请求>中的实例演示,以及上面针对条件请求和区间请求的介绍,从提供的功能和特性的角度对这个名为StaticFileMidd ...
- ASP.NET Core应用针对静态文件请求的处理[2]: 条件请求与区间请求
通过调用ApplicationBuilder的扩展方法UseStaticFiles注册的StaticFileMiddleware中间件帮助我们处理针对文件的请求.对于StaticFileMiddlew ...
- ASP.NET Core应用针对静态文件请求的处理[1]: 以Web的形式发布静态文件
虽然ASP.NET Core是一款"动态"的Web服务端框架,但是在很多情况下都需要处理针对静态文件的请求,最为常见的就是这对JavaScript脚本文件.CSS样式文件和图片文件 ...
- ASP.NET Core 1.1 静态文件、路由、自定义中间件、身份验证简介
概述 之前写过一篇关于<ASP.NET Core 1.0 静态文件.路由.自定义中间件.身份验证简介>的文章,主要介绍了ASP.NET Core中StaticFile.Middleware ...
- (5)ASP.NET Core 中的静态文件
1.前言 当我们创建Core项目的时候,Web根目录下会有个wwwroot文件目录,wwwroot文件目录里面默认有HTML.CSS.IMG.JavaScript等文件,而这些文件都是Core提供给客 ...
- asp.net core 系列之静态文件
这篇讲解asp.net core中的静态文件(大致翻译于官网). 静态文件,例如HTML,CSS, images和JavaScript. 要想直接被客户端访问,需要做一些配置. 一.Serve sta ...
- Asp.Net Core 中的静态文件
Asp.Net Core 中的静态文件 在这节中我们将讨论如何使 ASP.NET Core 应用程序,支持静态文件,如 HTML,图像,CSS 和 JavaScript 文件. 静态文件 默认情况下, ...
- ASP.NET Core 1.0 静态文件、路由、自定义中间件、身份验证简介
概述 ASP.NET Core 1.0是ASP.NET的一个重要的重新设计. 例如,在ASP.NET Core中,使用Middleware编写请求管道. ASP.NET Core中间件对HttpCon ...
随机推荐
- 探索ASP.NET MVC5系列之~~~4.模型篇---包含模型常用特性和过度提交防御
其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...
- 05.LoT.UI 前后台通用框架分解系列之——漂亮的时间选择器
LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/du ...
- HTML BOM Browser对象
BOM:Browser Object Model,即浏览器对象模型,提供了独立于内容的.可以与浏览器窗口进行互动的对象结构. Browser对象:指BOM提供的多个对象,包括:Window.Navig ...
- 富文本编辑器Simditor的简易使用
最近打算自己做一个博客系统,并不打算使用帝国cms或者wordpress之类的做后台管理!自己处于学习阶段也就想把从前台到后台一起谢了.好了,废话不多说了,先来看看富文本编辑器SimDitor,这里是 ...
- centos7+mono4+jexus5.6.2安装过程中的遇到的问题
过程参考: http://www.linuxdot.net/ http://www.jexus.org/ http://www.mono-project.com/docs/getting-starte ...
- 在ubuntu16.10 PHP测试连接MySQL中出现Call to undefined function: mysql_connect()
1.问题: 测试php7.0 链接mysql数据库的时候发生错误: Fatal error: Uncaught Error: Call to undefined function mysqli_con ...
- 再部署一个 instance 和 Local Network - 每天5分钟玩转 OpenStack(131)
上一节部署了 cirros-vm1 到 first_local_net,今天我们将再部署 cirros-vm2 到同一网络,并创建 second_local_net. 连接第二个 instance 到 ...
- app引导页(背景图片切换加各个页面动画效果)
前言:不知不觉中又加班到了10点半,整个启动页面做了一天多的时间,一共有三个页面,每个页面都有动画效果,动画效果调试起来麻烦,既要跟ios统一,又要匹配各种不同的手机,然后产品经理还有可能在中途改需求 ...
- 【转】为什么我们都理解错了HTTP中GET与POST的区别
GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二. 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数. 你可能自己 ...
- iOS从零开始学习直播之3.美颜
任何一款直播软件都必须进行美颜,不然哪来的那么多美女,所以技术改变世界,不只是说说而已.美颜在采集的时候就得就行,让主播实时看到直播的效果. 1.美颜原理 其实美颜的本质就是美白和磨皮,分别通 ...