IApplicationBuilderExtensions_UseStaticFiles.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. using Microsoft.AspNetCore.Builder;
  2. using Microsoft.AspNetCore.StaticFiles;
  3. using Microsoft.Extensions.FileProviders;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Threading.Tasks;
  9. using Vit.Core.Util.Common;
  10. using Vit.WebHost;
  11. namespace Vit.Extensions
  12. {
  13. public static partial class IApplicationBuilderExtensions_UseStaticFiles
  14. {
  15. /// <summary>
  16. /// 启用静态文件服务
  17. ///
  18. /// <example>
  19. /// <code>
  20. /// /* 映射静态文件。若不指定则不映射静态文件 */
  21. /// "staticFiles": {
  22. ///
  23. /// /* 请求路径(可不指定)。demo:"/file/static"。The relative request path that maps to static resources */
  24. /// //"requestPath": "/file",
  25. ///
  26. /// /* 静态文件路径。可为相对路径或绝对路径。若为空或空字符串则为默认路径(wwwroot)。demo:"wwwroot/demo" */
  27. /// //"rootPath": "wwwroot",
  28. ///
  29. /// /* 默认页面(可不指定)。An ordered list of file names to select by default. List length and ordering may affect performance */
  30. /// //"defaultFileNames": [],
  31. ///
  32. /// /* 是否可浏览目录(default false)。Enables directory browsing */
  33. /// //"useDirectoryBrowser": false,
  34. ///
  35. /// /* 静态文件类型映射配置的文件路径。可为相对路径或绝对路径。例如"contentTypeMap.json"。若不指定(或指定的文件不存在)则不指定文件类型映射配置 */
  36. /// "contentTypeMapFile": "contentTypeMap.json",
  37. ///
  38. /// /* 回应静态文件时额外添加的http回应头。可不指定。 */
  39. /// "responseHeaders": {
  40. ///
  41. /// //设置浏览器静态文件缓存3600秒
  42. /// "Cache-Control": "public,max-age=3600"
  43. /// }
  44. /// }
  45. ///
  46. /// </code>
  47. /// </example>
  48. ///
  49. /// </summary>
  50. /// <param name="data"></param>
  51. /// <param name="configPath">在appsettings.json文件中的路径。默认:"server.staticFiles"。</param>
  52. /// <returns></returns>
  53. public static IApplicationBuilder UseStaticFilesFromConfig(this IApplicationBuilder data, string configPath = "server.staticFiles")
  54. {
  55. return data.UseStaticFiles(Vit.Core.Util.ConfigurationManager.ConfigurationManager.Instance.GetByPath<Vit.WebHost.StaticFilesConfig>(configPath));
  56. }
  57. /// <summary>
  58. /// 启用静态文件服务
  59. ///
  60. /// <example>
  61. /// <code>
  62. /// /* 映射静态文件。若不指定则不映射静态文件 */
  63. /// "staticFiles": {
  64. ///
  65. /// /* 请求路径(可不指定)。demo:"/file/static"。The relative request path that maps to static resources */
  66. /// //"requestPath": "/file",
  67. ///
  68. /// /* 静态文件路径。可为相对路径或绝对路径。若为空或空字符串则为默认路径(wwwroot)。demo:"wwwroot/demo" */
  69. /// //"rootPath": "wwwroot",
  70. ///
  71. /// /* 默认页面(可不指定)。An ordered list of file names to select by default. List length and ordering may affect performance */
  72. /// //"defaultFileNames": [],
  73. ///
  74. /// /* 是否可浏览目录(default false)。Enables directory browsing */
  75. /// //"useDirectoryBrowser": false,
  76. ///
  77. /// /* 静态文件类型映射配置的文件路径。可为相对路径或绝对路径。例如"contentTypeMap.json"。若不指定(或指定的文件不存在)则不指定文件类型映射配置 */
  78. /// "contentTypeMapFile": "contentTypeMap.json",
  79. ///
  80. /// /* 回应静态文件时额外添加的http回应头。可不指定。 */
  81. /// "responseHeaders": {
  82. ///
  83. /// //设置浏览器静态文件缓存3600秒
  84. /// "Cache-Control": "public,max-age=3600"
  85. /// }
  86. /// }
  87. ///
  88. /// </code>
  89. /// </example>
  90. ///
  91. /// </summary>
  92. /// <param name="data"></param>
  93. /// <param name="config"></param>
  94. /// <returns></returns>
  95. public static IApplicationBuilder UseStaticFiles(this IApplicationBuilder data, StaticFilesConfig config)
  96. {
  97. if (config == null || data == null) return data;
  98. #region (x.1)UseStaticFiles
  99. var staticfileOptions = new StaticFileOptions();
  100. //(x.x.1)requestPath
  101. if (!string.IsNullOrEmpty(config.requestPath))
  102. {
  103. staticfileOptions.RequestPath = new Microsoft.AspNetCore.Http.PathString(config.requestPath);
  104. }
  105. #region (x.x.2)FileProvider
  106. IFileProvider fileProvider=null;
  107. string rootPath;
  108. if (!string.IsNullOrWhiteSpace(rootPath=config.rootPath) && Directory.Exists(rootPath))
  109. {
  110. fileProvider = new PhysicalFileProvider(rootPath);
  111. }
  112. else if (Directory.Exists(rootPath = CommonHelp.GetAbsPath("wwwroot")))
  113. {
  114. fileProvider = new PhysicalFileProvider(rootPath);
  115. }
  116. else
  117. {
  118. var dir = new DirectoryInfo("wwwroot");
  119. if(dir.Exists)
  120. fileProvider = new PhysicalFileProvider(dir.FullName);
  121. }
  122. staticfileOptions.FileProvider = fileProvider;
  123. #endregion
  124. //(x.x.3)OnInitStaticFileOptions
  125. config.OnInitStaticFileOptions?.Invoke(staticfileOptions);
  126. #region (x.x.4)Response Headers
  127. if (config.responseHeaders != null)
  128. {
  129. staticfileOptions.OnPrepareResponse +=
  130. ctx =>
  131. {
  132. var Headers = ctx.Context.Response.Headers;
  133. foreach (var kv in config.responseHeaders)
  134. {
  135. Headers[kv.Key] = kv.Value;
  136. }
  137. };
  138. }
  139. #endregion
  140. //(x.x.5)contentTypeProvider
  141. if (config.contentTypeProvider != null)
  142. {
  143. staticfileOptions.ContentTypeProvider = config.contentTypeProvider;
  144. }
  145. //(x.x.6)UseDefaultFiles
  146. if (config.defaultFileNames != null)
  147. {
  148. data.UseDefaultFiles(new DefaultFilesOptions
  149. {
  150. DefaultFileNames = config.defaultFileNames,
  151. FileProvider= fileProvider
  152. });
  153. }
  154. //(x.x.7)UseStaticFiles
  155. data.UseStaticFiles(staticfileOptions);
  156. #endregion
  157. //(x.2)UseDirectoryBrowser
  158. if (config.useDirectoryBrowser == true)
  159. {
  160. var options = new DirectoryBrowserOptions {
  161. RequestPath = staticfileOptions.RequestPath,
  162. FileProvider = fileProvider,
  163. Formatter = new SortedHtmlDirectoryFormatter()
  164. };
  165. data.UseDirectoryBrowser(options);
  166. }
  167. return data;
  168. }
  169. #region SortedHtmlDirectoryFormatter
  170. /// <summary>
  171. /// 自定义DirectoryFormatter
  172. /// https://www.cnblogs.com/artech/p/static-file-for-asp-net-core-04.html
  173. ///
  174. /// </summary>
  175. public class SortedHtmlDirectoryFormatter : HtmlDirectoryFormatter
  176. {
  177. /// <summary>
  178. /// 默认按文件名称排序。 contents => contents.OrderBy(f => f.Name)
  179. /// </summary>
  180. public Func<IEnumerable<IFileInfo>, IEnumerable<IFileInfo>> SetOrder = contents => contents.OrderBy(f => f.Name);
  181. public SortedHtmlDirectoryFormatter(System.Text.Encodings.Web.HtmlEncoder encoder = null) : base(encoder ?? System.Text.Encodings.Web.HtmlEncoder.Default)
  182. {
  183. }
  184. public override async Task GenerateContentAsync(Microsoft.AspNetCore.Http.HttpContext context, IEnumerable<IFileInfo> contents)
  185. {
  186. contents = SetOrder(contents);
  187. await base.GenerateContentAsync(context, contents);
  188. //context.Response.ContentType = "text/html";
  189. //await context.Response.WriteAsync("<html><head><title>Index</title><body><ul>");
  190. //foreach (var file in contents)
  191. //{
  192. // string href = $"{context.Request.Path.Value.TrimEnd('/')}/{file.Name}";
  193. // await context.Response.WriteAsync($"<li><a href='{href}'>{file.Name}</a></li>");
  194. //}
  195. //await context.Response.WriteAsync("</ul></body></html>");
  196. }
  197. }
  198. #endregion
  199. }
  200. }