这个中间件启用的重载方法和UseStaticFiles类似最终都是在传递DirectoryBrowserOptions,接下来我们就看DirectoryBrowserOptions传递了哪些信息[点击查看DirectoryBrowserOptions源码]
public class DirectoryBrowserOptions : SharedOptionsBase { public DirectoryBrowserOptions() : this(new SharedOptions()) { } public DirectoryBrowserOptions(SharedOptions sharedOptions) : base(sharedOptions) { } /// <summary> /// 目录格式化提供,默认是提供表格的形式展示,课自定义 /// </summary> public IDirectoryFormatter Formatter { get; set; } }无独有偶这个类和StaticFileOptions一样也是集成自SharedOptionsBase类,唯一多了IDirectoryFormatter操作,通过它我们可以自定义展示到页面的输出形式,接下来我们就重点看下DirectoryBrowserMiddleware中间件的实现
public class DirectoryBrowserMiddleware { private readonly DirectoryBrowserOptions _options; private readonly PathString _matchUrl; private readonly RequestDelegate _next; private readonly IDirectoryFormatter _formatter; private readonly IFileProvider _fileProvider; public DirectoryBrowserMiddleware(RequestDelegate next, IWebHostEnvironment hostingEnv, IOptions<DirectoryBrowserOptions> options) : this(next, hostingEnv, HtmlEncoder.Default, options) { } public DirectoryBrowserMiddleware(RequestDelegate next, IWebHostEnvironment hostingEnv, HtmlEncoder encoder, IOptions<DirectoryBrowserOptions> options) { _next = next; _options = options.Value; //默认是提供默认目录的访问程序 _fileProvider = _options.FileProvider ?? Helpers.ResolveFileProvider(hostingEnv); //默认传递的是HtmlDirectoryFormatter类型,也就是我们看到的输出表格的页面 _formatter = options.Value.Formatter ?? new HtmlDirectoryFormatter(encoder); _matchUrl = _options.RequestPath; } public Task Invoke(HttpContext context) { //1.IsGetOrHeadMethod判断是否为Get或Head请求 //2.TryMatchPath判断请求的路径和设置的路径是否可以匹配的上 //3.TryGetDirectoryInfo判断根据匹配出来的路径能否查找到真实的物理路径 if (context.GetEndpoint() == null && Helpers.IsGetOrHeadMethod(context.Request.Method) && Helpers.TryMatchPath(context, _matchUrl, forDirectory: true, subpath: out var subpath) && TryGetDirectoryInfo(subpath, out var contents)) { //判断请求路径是否是/为结尾 if (!Helpers.PathEndsInSlash(context.Request.Path)) { //如果不是以斜线结尾则重定向(个人感觉直接在服务端重定向就可以了,为啥还要返回浏览器在请求一次) context.Response.StatusCode = StatusCodes.Status301MovedPermanently; var request = context.Request; var redirect = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path + "http://www.likecs.com/", request.QueryString); context.Response.Headers[HeaderNames.Location] = redirect; return Task.CompletedTask; } //返回展示目录的内容 return _formatter.GenerateContentAsync(context, contents); } return _next(context); } /// <summary> /// 根据请求路径匹配到物理路径信息是否存在,存在则返回路径信息 /// </summary> private bool TryGetDirectoryInfo(PathString subpath, out IDirectoryContents contents) { contents = _fileProvider.GetDirectoryContents(subpath.Value); return contents.Exists; } }这个操作相对简单了许多,主要就是判断请求路径能否和预设置的路径匹配的到,如果匹配到则获取可以操作当前目录内容IDirectoryContents然后通过IDirectoryFormatter输出如何展示目录内容,关于IDirectoryFormatter的默认实现类HtmlDirectoryFormatter这里就不展示里面的代码了,逻辑非常的加单就是拼接成table的html代码然后输出,有兴趣的同学可自行查看源码[点击查看HtmlDirectoryFormatter源码],如果自定义的话规则也非常简单,主要看你想输出啥
public class TreeDirectoryFormatter: IDirectoryFormatter { public Task GenerateContentAsync(HttpContext context, IEnumerable<IFileInfo> contents) { //遍历contents实现你想展示的方式 } }然后在UseDirectoryBrowser的时候给Formatter赋值即可
app.UseDirectoryBrowser(new DirectoryBrowserOptions { Formatter = new TreeDirectoryFormatter() }); UseDefaultFiles