前言

我们之前已经完成了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. day53 作业

    写一个博客首页 <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...

  2. 技术干货丨通过wrap malloc定位C/C++的内存泄漏问题

    摘要:用C/C++开发的程序执行效率很高,但却经常受到内存泄漏的困扰.本文提供一种通过wrap malloc查找memory leak的思路. 用C/C++开发的程序执行效率很高,但却经常受到内存泄漏 ...

  3. java 面向对象(六):类结构 方法(三) java的值传递机制

    java的值传递机制 1.针对于方法内变量的赋值举例: System.out.println("***********基本数据类型:****************"); int ...

  4. javascript基础(六): 获取节点实例 jquery获取当前节点的前一个节点

    jquery获取当前节点的前一个节点步骤如下: 1.打开html开发工具,新建一来个html代码页面. 2.在html页面创建三个p标签,然后给这三个p标签设置不同的2113内容. 3.引入jquer ...

  5. scrapy 源码解析 (一):启动流程源码分析(一)命令行启动

    前言 虽然爬虫的入门级编写并不难,但要让爬虫真正稳定可靠的运行起来,真不是一件容易的事.首先,要用到scrapy,就必须要读懂scrapy这个爬虫框架,如果连这个框架的执行逻辑都搞不懂,那么爬虫也很难 ...

  6. vue 修改浏览器标题

    主要思路: 1.可以从路由获取当前页面的标题,再通过document.title设值,或者在最外层的index.html页面添加<title>标签 import router from ' ...

  7. Ethical Hacking - POST EXPLOITATION(2)

    MAINTAINING ACCESS - Methods 1. Using a veil-evasion Rev_http_service Rev_tcp_service Use it instead ...

  8. 集训作业 洛谷P1017 进制转换

    这个题的题目真的太恶心了. 重点是他的题目描述和他的目标没啥关系. 和最终目的有关系的只有这么一句话:”输出此负进制数及其基数,若此基数超过10,则参照16进制的方法处理.“ 我们通过看这句话可以发现 ...

  9. JavaScript动画实例:粒子文本

    1.粒子文本的实现原理 粒子文本的实现原理是:使用两张 canvas,一张是用户看不到的canvas1,用来绘制文本:另一张是用户看到的canvas2,用来根据canvas1中绘制的文本数据来生成粒子 ...

  10. jupyter中%matplotlib inline报错

    学习matplotlib时,使用的jupyter跑代码.报错如上图.大致就是后面的注释不能被识别.我寻思着注释不用识别吧,大概是因为%后跟的语句被全部当成命令行执行了,然后命令行不识别行内注释,导致报 ...