• 《深入浅出.NET框架设计与实现》阅读笔记(四)


    静态文件系统


    通过ASP.NET Core 提供的静态文件模块和静态文件中间件,可以轻松的让应用程序拥有访问静态文件的功能,同时可以基于IFileProvider对象来自定义文件系统,如基于Redis做扩展文件系统

    启动静态文件服务

    Program.cs 类中,通过WebApplication的UseStaticFiles扩展方法启动。

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    app.UseStaticFiles();
    app.Run();
    
    • 1
    • 2
    • 3
    • 4

    默认存储目录(wwwroot)

    默认情况下,静态文件存储在项目的wwwroot目录下。
    在这里插入图片描述

    • 读取静态文件(以favicon.ico文件为例):https:// localhost:6379/favicon.ico
    • 读取静态文件(以README.md文件为例):https://localhost:6379/css/open-iconic/README.md

    增加自定义静态目录文件

    • 调用UseStaticFiles方法时传递StaticFileOptions配置参数。
    • StaticFileOptionsFileProvider为指定的文件夹路径
    • StaticFileOptionsRequestPath为请求路径的前缀
    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    //自定义静态文件目录
    StaticFileOptions fileOpt = new()
    {
        FileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),//指定文件夹目录
        RequestPath = "/StaticFiles"//自定义前缀
    };
    app.UseStaticFiles(fileOpt);
    app.Run();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 指定了在项目文件目录下的MyStaticFiles文件夹
      在这里插入图片描述
    • 通过路径来获取想要的文件(以用户手册.pdf为例):https://localhost:6379/StaticFiles/用户手册.pdf
      在这里插入图片描述

    自定义一个简单的文件系统

    在ASP.NET Core中,允许开发人员自定义文件系统,可以利用IFileProvider接口来构建文件系统。

    文件信息类(RedisFileInfo)

    public class RedisFileInfo : IFileInfo
    {
        /// 
        /// 判断目录或文件是否真的存在
        /// 
        public bool Exists { get; set; } = true;
        /// 
        /// 表示是目录还是文件
        /// 
        public bool IsDirectory { get; set; }
        /// 
        /// 文件或目录最后一次修改的时间
        /// 
        public DateTimeOffset LastModified { get; set; }
        /// 
        /// 表示文件内容的字节长度
        /// 
        public long Length => _fileContent.Length;
        /// 
        /// 表示文件或目录的名字
        /// 
        public string Name { get; set; }
        /// 
        /// 表示文件或目录的物理路径
        /// 
        public string PhysicalPath { get; set; }
    
        private readonly byte[] _fileContent;
        public Stream CreateReadStream()
        {
            var stream = new MemoryStream(_fileContent);
            stream.Position = 0;
            return stream;
        }
    
        public RedisFileInfo() { }
        public RedisFileInfo(string name, string content)
        {
            Name = name;
            LastModified = DateTimeOffset.Now;
            _fileContent = Convert.FromBase64String(content);
        }
        public RedisFileInfo(string name,bool isDirectory)
        {
            Name = name;
            LastModified = DateTimeOffset.Now; 
            IsDirectory = isDirectory;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    文件目录类(EnumerableDirectoryContents)

    public class EnumerableDirectoryContents : IDirectoryContents
    {
        private readonly IEnumerable<IFileInfo> _entries;
        public bool Exists => true;
    
        public EnumerableDirectoryContents(IEnumerable<IFileInfo> entries)
        {
            _entries = entries;
        }
    
        public IEnumerator<IFileInfo> GetEnumerator()
        {
            return _entries.GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Redis配置文件(RedisFileOptions)

    public class RedisFileOptions
    {
        /// 
        /// 配置Redius连接信息
        /// 
        public string HostAndPort { get; set; }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    文件系统逻辑处理类(RedisFileProvider)

        /// 
        /// Redis文件解析器,只要用于通过指定的名称从Redis中读取存储的图片内容
        /// 
    public class RedisFileProvider : IFileProvider
    {
        private readonly RedisFileOptions _options;
        private readonly ConnectionMultiplexer _redis;
    
        private static string NormalizePath(string path) => path.TrimStart('/').Replace('/', ':');
        /// 
        /// 参数为Ioptions的好处是可以使用Options.Create()方法来直接生成
        /// 
        /// 
        public RedisFileProvider(IOptions<RedisFileOptions> options)
        {
            _options = options.Value;
            _redis = ConnectionMultiplexer.Connect(new ConfigurationOptions
            {
                EndPoints = { _options.HostAndPort }
            });
        }
    
        /// 
        /// 获得指定的目录
        /// 
        /// 通过
        /// 
        /// 
        /// 
        /// 
        public IDirectoryContents GetDirectoryContents(string subpath)
        {
            
            var db = _redis.GetDatabase();
            var server = _redis.GetServer(_options.HostAndPort);
            var list = new List<IFileInfo>();
            subpath = NormalizePath(subpath);
            foreach (var key in server.Keys(0, $"{subpath}*"))
            {
                var k = "";
                if (subpath != "") k = key.ToString().Replace(subpath, "").Split(":")[0];
                else k = key.ToString().Split(":")[0];
                if (list.Find(f => f.Name == k) == null)
                {
                    //判断是否存在.
                    if (k.IndexOf('.', StringComparison.OrdinalIgnoreCase) >= 0)
                    {
                        list.Add(new RedisFileInfo(k, db.StringGet(k)));
                    }
                    else
                    {
                        list.Add(new RedisFileInfo(k, true));
                    }
                }
            }
            if (list.Count == 0)
            {
                return NotFoundDirectoryContents.Singleton;
            }
            return new EnumerableDirectoryContents(list);
        }
        /// 
        /// 得到指定目录或文件的IFileInfo对象
        /// 通过subpath参数值再Redis客户端读取文件信息。
        /// 
        /// 
        /// 
        /// 
        public IFileInfo GetFileInfo(string subpath)
        {
            subpath = NormalizePath(subpath);
            var db = _redis.GetDatabase();
            var redisValue = db.StringGet(subpath);
            return !redisValue.HasValue ? new NotFoundFileInfo(subpath) : new RedisFileInfo(subpath, redisValue.ToString());
        }
    
        public IChangeToken Watch(string filter)
        {
            throw new NotImplementedException();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    注入服务

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    //使用自定义文件系统
    StaticFileOptions fileOpt = new()
    {
        FileProvider = new RedisFileProvider(Options.Create(new RedisFileOptions
        {
            HostAndPort = "localhost:6379",
        }))
    };
    app.UseStaticFiles(fileOpt);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    Kubernetes简略架构
    AI学习指南机器学习篇-不同类型的朴素贝叶斯算法
    u盘就能用:RadiAnt DICOM Viewer CD/DVD 2023.1
    a标签下载文件与解决浏览器默认打开某些格式文件的问题
    刘畊宏男孩女孩看过来!运动数据分析挖掘!⛵
    Springboot+高校教材预订信息管理系统 毕业设计-附源码150905
    【odoo15】前端自定义模态弹窗
    LeetCode 416. 分割等和子集(dp背包问题)
    MMORPG网络游戏开发之Protobuf的基本使用
    Ubuntu安装ufw
  • 原文地址:https://blog.csdn.net/Oneal5354/article/details/134391158