【.Net Configuration】编写自己的配置库(笔记)

.net framework config provider

  • 参照课程和JsonFileConfiguration制作自己的配置库
  • 能跑成功,但是先放着,等到需要时再自习分析

项目结构

  • 其中test项目依赖工程项目
    在这里插入图片描述

nuget库

在这里插入图片描述
在这里插入图片描述

DotnetFrameworkConfigurationProvider

DotnetFrameworkConfigurationGlobalConfig


namespace Cattail.ConfigurationProvider.DotnetFrameworkConfigurationProvider;

/// <summary>
/// [usage] 为DotnetFrameworkConfiguration项目提供全局配置
/// </summary>
public static class DotnetFrameworkConfigurationGlobalConfig
{
    /// <summary>
    /// [usage] webconfig.xml文件的位置
    /// </summary>
    public static string ConfigPath = Environment.CurrentDirectory + "\\Configuration\\webconfig.xml";
    // public static string ConfigPath = "/Configuration/webconfig.xml";
}

Configuration

namespace Cattail.ConfigurationProvider.DotnetFrameworkConfigurationProvider;

// [file] xml文件实例化类型

public class Configuration
{
    public ConnectionStringClass? Connstr1 { get; set; }
    public ConnectionStringClass? Contest1 { get; set; }
    public Config? Config { get; set; }

    public override string ToString()
    {
        // tostring
        return $"{nameof(Connstr1)}: {Connstr1}, {nameof(Contest1)}: {Contest1}, {nameof(Config)}: {Config}";
    }
}

public class ConnectionStringClass
{
    public string? ConnectionString { get; set; }
    public string? ProviderName { get; set; }

    public override string ToString()
    {
        // tostring
        return $"{nameof(ConnectionString)}: {ConnectionString}, {nameof(ProviderName)}: {ProviderName}";
    }
}

public class Config
{
    public string? RedisServer { get; set; }
    public string? RedisPassword { get; set; }
    public Smtp? Smtp { get; set; }

    public override string ToString()
    {
        // tostring
        return $"{nameof(RedisServer)}: {RedisServer}, {nameof(RedisPassword)}: {RedisPassword}, {nameof(Smtp)}: {Smtp}";
    }
}

public class Smtp
{
    public string? Server { get; set; }
    public string? Port { get; set; }

    public override string ToString()
    {
        // tostring
        return $"{nameof(Server)}: {Server}, {nameof(Port)}: {Port}";
    }
}

webconfig.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- 配置 -->
<configuration>
    <!-- 链接信息 -->
    <connectionStrings>
        <add name="connstr1" connectionString="DataSource=.;InitialCatalog=DemoDB;UserId=sa;Password=123456"/>
        <add name="contest1" connectionString="test text" providerName="MySql"/>
    </connectionStrings>
  
    <appSettings>
        <add key="Smtp:Server" value="smtp.test.com"/>
        <add key="Smtp:Port" value="25"/>
        <add key="RedisServer" value="127.0.0.1"/>
        <add key="RedisPassword" value="abc123"/>
    </appSettings>
</configuration>

FxFileConfigurationSource

using Microsoft.Extensions.Configuration;

namespace Cattail.ConfigurationProvider.DotnetFrameworkConfigurationProvider;

public class FxFileConfigurationSource : FileConfigurationSource
{
    public override IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        // [notice] 该语句用于处理path等默认值问题
        EnsureDefaults(builder);
        return new FxFileConfigurationProvider(this);
    }
}

FxFileConfigurationProvider

using System.Xml;
using Microsoft.Extensions.Configuration;

namespace Cattail.ConfigurationProvider.DotnetFrameworkConfigurationProvider;

/// <summary>
/// <para>
/// [功能] .net framework 配置文件读取 配置提供者
/// </para>
/// </summary>
public class FxFileConfigurationProvider : FileConfigurationProvider
{
    public FxFileConfigurationProvider(FxFileConfigurationSource source) : base(source)
    {
    }

    /// <summary>
    /// [功能] 解析配置文件中的connectionStrings节点
    /// </summary>
    /// <param name="xmlDocument"></param>
    /// <param name="data"></param>
    private static void ConnectionStringsXmlParser(XmlDocument xmlDocument, Dictionary<string, string?> data)
    {
        // [步骤] 解析xml目标节点
        using (XmlNodeList? nodeConnectStrings = xmlDocument.SelectNodes("/configuration/connectionStrings/add"))
        {
            if (nodeConnectStrings is null)
                return;

            // [步骤] 遍历节点
            foreach (XmlNode nodeConnectString in nodeConnectStrings.Cast<XmlNode>())
            {
                // [步骤] 提取add中的name和相应的connectionString
                string? name = nodeConnectString.Attributes?["name"]?.Value;
                string? connectionString = nodeConnectString.Attributes?["connectionString"]?.Value;

                // [步骤] 记录name、connectionString和它的值value
                if (connectionString is not null)
                    data[$"{name}:connectionString"] = connectionString;

                // [步骤] 提取add节点中的providerName参数
                var providerNameProperty = nodeConnectString.Attributes?["providerName"];

                // 记录name、providerName和它的值value
                string? providerName = providerNameProperty?.Value;
                data[$"{name}:providerName"] = providerName;
            }
        }
    }
  
    /// <summary>
    /// [功能] 解析配置文件中的appSettings节点
    /// </summary>
    /// <param name="xmlDocument"></param>
    /// <param name="data"></param>
    private static void AppSettingsXmlParser(XmlDocument xmlDocument, Dictionary<string, string?> data)
    {
        using (var asNodes = xmlDocument.SelectNodes("/configuration/appSettings/add"))
        {
            if (asNodes is null)
                return;
          
            foreach (var xmlNode in asNodes.Cast<XmlNode>())
            {
                if (xmlNode is null)
                    continue;

                // [process] key
                string? key = xmlNode.Attributes?["key"]?.Value;
                key = key?.Replace(".", ";");

                // [process] value
                string? value = xmlNode.Attributes?["value"]?.Value;
              
                data[$"{nameof(Config)}:" + key] = value;
            }
        }
    }

    /// <summary>
    /// [功能] 加载资源
    /// </summary>
    /// <remarks>
    /// [实现步骤] 创建大小写不敏感的Dictionary;加载xml文件;解析xml;找到目标节点下的多个资源;解析资源并保存到dictionary
    /// </remarks>
    /// <param name="stream">配置数据流</param>
    public override void Load(Stream stream)
    {
        // [步骤] 创建大小写不敏感的Dictionary,用于存储config参数
        // [解释] 参数StringComparer.OrdinalIgnoreCase表示该dictionary是大小写不敏感的
        var data = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);

        // [步骤] 加载xml文件
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.Load(stream);

        // [步骤] 解析配置文件中的connectionStrings节点
        ConnectionStringsXmlParser(xmlDocument, data);

        // [步骤] 解析配置文件中的appSettings节点
        AppSettingsXmlParser(xmlDocument, data);
      
        // [步骤] 配置data
        this.Data = data;
    }
}

FxFileConfigurationExtensions

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.FileProviders;

namespace Cattail.ConfigurationProvider.DotnetFrameworkConfigurationProvider;

public static class FxFileConfigurationExtensions
{
  
    // [class message]
    // [refer to] JsonConfigurationExtensions
  
    /// <summary>
    /// Adds a Fx configuration source to &lt;paramref name="builder".
    /// (fx configuration is a xml .net framework config file);
    /// </summary>
    /// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
    /// <param name="configureSource">Configures the source.</param>
    /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
    // [idea] 使用原生builder.Add(Action<FxFileConfigurationSource>?)方法
    // [notice] builder.Add 传输action,表示Configuration Source配置的方式,
    // [notice] 但是Configuration Source创建对象的时机还在官方代码
    public static IConfigurationBuilder AddFxFile(this IConfigurationBuilder builder,
        Action<FxFileConfigurationSource>? configureSource) => builder.Add(configureSource);
  
    /// <summary>
    /// Adds a Fx configuration source to <paramref name="builder"/>.
    /// <para>(fx configuration is a xml .net framework config file)</para>
    /// </summary>
    /// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
    /// <param name="provider">The <see cref="IFileProvider"/> to use to access the file.</param>
    /// <param name="path">Path relative to the base path stored in
    /// <see cref="IConfigurationBuilder.Properties"/> of <paramref name="builder"/>.</param>
    /// <param name="optional">Whether the file is optional.</param>
    /// <param name="reloadOnChange">Whether the configuration should be reloaded if the file changes.</param>
    /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
    public static IConfigurationBuilder AddFxFile(this IConfigurationBuilder builder, IFileProvider? provider,
        string path, bool optional, bool reloadOnChange)
    {
        // [process begin] 参数校验

        if (builder is null)
        {
            throw new ArgumentNullException($"{nameof(builder)}参数不能为null!");
        }

        if (string.IsNullOrEmpty(path))
        {
            throw new ArgumentException($"{nameof(path)}参数不能为null!");
        }

        // [process] 路径验证
        // [propose] 为了让路径验证掌握在自己编写的代码中
        if (!File.Exists(path))
        {
            throw new FileNotFoundException($"文件{path}不存在!请检查{nameof(path)}的路径!");
        }

        // [process end] 参数校验

        // [process] configuration builder 参数添加 configuration source
        return builder.AddFxFile(s =>
        {
            s.FileProvider = provider;
            s.Path = path;
            s.Optional = optional;
            s.ReloadOnChange = reloadOnChange;
            s.ResolveFileProvider();
        });
    }
  
    /// <summary>
    /// Adds a Fx configuration source to <paramref name="builder"/>.
    /// <para>(fx configuration is a xml .net framework config file)</para>
    /// </summary>
    /// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
    /// <param name="path">Path relative to the base path stored in
    /// <see cref="IConfigurationBuilder.Properties"/> of <paramref name="builder"/>.</param>
    /// <param name="optional">Whether the file is optional.</param>
    /// <param name="reloadOnChange">Whether the configuration should be reloaded if the file changes.</param>
    /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
    public static IConfigurationBuilder AddFxFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange)
    {
        return AddFxFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange);
    }
  
    /// <summary>
    /// Adds a Fx configuration source to <paramref name="builder"/>.
    /// <para>(fx configuration is a xml .net framework config file)</para>
    /// </summary>
    /// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
    /// <param name="path">Path relative to the base path stored in
    /// <see cref="IConfigurationBuilder.Properties"/> of <paramref name="builder"/>.</param>
    /// <param name="optional">Whether the file is optional.</param>
    /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
    public static IConfigurationBuilder AddFxFile(this IConfigurationBuilder builder, string path, bool optional)
    {
        return AddFxFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false);
    }
  
    /// <summary>
    /// Adds a Fx configuration source to <paramref name="builder"/>.
    /// <para>(fx configuration is a xml .net framework config file)</para>
    /// </summary>
    /// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
    /// <param name="path">Path relative to the base path stored in
    /// <see cref="IConfigurationBuilder.Properties"/> of <paramref name="builder"/>.</param>
    /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
    public static IConfigurationBuilder AddFxFile(this IConfigurationBuilder builder, string path)
    {
        return AddFxFile(builder, provider: null, path: path, optional: false, reloadOnChange: false);
    }
}

DotnetFrameworkConfigurationProviderTest

WebConfigServiceTest

using Cattail.ConfigurationProvider.DotnetFrameworkConfigurationProvider;
using Microsoft.Extensions.Options;

namespace DotnetFrameworkConfigurationProviderTest;

public class WebConfigServiceTest(IOptionsSnapshot<Configuration> optionsSnapshot)
{
    private IOptionsSnapshot<Configuration> _optionsSnapshot = optionsSnapshot;

    public override string ToString()
    {
        // tostring
        return "WebConfigServiceTest._optionsSnapshot: " + _optionsSnapshot.Value.ToString();
    }
}

DotnetFrameworkConfigurationProviderTest

using Cattail.ConfigurationProvider.DotnetFrameworkConfigurationProvider;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DotnetFrameworkConfigurationProviderTest;

/// <summary>
/// 测试自己编写的配置提供器
/// </summary>
[TestClass]
public class DotnetFrameworkConfigurationProviderTest
{
    // [test method] 测试自己编写的配置提供器
    [TestMethod]
    public void TestDotnetFrameworkConfigurationProvider()
    {
        // [process] 验证文件是否存在
        if (!File.Exists(DotnetFrameworkConfigurationGlobalConfig.ConfigPath))
        {
            Console.WriteLine("文件不存在");
            throw new FileNotFoundException();
        }
      
        // // [process] 装配config source
        // FxFileConfigurationSource fxFileConfigurationSource = new FxFileConfigurationSource();
        // fxFileConfigurationSource.Path = DotnetFrameworkConfigurationGlobalConfig.ConfigPath;
        // // [debug] 防止绝对路径引起的 “The configuration file was not found and is not optional”报错
        // fxFileConfigurationSource.ResolveFileProvider();
      
        // [process] 创建config builder
        ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
        // [process] 添加config source
        // configurationBuilder.Add(fxFileConfigurationSource);
        configurationBuilder.AddFxFile(DotnetFrameworkConfigurationGlobalConfig.ConfigPath);
        // [process] 生成config root
        IConfigurationRoot configurationRoot = configurationBuilder.Build();
      
        // [process] 配置依赖注入
        ServiceCollection serviceCollection = new ServiceCollection();
        serviceCollection.AddOptions()
            .Configure<Configuration>(e => configurationRoot.Bind(e));
      
        // [process] 配置需求类依赖注入
        serviceCollection.AddScoped<WebConfigServiceTest>();
      
        // [process] 生成service provider
        using (ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider())
        {
            var test = serviceProvider.GetService<WebConfigServiceTest>();
            Console.WriteLine(test);
        }
    }
}

在这里插入图片描述


.NET 6教程,.Net Core 2022视频教程,杨中科主讲 - p43 - 编写自己的配置类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
IBM、微软、华为等……均采用的软件配置。目录摘要如下: 配置结构 ..........\1 配置项 CI ..........\...........\1.01 客户文档 Customer ..........\...........\1.02 项目计划 Plan ..........\...........\.............\1.2.1 软件估计Estimation ..........\...........\.............\1.2.2 软件开发计划PPL ..........\...........\.............\1.2.3 配置管理计划CMP ..........\...........\1.03 需求分析SRS ..........\...........\................\infoX-MDSP PortalDemo SRS 软件需求规格说明书.doc .................................................. ..........\2 项目管理 PM ..........\.............\2.1 会议纪要 MOM ..........\.............\................\2.1.1 开工会 kick-off ..........\.............\................\2.1.2 周例会 weekly ..........\.............\................\2.1.3 阶段结束会议 EOP ..........\.............\................\2.1.4 关闭会议 closure ..........\.............\................\2.1.5 技术讨论会 Technical ..........\.............\................\2.1.6 其他会议 other ..........\.............\2.2 项目报告 Daily ..........\.............\..................\2.2.1 项目日报 Daily ..........\.............\..................\2.2.2 项目周报 weekly .................................................. ..........\.............\2.3 问题跟踪 Tracking ..........\.............\2.4 团队建设 Team Buliding ..........\.............\..........................\MTV-SMCP项目组月考核汇总表9月.xls ..........\.............\..........................\portaldemo项目沟通既要.xls ..........\.............\..........................\vssver.scc ..........\.............\2.5 公司制度 ..........\3 配置管理 CM .................................................. ..........\4 质量管理 QM ..........\.............\4.1 度量 Metrics .................................................. ..........\5 测试记录 Test Record .................................................. ..........\6 培训及总结 Training ..........\.....................\6.1 Plan阶段 .................................................. ..........\7 工具使用 Tools ..........\8 参考资料 Reference ..........\9 日志 Timesheet ..........\................\9.1 工时统计 Timesheet ..........\................\9.2 工作日志 Log ..........\................\9.3 技术问题跟踪Tracking ..........\................\........................\infoX-PortalDemo技术讨论问题跟踪表.xls
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值