前言

我们之前已经完成了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下的实践方案(续一)的更多相关文章

  1. SeaweedFS在.net core下的实践方案

    一直对分布式的文件储存系统很感兴趣,最开始关注淘宝的TFS(Taobao File System),好像搁浅了,官方地址无法访问,github上面,各种编译问题,无意间发现了SeaweedFS 链接s ...

  2. 【转】.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 ...

  3. .net core下简单构建高可用服务集群

    一说到集群服务相信对普通开发者来说肯定想到很复杂的事情,如zeekeeper ,反向代理服务网关等一系列的搭建和配置等等:总得来说需要有一定经验和规划的团队才能应用起来.在这文章里你能看到在.net ...

  4. .Net core下的配置设置(二)——Option

    我在前面的文章.Net core下的配置设置(一)——Configuration中介绍了.net core下配置文件的读取方法,在.net core中,直接从Configuration对象中读取的并不 ...

  5. 基于OVS的VLAN虚拟化简易实践方案

    基于OVS的VLAN虚拟化简易实践方案 前言 本实验基于ovs的vlan流表匹配,根据端口进行vlan标签插入.手工配置ovs,使其具有vlan虚拟化方案. 实验拓扑 ---- ---- | h1 | ...

  6. .net core 下使用StackExchange的Redis库访问超时解决

    原文:.net core 下使用StackExchange的Redis库访问超时解决 目录 问题:并发稍微多的情况下Redis偶尔返回超时 给出了参考网址? 结论 小备注 引用链接 问题:并发稍微多的 ...

  7. .NET CORE下最快比较两个文件内容是否相同的方法 - 续

    .NET CORE下最快比较两个文件内容是否相同的方法 - 续 在上一篇博文中, 我使用了几种方法试图找到哪个是.NET CORE下最快比较两个文件的方法.文章发布后,引起了很多博友的讨论, 在此我对 ...

  8. .NET Core 下的 API 网关

    网关介绍 网关其实就是将我们写好的API全部放在一个统一的地址暴露在公网,提供访问的一个入口.在 .NET Core下可以使用Ocelot来帮助我们很方便的接入API 网关.与之类似的库还有Proxy ...

  9. nginx及其常用实践方案

    nginx及其常用实践方案 1.概述 1.1 什么是nginx? 1.2 什么是反向代理? 2.nginx常用命令 3.ningx配置实践 3.1 nginx.conf基础配置项 3.2 http 反 ...

随机推荐

  1. 选择困难症必看!云服务器如何选择操作系统,Windows和Linux哪个更好?

    在购买云服务器时,会有一个必选的配置,就是操作系统的选择,如何选择操作系统?操作系统选择错了怎么办?这是不少用户会遇到的问题,今天我们就来教大家如何选择操作系统,以及操作系统选择错了,该怎么切换. W ...

  2. CSS(二)- 选择器 - 一定要搞懂的选择器优先级和权重问题

    css的优先级之前一直没怎么注意没当回事,总以为对同一元素靠后的渲染会覆盖前面的渲染,要是覆盖不了那就来个!important嘛.直到我那在学前端基础的后端伙伴拿一个问题问住了我,我才意识到这是重点中 ...

  3. 基于html5拖拽api实现列表的拖拽排序

    基于html5拖拽api实现列表的拖拽排序 html代码: <ul ondrop="drop_handler(event);" ondragover="dragov ...

  4. redis(十):Redis 列表(List)

    Redis 列表(List) Redis列表是简单的字符串列表,按照插入顺序排序.你可以添加一个元素到列表的头部(左边)或者尾部(右边) 一个列表最多可以包含 232 - 1 个元素 (4294967 ...

  5. 京东秋招提前批初试--java开发工程师

    1,自我介绍,学过的课程有哪些 2,介绍一下java的内存结构和内存模型(jvm和jmm) 3,对于NIO有没有了解?作用是什么?(基于通道和缓冲区的I/O方式,用的是DirectByteBuffer ...

  6. 阅读手札 | 手把手带你探索『图解 HTTP』

    前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 Github 博客 学习清单: 一.网络基础 TCP/IP 通常使用的网络(包括互联网)是在 TCP/IP 协议族的基础上 ...

  7. 2019CSP-J T4 加工零件

    题目描述 凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇.工厂里有 n 位工人,工人们从 1 ∼n 编号.某些工人之间存在双向的零件传送带.保证每两名工人之间最多只存在一 ...

  8. 题解 CF13E 【Holes】

    这个题和$P3203\ $弹飞绵羊基本上完全一致 我的做法是用\(LCT\)维护信息,开一个节点\(fly\),表示到此节点时,小球会弹飞,那么查询弹多少次即为\(siz[fly]-1\) 最后一次落 ...

  9. ContiPerf

    概述 ContiPerf 是一个轻量级的单元测试工具,基于JUnit 4二次开发,使用它基于注解的方式,快速在本地进行单元压测并提供详细的报告. Example 1. 新建 SpringBoot 工程 ...

  10. 如何查看预收录在arXiv上论文的LaTeX源文件并编译

    arXiv 是一个收集物理学.数学.计算机科学与生物学论文预印本的网站. 对于理科生来说,经常需要在上面搜索下载一些论文,正常情况下,一般人下载的只是 pdf 文件,其实可以在 arXiv 上下载编译 ...