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

news/2024/7/24 8:02:40 标签: .net, 笔记

静态文件系统


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

启动静态文件服务

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

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseStaticFiles();
app.Run();

默认存储目录(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();
  • 指定了在项目文件目录下的MyStaticFiles文件夹
    在这里插入图片描述
  • 通过路径来获取想要的文件(以用户手册.pdf为例):https://localhost:6379/StaticFiles/用户手册.pdf
    在这里插入图片描述

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

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

文件信息类(RedisFileInfo)

public class RedisFileInfo : IFileInfo
{
    /// <summary>
    /// 判断目录或文件是否真的存在
    /// </summary>
    public bool Exists { get; set; } = true;
    /// <summary>
    /// 表示是目录还是文件
    /// </summary>
    public bool IsDirectory { get; set; }
    /// <summary>
    /// 文件或目录最后一次修改的时间
    /// </summary>
    public DateTimeOffset LastModified { get; set; }
    /// <summary>
    /// 表示文件内容的字节长度
    /// </summary>
    public long Length => _fileContent.Length;
    /// <summary>
    /// 表示文件或目录的名字
    /// </summary>
    public string Name { get; set; }
    /// <summary>
    /// 表示文件或目录的物理路径
    /// </summary>
    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;
    }

}

文件目录类(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();
    }
}

Redis配置文件(RedisFileOptions)

public class RedisFileOptions
{
    /// <summary>
    /// 配置Redius连接信息
    /// </summary>
    public string HostAndPort { get; set; }
}

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

    /// <summary>
    /// Redis文件解析器,只要用于通过指定的名称从Redis中读取存储的图片内容
    /// </summary>
public class RedisFileProvider : IFileProvider
{
    private readonly RedisFileOptions _options;
    private readonly ConnectionMultiplexer _redis;

    private static string NormalizePath(string path) => path.TrimStart('/').Replace('/', ':');
    /// <summary>
    /// 参数为Ioptions的好处是可以使用Options.Create()方法来直接生成
    /// </summary>
    /// <param name="options"></param>
    public RedisFileProvider(IOptions<RedisFileOptions> options)
    {
        _options = options.Value;
        _redis = ConnectionMultiplexer.Connect(new ConfigurationOptions
        {
            EndPoints = { _options.HostAndPort }
        });
    }

    /// <summary>
    /// 获得指定的目录
    /// 
    /// 通过
    /// </summary>
    /// <param name="subpath"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    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);
    }
    /// <summary>
    /// 得到指定目录或文件的IFileInfo对象
    /// 通过subpath参数值再Redis客户端读取文件信息。
    /// </summary>
    /// <param name="subpath"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    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();
    }
}

注入服务

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);

http://www.niftyadmin.cn/n/5181344.html

相关文章

JAVA Web项目中常用工具类集合

WebUtil 网络服务工具类 完整代码如下&#xff1a; import org.apache.commons.codec.Charsets; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.lang.Nullable; import org.springfr…

HDP集群Kafka开启SASLPLAINTEXT安全认证

hdp页面修改kafka配置 java代码连接kafka增加对应的认证信息 props.put("security.protocol","SASL_PLAINTEXT");props.put("sasl.mechanism","PLAIN");props.put("sasl.jaas.config","org.apache.kafka.common.securi…

Jenkins Docker Swarm插件 配置的坑

配置 Docker Host URI 注意&#xff0c;这里要用 http://&#xff01;&#xff01;&#xff01;如果按照提示里用了 tcp:// 则会报错&#xff0c;异常信息如下&#xff1a; 2023-11-13 16:28:42.6830000 [id34] WARNING o.e.j.s.h.ContextHandler$Context#log: Error while s…

【Qt之QWizard】使用2,示例分析

效果图 根据首页的选择不同&#xff0c;进入不同的选项。 以下是代码。 示例 .h #ifndef LICENSEWIZARD_H #define LICENSEWIZARD_H#include <QWizard>QT_BEGIN_NAMESPACE class QCheckBox; class QLabel; class QLineEdit; class QRadioButton; QT_END_NAMESPACEcla…

【数据分享】2015-2023年我国地级市逐月房价数据(Excel格式/Shp格式)

房价是一个城市发展程度的重要体现&#xff0c;一个城市的房价越高通常代表这个城市越发达&#xff0c;对于人口的吸引力越大&#xff01;因此&#xff0c;房价数据是我们在各项城市研究中都非常常用的数据&#xff01;之前我们分享过我国主要城市2023年房价数据&#xff08;可…

Android 12.0 mt6771新增分区功能实现一

1.前言 在12.0的系统开发中,在对某些特殊模块中关于数据的存储方面等需要新增分区来保存, 所以就需要在系统分区新增相关的分区,来实现功能,接下来就来实现这个功能,来新增分区功能 2.mt6771新增分区功能实现一的核心类 build/make/core/Makefilebuild/make/core/board_…

如何把小米路由器刷入OpenWRT系统并通过内网穿透工具实现公网远程访问

小米路由器4A千兆版刷入OpenWRT并远程访问 文章目录 小米路由器4A千兆版刷入OpenWRT并远程访问前言1. 安装Python和需要的库2. 使用 OpenWRTInvasion 破解路由器3. 备份当前分区并刷入新的Breed4. 安装cpolar内网穿透4.1 注册账号4.2 下载cpolar客户端4.3 登录cpolar web ui管理…

算法笔记-第七章-链表(未完成)

算法笔记-第七章-链表 链表的遍历链表结点的个数链表的头插法!链表删除元素链表反转例题思路一:原地反转思路二:头插法链表去除重复元素(有些复杂了)思路题目一题目二链表的遍历 #include<cstdio> const int N = 100; struct Node {int data, next;//表示的是当前数据和…