Asp.Net Core 中的“虚拟目录”

写在前面

现在部署Asp.Net Core应用已经不再限制于Windows的IIS上,更多的是Docker容器、各种反向代理来部署。也有少部分用IIS部署的,IIS部署确实是又快又简单,图形化操作三下五除二就可以发布好一个系统了。在过去Asp.Net MVC 项目部署的时候,还常常使用IIS一个功能——虚拟目录

虚拟目录可以直接定位到非项目的其他路径,将路径作为网站的一部分,可实现上传文件保存到其他盘符或间接的使用项目以外的静态文件。在Asp.Net MVC中从虚拟路径中存取文件也很简单,如 

Server.MapPath("~/Upload/liohuang.jpg");

但在Asp.Net Core上不同,它被抽象出一个“文件系统”,也就是FileProvider。FileProvider是对所有实现了IFileProvider接口的所有类型以及对应对象的统称,文件系统在Artech蒋老师的《.NET Core的文件系统[2]:FileProvider是个什么东西?》文章中已经透析了,这里不在罗里吧嗦了。

这篇文章要解决的内容是:Asp.Net Core应用中,如何优雅的使用“虚拟目录”。

实操

首先,新建一个.Net Core WebApi空项目部署在D盘,“虚拟目录”假设物理路径在F盘,分别创建三个测试目录 F:/test1 、 F:/test2 和 F:/test3 ,目录里分别存放对应的文件1/2/3.jpg 和 mybook.txt 。

读取虚拟目录文件

在 Startup.ConfigureServices 注入 IFileProvider :

services.AddSingleton<IFileProvider>(new PhysicalFileProvider("F:\\test1"));

新建一个控制器,读取 mybook.txt 中的内容:

[ApiController]
[Route("[controller]/[action]")]
public class LioHuangController : ControllerBase
{[HttpGet]public object GetFiles([FromServices]IFileProvider fileProvider){var file = fileProvider.GetFileInfo("mybook.txt");if (file.Exists){return ReadTxtContent(file.PhysicalPath);}return 0;}/// <summary>/// 读取文本/// </summary>private string ReadTxtContent(string Path){if (!System.IO.File.Exists(Path)){return "Not found!";}using (StreamReader sr = new StreamReader(Path, Encoding.UTF8)){StringBuilder sb = new StringBuilder();string content;while ((content = sr.ReadLine()) != null){sb.Append(content);}return sb.ToString();}}
}

访问接口,接口读取文件之后,返回内容:

IFileProvider 接口采用目录来组织文件,并统一使用 IFileInfo 接口来表示, PhysicalPath 表示文件的物理路径。

public interface IFileInfo
{bool Exists { get; }bool IsDirectory { get; }DateTimeOffset LastModified { get; }string Name { get; }string PhysicalPath { get; }Stream CreateReadStream();
}

如多个虚拟目录,怎么处理?简单,注入多个 IFileProvider 即可:

services.AddSingleton<IFileProvider>(new PhysicalFileProvider("F:\\test1"));
services.AddSingleton<IFileProvider>(new PhysicalFileProvider("F:\\test2"));
services.AddSingleton<IFileProvider>(new PhysicalFileProvider("F:\\test3"));

代码修改为:

public object GetFiles([FromServices] IEnumerable<IFileProvider> fileProviders)

IEnumerable<IFileProvider> fileProviders 接口数组将会有三个,按注入的顺序对应不同的目录。当然,注入 IFileProvider 的时候,就可以封装一层了,下面再讲。

另外,有的说直接 ReadTxtContent("F:\test1\mybook.txt"); 不香吗?香,Asp.Net Core的访问权限要比Asp.Net MVC之前老版本项目要高许多,确实是可以直接读取项目以外的文件,但是并不适合直接去访问,除非说你只有一个地方使用到,那么就可以直接读取,但静态的文件的访问,就访问不到了,仅仅是后台读取而已。所以统一使用 IFileProvider 来约束,代码的可维护性要高许多。

静态文件访问

  在Startup.Configure设置静态文件目录,即可:

app.UseStaticFiles(new StaticFileOptions()
{FileProvider = new PhysicalFileProvider("F:\\test1"),RequestPath = "/test"
});;
app.UseStaticFiles(new StaticFileOptions()
{FileProvider = new PhysicalFileProvider("F:\\test2"),RequestPath = "/test"
});
app.UseStaticFiles(new StaticFileOptions()
{FileProvider = new PhysicalFileProvider("F:\\test3"),RequestPath = "/test"
});

 FileProvider 同上面所说的,设置好物理路径的根目录, RequestPath 则是访问路径的前缀,必须是斜杆 “/” 开头,访问地址前缀则为:

 https://localhost:5001/test/ 

设置好之后,就可以访问项目以外的路径了。

如在IIS部署的时候 ,可以直接忽略IIS中的虚拟目录设置,完完全全可以通过注入的配置来设置达到“虚拟目录”的效果。

简化配置

为了方便达到真实项目中可以直接使用,那么就要设置为可配置的。

在 appsettings.json 中设置:

{"Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"}},"AllowedHosts": "*","VirtualPath": [{"RealPath": "F:\\test1", //真实路径"RequestPath": "/test","Alias": "first"},{"RealPath": "F:\\test2", //真实路径"RequestPath": "/test","Alias": "second"},{"RealPath": "F:\\test3", //真实路径"RequestPath": "/test","Alias": "third"}]
}

创建对应的实体映射:

public class VirtualPathConfig
{public List<PathContent> VirtualPath { get; set; }
}public class PathContent
{public string RealPath { get; set; }public string RequestPath { get; set; }public string Alias { get; set; }
}

在 PhysicalFileProvider 上封装一层,加入别名便于获取:

public class MyFileProvider : PhysicalFileProvider
{public MyFileProvider(string root, string alias) : base(root){this.Alias = alias;}public MyFileProvider(string root, Microsoft.Extensions.FileProviders.Physical.ExclusionFilters filters, string alias) : base(root, filters){this.Alias = alias;}/// <summary>/// 别名/// </summary>public string Alias { get; set; }
}

调整 Startup.ConfigureServices 和 Startup.Configure :

public void ConfigureServices(IServiceCollection services)
{services.AddControllers();services.Configure<VirtualPathConfig>(Configuration);var config = Configuration.Get<VirtualPathConfig>().VirtualPath;config.ForEach(f => {services.AddSingleton(new MyFileProvider(f.RealPath,f.Alias));});
}public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}var config = Configuration.Get<VirtualPathConfig>().VirtualPath;config.ForEach(f =>{app.UseStaticFiles(new StaticFileOptions(){FileProvider = new PhysicalFileProvider(f.RealPath),RequestPath =f.RequestPath});});app.UseRouting();app.UseAuthorization();app.UseEndpoints(endpoints =>{endpoints.MapControllers();});
}

最后,调整调用方式,即可。

最后

物理文件系统的抽象通过 PhysicalFileProvider 这个 FileProvider 来实现,借助 IFileProvider 的特点,其实可以扩展实现轻量“云盘”的功能了,而不仅仅只是实现IIS虚拟目录功能。搞定,今晚不加班!

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

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

相关文章

[mybatis]缓存_缓存有关的设置以及属性

缓存有关的设置以及属性 全局配置中的设置 和缓存有关的设置/属性1.cacheEnabletrue&#xff1b;false&#xff1b;关闭缓存(二级缓存关闭)(一级缓存一直可用的)2.每个select标签都有useCache“true”&#xff1b; false&#xff1b;不使用缓存(一级缓存依然使用&#xff0c;二…

EF批量插入太慢?那是你的姿势不对

大概所有的程序员应该都接触过批量插入的场景&#xff0c;我也相信任何的程序员都能写出可正常运行的批量插入的代码。但怎样实现一个高效、快速插入的批量插入功能呢&#xff1f;由于每个人的工作履历&#xff0c;工作年限的不同&#xff0c;在实现这样的一个需求时&#xff0…

[RabbitMQ]什么是MQ

什么是MQ MQ(message queue)&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是message 而已&#xff0c;还是一种跨进程的通信机制&#xff0c;用于上下游传递消息。在互联网架构中&#xff0c;MQ 是一种非常…

.NET Core 实现基于Websocket的在线聊天室

什么是Websocket我们在传统的客户端程序要实现实时双工通讯第一想到的技术就是socket通讯&#xff0c;但是在web体系是用不了socket通讯技术的&#xff0c;因为http被设计成无状态&#xff0c;每次跟服务器通讯完成后就会断开连接。在没有websocket之前web系统如果要做双工通讯…

用 Natasha 写个类型调用的架子

一、想法自上篇文章&#xff0c;我一直琢磨整个好点的例子来展示 Natasha 动态编程能力, 于是就写了一个简单的类型调用的架子&#xff0c;耗时40分钟左右, 项目地址&#xff1a;https://github.com/NMSAzulX/TypeCaller二、功能特点a)、简单的注入功能支持无参构造注入支持递…

Natasha v4.0.0.0 动态编程新篇章

一、简介Natasha 基于 Roslyn 的 C# 动态程序集构建库&#xff0c;该库允许开发者在运行时使用 C# 代码构建域 / 程序集 / 类 / 结构体 / 枚举 / 接口 / 方法等&#xff0c;使得程序在运行的时候可以增加新的模块及功能。Natasha 集成了域管理/插件管理&#xff0c;可以实现域隔…

[RabbitMQ]RabbitMQ概念_四大核心概念

RabbitMQ RabbitMQ 的概念 RabbitMQ 是一个消息中间件&#xff1a;它接受并转发消息。你可以把它当做一个快递站点&#xff0c;当你要发送一个包裹时&#xff0c;你把你的包裹放到快递站&#xff0c;快递员最终会把你的快递送到收件人那里&#xff0c;按照这种逻辑 RabbitMQ …

.Net Core in Docker极简入门(下篇)

点击上方蓝字"小黑在哪里"关注我吧Docker-Compose代码修改yml fileup & down镜像仓库前言上一篇【.Net Core in Docker极简入门&#xff08;上篇&#xff09;】讲解了docker的一些基本命令和操作&#xff0c;并成功构建了自己的asp.net core web应用的镜像&#…

这么多Apache顶级项目,SkyWalking为何一枝独秀?

吴晟读完需要5分钟速读仅需 2 分钟吴晟Apache基金会会员&#xff0c;Apache SkyWalking创始人、项目VP和PMC成员&#xff0c;Apache孵化器PMC成员&#xff0c;Apache ShardingSphere PMC成员&#xff0c;Apache APISIX (incubating) PPMC成员&#xff0c;Apache ECharts (incub…

[RabbitMQ]工作原理_原理名词解释

RabbitMQ 核心部分 各个名词介绍 RabbitMQ工作原理 Broker&#xff1a; 接收和分发消息的应用&#xff0c;RabbitMQ Server 就是 Message Broker Virtual host&#xff1a; 出于多租户和安全因素设计的&#xff0c;把 AMQP 的基本组件划分到一个虚拟的分组中&#xff0c;类…

Istio 中的授权策略详解

本文节选自 ServiceMesher 社区出品的开源电子书《Istio Handbook——Istio 服务网格进阶实践》&#xff0c;阅读地址&#xff1a;https://www.servicemesher.com/istio-handbook/授权功能是 Istio 中安全体系的一个重要组成部分&#xff0c;它用来实现访问控制的功能&#xff…

[RabbitMQ]创建Java开发环境_消费者_生产者

我们将用 Java 编写两个程序。发送单个消息的生产者和接收消息并打印出来的消费者。我们将介绍 Java API 中的一些细节。 在下图中&#xff0c;“ P”是我们的生产者&#xff0c;“ C”是我们的消费者。中间的框是一个队列-RabbitMQ 代表使用者保留的消息缓冲区 引入依赖 <…

如何利用Gitlab-CI持续部署到远程机器?

长话短说&#xff0c;今天聊一聊使用Gitlab-CI 自动部署到远程服务器。如果看过《基于docker-compose的Gitlab CI/CD实践&排坑指南》这篇文章的朋友&#xff0c;会注意到我是在 Gitlab-Runner服务器上自动部署的站点&#xff0c;本次我们结合ssh部署到远程机器(将CI服务器和…

[RabbitMQ]工作队列原理_代码实现

Work Queues 工作队列(又称任务队列)的主要思想是避免立即执行资源密集型任务&#xff0c;而不得不等待它完成。 相反我们安排任务在之后执行。我们把任务封装为消息并将其发送到队列。在后台运行的工作进程将弹出任务并最终执行作业。当有多个工作线程时&#xff0c;这些工作…

使用ImpromptuInterface反射方便的创建自定义DfaGraphWriter

在本文中&#xff0c;我为创建的自定义的DfaGraphWriter实现奠定了基础。DfaGraphWriter是公开的&#xff0c;因此您可以如上一篇文章《将终结点图添加到你的ASP.NET Core应用程序中》中所示在应用程序中使用它&#xff0c;但它使用的所有类均已标记为internal。这使得创建自己…

[RabbitMQ]消息应答概念_消息手动应答代码

消息应答 概念 消费者完成一个任务可能需要一段时间&#xff0c;如果其中一个消费者处理一个长的任务并仅只完成了部分突然它挂掉了&#xff0c;会发生什么情况。RabbitMQ 一旦向消费者传递了一条消息&#xff0c;便立即将该消 息标记为删除。在这种情况下&#xff0c;突然有…

rust火箭基地主楼开启方法_Rust 为什么能成为 Stack Overflow 最受欢迎的语言?

每年&#xff0c;开发者问答网站 Stack Overflow 都会对程序员社区展开年度调查&#xff0c;包括他们最喜爱的技术到工作偏好的所有内容。 在2017 年和2018 年Stack Overflow 年度开发者调查中&#xff0c;Rust语言已经连续两年成为最受欢迎语言Top 1。2018 年 Stack Overflow …

[RabbitMQ]队列持久化

RabbitMQ持久化 概念 如何保障当 RabbitMQ 服务停掉以后消息生产者发送过来的消息不丢失。默认情况下 RabbitMQ 退出或由于某种原因崩溃时&#xff0c;它忽视队列和消息&#xff0c;除非告知它不要这样做。确保消息不会丢失需要做两件事&#xff1a;我们需要将队列和消息都标…

微服务认证架构如何演进来的?

【答疑解惑】| 作者 / Edison Zhou这是恰童鞋骚年的第267篇原创内容之前有同事问为何要用基于JWT令牌的认证架构&#xff0c;然后近期又有童鞋在后台留言问微服务安全认证架构的实践&#xff0c;因此我决定花两篇推文来解答一下。为了答好这个话题&#xff0c;我们先来看看微服…

maskrcnn还可以加网络吗_绿茶加蜂蜜的功效,绿茶可以加蜂蜜吗?

绿茶是我国的主要茶类之一&#xff0c;是一种天然健康的饮料&#xff0c;蜂蜜也是一种营养丰富的滋补食品&#xff0c;有些人不喜欢绿茶的苦味&#xff0c;想放点蜂蜜中和一下&#xff0c;但是不知道能不能这样做。那么绿茶能不能加蜂蜜呢?蜂蜜的主要成分是葡萄糖、果糖&#…