SeaweedFS在.net core下的实践方案(续一)
前言
我们之前已经完成了SeaweedFS在.net core下的使用了,但是说实话,还是不够,于是,我的目光盯住了IApplicationBuilder的扩展方法UseStaticFiles
这个可是好东西啊,我们访问资源的静态文件映射,你懂我的意思吧,对这里下手~
前戏
开工之前,我们转到定义看看
StaticFileOptions,这个就是我们自定义乱嗨的前提
它有两个,我们DIY需要用到的参数
RequestPath、FileProvider
顾名思义,前者是访问路径的前置地址
RequestPath的值是wwwroot,那么我们访问
http://url/wwwroot/XX.后缀 才会触发这个,而且,一定要是带后缀的才触发
后者是,前置地址触发的基础上才调用的
我们给他安排一下
实现
因为核心参数FileProvider类型为IFileProvider,所以,我们写一个实现类吧
public class SeaweedFSFileProvider : IFileProvider
{
public IDirectoryContents GetDirectoryContents(string subpath)
{
throw new NotImplementedException();
} public IFileInfo GetFileInfo(string subpath)
{
throw new NotImplementedException();
} public IChangeToken Watch(string filter)
{
throw new NotImplementedException();
}
}
我们现在需要用到的是GetFileInfo这个方法,另外两个,并不会触发(严谨一点说,GetDirectoryContents,我们访问无论是资源目录路径,还是完整的资源路径,都不会触发)
比如我们wwwroot这个文件夹是资源路径
无论是
http://url/wwwroot/ 还是 http://url/wwwroot,都不触发
这个也没触发~
emmmmm,可能研究太浅了,这两个接口方法是给其他实现类提供的定制化功能?比如FileServer?
GetFileInfo方法的返回值是IFileInfo
这个接口,触发文件返回的顺序是
Exists属性->Length属性->LastModified属性->Exists属性->PhysicalPath属性->CreateReadStream方法
我们写一个实现
public class SeaweedFSFileInfo : IFileInfo
{
public bool Exists { get; set; } public long Length => new MemoryStream(Context).Length; public string PhysicalPath { get; set; } public string Name { get; set; } public DateTimeOffset LastModified { get; } public bool IsDirectory => false; private byte[] Context { get; } public SeaweedFSFileInfo()
{
} public SeaweedFSFileInfo(string physicalPath, byte[] context)
{
Context = context;
PhysicalPath = physicalPath;
Name = Path.GetFileName(PhysicalPath);
LastModified = DateTimeOffset.Now;
Exists = true;
} public Stream CreateReadStream()
{
return new MemoryStream(Context);
}
}
我们修改一下SeaweedFSFileProvider,这里注入一个IFileService
因为我们希望整个SeaweedFSFileProvider他只依赖于IFileService,而不过多依赖SeaweedFS的实现,不会让代码简洁性受损
public class SeaweedFSFileProvider : IFileProvider
{
private IFileService Service { get; } public SeaweedFSFileProvider(IFileService service)
{
Service = service;
} public IDirectoryContents GetDirectoryContents(string subpath)
{
throw new NotImplementedException();
} public IFileInfo GetFileInfo(string subpath)
{
throw new NotImplementedException();
} public IChangeToken Watch(string filter)
{
throw new NotImplementedException();
}
}
我们转到接口IFileService,写一个接口
public interface IFileService
{
Task<SeaweedFSDirAssignModel> GetUploadFileUrlAsync(); Task<SeaweedFSUploadResponse> UploadFileAsync(string url,byte[] context); IFileInfo GetFileInfo(string subpath);
}
再转到实现类
增加这个实现
public IFileInfo GetFileInfo(string subpath)
{
throw new NotImplementedException();
}
我们去外层的SeaweedFSFileProvider修改一下
public class SeaweedFSFileProvider : IFileProvider
{
private IFileService Service { get; } public SeaweedFSFileProvider(IFileService service)
{
Service = service;
} public IDirectoryContents GetDirectoryContents(string subpath)
{
throw new NotImplementedException();
} public IFileInfo GetFileInfo(string subpath)
{
return Service.GetFileInfo(subpath);
} public IChangeToken Watch(string filter)
{
throw new NotImplementedException();
}
}
这样IFileService 里面变成什么样,都跟这层没关系了
我们定义一个IFileInfoFactory
public interface IFileInfoFactory
{
bool Contains(string filepath); IFileInfo GetFileInfo(string filepath); IFileInfo AddFileInfo(string filepath, byte[] context); IFileInfo AddNotExists(string filepath);
}
再写一个默认实现
public class FileInfoFactory: IFileInfoFactory
{
private List<IFileInfo> FileInfo { get; } = new List<IFileInfo>(); public bool Contains(string filepath)
{
return FileInfo.Any(file => file.PhysicalPath.Equals(filepath));
} public IFileInfo GetFileInfo(string filepath)
{
return FileInfo.FirstOrDefault(file => file.PhysicalPath.Equals(filepath));
} public IFileInfo AddFileInfo(string filepath,byte[] context)
{
var info = new SeaweedFSFileInfo(filepath, context);
FileInfo.Add(info); return info;
} public IFileInfo AddNotExists(string filepath)
{
var info = new SeaweedFSFileInfo();
FileInfo.Add(info); return info;
}
}
我们修改一下
SeaweedFSService的默认实现,增加一个注入IFileInfoFactory
private IFileInfoFactory FileInfoFactory { get; } public SeaweedFSService(IOptions<SeaweedFSServiceConfiguration> options, IFileInfoFactory fileInfoFactory)
{
Configuration = options.Value;
FileInfoFactory = fileInfoFactory;
}
我们实现一下
GetFileInfo方法
public IFileInfo GetFileInfo(string subpath)
{
using (var client = HttpClientFactory.Create())
{
var path = subpath.Replace(Path.GetExtension(subpath), "");
var splits = path.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (splits.Length == )
{
return FileInfoFactory.AddNotExists(subpath);
}
else
{
var fid = $"{splits[0]},{splits[1]}"; var response = client.GetAsync($"http://{Configuration.BaseUrl}/{fid}")
.GetAwaiter()
.GetResult(); if (response.StatusCode == HttpStatusCode.NotFound)
{
return FileInfoFactory.AddNotExists(subpath);
}
else
{
var context = response.Content;
var bytes = context.ReadAsByteArrayAsync()
.GetAwaiter()
.GetResult(); if (FileInfoFactory.Contains(subpath))
{
return FileInfoFactory.GetFileInfo(subpath);
}
else
{
return FileInfoFactory.AddFileInfo(subpath, bytes);
}
}
}
}
}
这个时候,我们测试一下
大功告成,撒花
优化
但是我们可能场景是这个文件上传了,就不再修改了,修改后文件,变成新路径,这样,文件就始终是静态的,那么这样反复http请求就没意义了
所以,我们修改一下
private SeaweedFSServiceConfiguration Configuration { get; }
private IFileInfoFactory FileInfoFactory { get; }
private IDistributedCache Cache { get; } public SeaweedFSService(IOptions<SeaweedFSServiceConfiguration> options, IFileInfoFactory fileInfoFactory, IDistributedCache cache)
{
Configuration = options.Value;
FileInfoFactory = fileInfoFactory;
Cache = cache;
}
增加了一个分布式缓存
我们就找这个缓存,能不能找到,还能找到,就说明已经缓存了这个文件信息,就不再走http
修改一下GetFileInfo
public IFileInfo GetFileInfo(string subpath)
{
var key = $"Distributed_Files_{subpath}"; var contextBytes = Cache.Get(key); if (contextBytes != null && FileInfoFactory.Contains(subpath))
{
return FileInfoFactory.GetFileInfo(subpath);
}
else
{
using (var client = HttpClientFactory.Create())
{
var path = subpath.Replace(Path.GetExtension(subpath), "");
var splits = path.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); Cache.Set(key, new byte[] { }); if (splits.Length == )
{
return FileInfoFactory.AddNotExists(subpath);
}
else
{
var fid = $"{splits[0]},{splits[1]}"; var response = client.GetAsync($"http://{Configuration.BaseUrl}/{fid}")
.GetAwaiter()
.GetResult(); if (response.StatusCode == HttpStatusCode.NotFound)
{
return FileInfoFactory.AddNotExists(subpath);
}
else
{
var context = response.Content;
var bytes = context.ReadAsByteArrayAsync()
.GetAwaiter()
.GetResult(); if (FileInfoFactory.Contains(subpath))
{
return FileInfoFactory.GetFileInfo(subpath);
}
else
{
return FileInfoFactory.AddFileInfo(subpath, bytes);
}
}
}
}
}
}
这样访问的地址,缓存没失效之前,并且在文件缓存里面,就不再走http请求了
附
我们附上入口的代码
ConfigureServices方法内增加
services.AddDistributedMemoryCache();
这样就启用了默认的分布式缓存接口,后期要替换的实现,只用更换这里的具体实现就好了,我们不依赖具体实现
Configure方法内增加代码
using (var services = app.ApplicationServices.CreateScope())
{
var fileService = services.ServiceProvider.GetRequiredService<IFileService>(); app.UseStaticFiles(
new StaticFileOptions
{
RequestPath = "/Resource",
FileProvider = new SeaweedFSFileProvider(fileService)
}
);
}
SeaweedFS在.net core下的实践方案(续一)的更多相关文章
- SeaweedFS在.net core下的实践方案
一直对分布式的文件储存系统很感兴趣,最开始关注淘宝的TFS(Taobao File System),好像搁浅了,官方地址无法访问,github上面,各种编译问题,无意间发现了SeaweedFS 链接s ...
- 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生
[转].NET(C#):浅谈程序集清单资源和RESX资源 目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...
- .net core下简单构建高可用服务集群
一说到集群服务相信对普通开发者来说肯定想到很复杂的事情,如zeekeeper ,反向代理服务网关等一系列的搭建和配置等等:总得来说需要有一定经验和规划的团队才能应用起来.在这文章里你能看到在.net ...
- .Net core下的配置设置(二)——Option
我在前面的文章.Net core下的配置设置(一)——Configuration中介绍了.net core下配置文件的读取方法,在.net core中,直接从Configuration对象中读取的并不 ...
- 基于OVS的VLAN虚拟化简易实践方案
基于OVS的VLAN虚拟化简易实践方案 前言 本实验基于ovs的vlan流表匹配,根据端口进行vlan标签插入.手工配置ovs,使其具有vlan虚拟化方案. 实验拓扑 ---- ---- | h1 | ...
- .net core 下使用StackExchange的Redis库访问超时解决
原文:.net core 下使用StackExchange的Redis库访问超时解决 目录 问题:并发稍微多的情况下Redis偶尔返回超时 给出了参考网址? 结论 小备注 引用链接 问题:并发稍微多的 ...
- .NET CORE下最快比较两个文件内容是否相同的方法 - 续
.NET CORE下最快比较两个文件内容是否相同的方法 - 续 在上一篇博文中, 我使用了几种方法试图找到哪个是.NET CORE下最快比较两个文件的方法.文章发布后,引起了很多博友的讨论, 在此我对 ...
- .NET Core 下的 API 网关
网关介绍 网关其实就是将我们写好的API全部放在一个统一的地址暴露在公网,提供访问的一个入口.在 .NET Core下可以使用Ocelot来帮助我们很方便的接入API 网关.与之类似的库还有Proxy ...
- nginx及其常用实践方案
nginx及其常用实践方案 1.概述 1.1 什么是nginx? 1.2 什么是反向代理? 2.nginx常用命令 3.ningx配置实践 3.1 nginx.conf基础配置项 3.2 http 反 ...
随机推荐
- Windows下生成IOS证书并发布APP安装到IPhone
目录: 一:生成证书 二:安装到IPhone 准备环境: 1.Appuploader(需要安装Java环境) 2.爱思助手 一.生成证书 1.1.打开appuploader后登陆开发者账号 1.2.点 ...
- CTFHub_技能树_SQL注入Ⅰ
SQL注入 布尔盲注 查看页面: 尝试输入测试信息: 提示为布尔注入,构造相应payload: ?id=1 and ascii(substr((select database()),1,1))> ...
- Python-01矩阵、数组和列表等的总结
python的基础知识总结 使用到了numpy库,所以第一步需要 import numpy as np 1.创建矩阵 1.1一般矩阵的创建 创建一个二维的矩阵,并使用ndim.shape.size分别 ...
- 前端01 /HTML简单简绍
前端01 /HTML简单简绍 目录 前端01 /HTML简单简绍 1.web服务本质 2.浏览器的工作流程 3.HTML是什么 4.web服务本质 5.HTML文档结构 6.HTML注释 6.标签语法 ...
- tensorboard学习笔记
TensorBoard 默认是不会记录每个节点的用时.耗费的内存大小等这些信息的,那么如何才能在图上显示这些信息呢?关键就是如下这些代码,主要就是在 sess.run() 中加入 options 和 ...
- How to start MySQL on Linux
启动MySQL数据库 service mysql start 查看MySQL进程 ps -ef |grep mysql 查看MySQL端口号 cd /etc/init.d/ netstat -atnp ...
- Python基础最难知识点:正则表达式(使用步骤)
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 正则表达式,简称regex,是文本模式的描述方法.你可以在google上搜 ...
- bzoj3687简单题*
bzoj3687简单题 题意: 给个集合,求所有子集的元素和的异或和.集合元素个数≤1000,整个集合的元素和≤2000000 题解: 用bitset维护每个子集元素和的个数是奇数还是偶数.每次读入一 ...
- C++语法小记---如何判断一个变量是不是指针
如何判断一个变量是不是指针? 思路:模板函数 + 可变参数 + sizeof(函数) #include <iostream> #include <string> using n ...
- 记一次css字体反爬
前段时间在看css反爬的时候,发现很多网站都做了css反爬,比如,设置字体反爬的(58同城租房版块,实习僧招聘https://www.shixiseng.com/等)设置雪碧图反爬的(自如租房http ...