前言

我们之前已经完成了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. Redis安装与运行讲解

    第一步:安装Redis 打开网址:https://github.com/MicrosoftArchive/redis/releases 因为版本比较多,最新版已经是3.2.100,我们选择3.0.50 ...

  2. python3 读取chrome浏览器cookies

    原文链接:https://www.cnblogs.com/gayhub/p/pythongetcookiefromchrome.html 好几年前我在做一些自动化的脚本时,脑子里也闪过这样的想法:能不 ...

  3. 数据分析02 /pandas基础

    数据分析02 /pandas基础 目录 数据分析02 /pandas基础 1. pandas简介 2. Series 3. DataFrame 4. 总结: 1. pandas简介 numpy能够帮助 ...

  4. Python 实现邮件发送功能(初级)

    在我们日常项目中,会经常使用到邮件的发送功能,如何利用Python发送邮件也是一项必备的技能.本文主要讲述利用Python来发送邮件的一些基本操作. 本章主要包含知识点: 邮件发送原理简述即常用smt ...

  5. Unity-Editor

    Undo.RecordObject [MenuItem("Example/Random Rotate")] static void RandomRotate() { var tra ...

  6. 简易防止U盘中毒

    1.将U盘插入电脑,打开u盘 2.在U盘里面新建一个文本文档,将文本文档重命名autorun.inf保存完成. 3.为了防止误删次文件可以将属性设为影藏,就完成了.

  7. ajax+jquery+JSON笔记

    ajax (asynchronous javascript and xml -- 基于javascript和xml的异同步通讯技术)    特征: 异步通讯  异步的请求-响应模式     1.传统的 ...

  8. Python Ethical Hacking - BeEF Framework(2)

    Basic BeEF commands: Login the BeEF Control Panel, and go to Commands page. Create Alert Dialog: Run ...

  9. 【原创】linux设备模型之kset/kobj/ktype分析

    背 景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本 ...

  10. CSS:有点难的面试题①

    1 举例说明匿名块框和匿名行内框2 什么是标准文档流?3 inline-block遵循怎样的渲染规则?4 什么是BFC?如何触发BFC?5 什么是Line box?(最好画图说明) 6 <met ...