.NET6 ConfigurationManager的实现及使用方式

前言

友情提示:建议阅读本文之前先了解下.Net Core配置体系相关,也可以参考本人之前的文章《.Net Core Configuration源码探究 》然后对.Net Core的Configuration体系有一定的了解,使得理解起来更清晰。

在.Net6中关于配置相关多出一个关于配置相关的类ConfigurationManager,如果大概了解过Minimal API中的WebApplicationBuilder类相信你肯定发现了,在Minimal API中的配置相关属性Configuration正是ConfigurationManager的对象。ConfigurationManager本身并没有引入新的技术,也不是一个体系,只是在原来的基础上进行了进一步的封装,使得配置体系有了一个新的外观操作,暂且可以理解为新瓶装旧酒。本文我们就来了解下ConfigurationManager类,来看下微软为何在.Net6中会引入这么一个新的操作。

使用方式

关于.Net6中ConfigurationManager的使用方式,我们先通过简单的示例演示一下

ConfigurationManager configurationManager = new();
configurationManager.AddJsonFile("appsettings.json",true,reloadOnChange:true);
string serviceName = configurationManager["ServiceName"];
Console.WriteLine(serviceName);

当然,关于获取值得其他方式。比如GetSection、GetChildren相关方法还是可以继续使用的,或者使用Binder扩展包相关的Get<string>()GetValue<NacosOptions>("nacos")类似的方法也照样可以使用。那它和之前的.Net Core上的配置使用起来有什么不一样呢,我们看一下之前配置相关的使用方式,如下所示

IConfigurationBuilder configurationBuilder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
IConfiguration configuration = configurationBuilder.Build();
string serviceName = configuration["ServiceName"];
Console.WriteLine(serviceName);

这里需要注意的是,如果你是使用ConfigurationManager或者是IConfiguration封装的Helper类相关,并没有通过框架体系默认注入的时候,一定要注意将其设置为单例模式。其实这个很好理解,先不说每次用的时候都去实例化带来的内存CPU啥的三高问题。读取配置文件本质不就是把数据读到内存中吗?内存中有一份缓存这就好了,每次都去重新实例去读本身就是一种不规范的方式。许多时候如果你实在不知道该定义成什么样的生命周期,可以参考微软的实现方式,以ConfigurationManager为例,我们可以参考WebApplicationBuilder类中对ConfigurationManager注册的生命周期[点击查看源码]

public ConfigurationManager Configuration { get; } = new();
//这里注册为了单例模式
Services.AddSingleton<IConfiguration>(_ => Configuration);

通过上面我们演示的示例可以看出在ConfigurationManager的时候注册配置和读取配置相关都只是使用了这一个类。而在之前的配置体系中,注册配置需要使用IConfigurationBuilder,然后通过Build方法得到IConfiguration实例,然后读取是通过IConfiguration实例进行的。本身操作配置的时候IConfigurationBuilder和IConfiguration是满足单一职责原则没问题,像读取配置这种基础操作,应该是越简单越好,所以微软才进一步封装了ConfigurationManager来简化配置相关的操作。

在.Net6中微软并没有放弃IConfigurationBuilder和IConfiguration,因为这是操作配置文件的基础类,微软只是借助了它们两个在上面做了进一层封装而已,这个是需要我们了解的。

源码探究

上面我们了解了新的ConfigurationManager的使用方式,这里其实我们有疑问了,为什么ConfigurationManager可以进行注册和读取操作。上面我提到过ConfigurationManager本身就是新瓶装旧酒,而且它只是针对原有的配置体系做了一个新的外观,接下来哦我们就从源码入手,看一下它的实现方式。

定义入手

首先来看一下ConfigurationManager的的定义,如下所示[点击查看源码]

public sealed class ConfigurationManager : IConfigurationBuilder, IConfigurationRoot, IDisposable
{
}

其实只看它的定义就可以解答我们心中的大部分疑惑了,之所以ConfigurationManager能够满足IConfigurationBuilder和IConfigurationRoot这两个操作的功能是因为它本身就是实现了这两个接口,集它们的功能于一身了,IConfigurationRoot接口本身就集成自IConfiguration接口。因此如果给ConfigurationManager换个马甲的话你就会发现还是原来的配方还是原来的味道

ConfigurationManager configurationManager = new();
IConfigurationBuilder configurationBuilder = configurationManager.AddJsonFile("appsettings.json", true, reloadOnChange: true);
//尽管放心的调用Build完全不影响啥
IConfiguration configuration = configurationBuilder.Build();
string serviceName = configuration["ServiceName"];
Console.WriteLine(serviceName);

这种写法只是为了更好的看清它的本质,如果真实操作这么写,确实有点画蛇添足了,因为ConfigurationManager本身就是为了简化我们的操作。

认识IConfigurationBuilder和IConfiguration

通过上面我们了解到ConfigurationManager可以直接注册过配置文件就可以直接去操作配置文件里的内容,这一步是肯定通过转换得到的,毕竟之前的方式我们是通过IConfigurationBuilder的Build操作得到的IConfiguration的实例,那么我们就先来看下原始的方式是如何实现的。这里需要从IConfigurationBuilder的默认实现类ConfigurationBuilder说起,它的实现很简单[点击查看源码]

public class ConfigurationBuilder : IConfigurationBuilder
{
    /// <summary>
    /// 添加的数据源被存放到了这里
    /// </summary>
    public IList<IConfigurationSource> Sources { get; } = new List<IConfigurationSource>();

    public IDictionary<string, object> Properties { get; } = new Dictionary<string, object>();

    /// <summary>
    /// 添加IConfigurationSource数据源
    /// </summary>
    /// <returns></returns>
    public IConfigurationBuilder Add(IConfigurationSource source)
    {
        if (source == null)
        {
            throw new ArgumentNullException(nameof(source));
        }
        Sources.Add(source);
        return this;
    }

    public IConfigurationRoot Build()
    {
        //获取所有添加的IConfigurationSource里的IConfigurationProvider
        var providers = new List<IConfigurationProvider>();
        foreach (var source in Sources)
        {
            var provider = source.Build(this);
            providers.Add(provider);
        }
        //用providers去实例化ConfigurationRoot
        return new ConfigurationRoot(providers);
    }
}

这里我们来解释一下,其实我们注册配置相关的时候比如AddJsonFile()、AddEnvironmentVariables()、AddInMemoryCollection()等等它们其实都是扩展方法,本质就是添加IConfigurationSource实例,而IConfigurationBuilder的Build本质操作其实就是在IConfigurationSource集合中得到IConfigurationProvider集合,因真正从配置读取到的数据都是包含在IConfigurationProvider实例中的,ConfigurationRoot通过一系列的封装,让我们可以更便捷的得到配置里相关的信息。这就是ConfigurationBuilder的工作方式,也是配置体系的核心原理。
我们既然知道了添加配置的本质其实就是IConfigurationBuilder.Add(IConfigurationSource source)那么我就来看一下ConfigurationManager是如何实现这一步的。我们知道ConfigurationManager实现了IConfigurationBuilder接口,所以必然重写了IConfigurationBuilder的Add方法,找到源码位置[点击查看源码]

private readonly ConfigurationSources _sources = new ConfigurationSources(this); ;
IConfigurationBuilder IConfigurationBuilder.Add(IConfigurationSource source)
{
    _sources.Add(source ?? throw new ArgumentNullException(nameof(source)));
    return this;
}

这里返回了this也就是当前ConfigurationManager实例是为了可以进行链式编程,ConfigurationSources这个类是个新物种,原来的类叫ConfigurationSource,这里多了个s表明了这是一个集合类,我们就来看看它是个啥操作,找到源码位置[点击查看源码]

/// <summary>
/// 本身是一个IConfigurationSource集合
/// </summary>
private class ConfigurationSources : IList<IConfigurationSource>
{
    private readonly List<IConfigurationSource> _sources = new();
    private readonly ConfigurationManager _config;

    /// <summary>
    /// 因为是ConfigurationManager的内部类所以传递了当前ConfigurationManager实例
    /// </summary>
    /// <param name="config"></param>
    public ConfigurationSources(ConfigurationManager config)
    {
        _config = config;
    }

    /// <summary>
    /// 根据索引获取其中一个IConfigurationSource实例
    /// </summary>
    /// <returns></returns>
    public IConfigurationSource this[int index]
    {
        get => _sources[index];
        set
        {
            _sources[index] = value;
            _config.ReloadSources();
        }
    }

    public int Count => _sources.Count;

    public bool IsReadOnly => false;

    /// <summary>
    /// 这是重点添加配置源
    /// </summary>
    /// <param name="source"></param>
    public void Add(IConfigurationSource source)
    {
        //给自己的IConfigurationSource集合添加
        _sources.Add(source);
        //调用了ConfigurationManager的AddSource方法
        _config.AddSource(source);
    }

    /// <summary>
    /// 实现IList清除操作
    /// </summary>
    public void Clear()
    {
        _sources.Clear();
        //这里可以看到ConfigurationManager的ReloadSources方法很重要
        //通过名字可以看出是刷新配置数据用的
        _config.ReloadSources();
    }

    public void Insert(int index, IConfigurationSource source)
    {
        _sources.Insert(index, source);
        _config.ReloadSources();
    }

    public bool Remove(IConfigurationSource source)
    {
        var removed = _sources.Remove(source);
        _config.ReloadSources();
        return removed;
    }

    public void RemoveAt(int index)
    {
        _sources.RemoveAt(index);
        _config.ReloadSources();
    }

    //这里省略了实现了实现IList接口的其他操作
    //ConfigurationSources本身就是IList<IConfigurationSource>
}

正如我们看到的那样ConfigurationSources本身就是一个IConfigurationSource的集合,在新的.Net体系中微软喜欢把集合相关的操作封装一个Collection类,这样的好处就是让大家能更清晰的了解它是功能实现类,而不在用一个数据结构的眼光去看待。通过源码我们还看到了Add方法里还调用了ConfigurationManager的AddSource方法,这究竟是一个什么操作我们来看下[点击查看源码]

private readonly object _providerLock = new();
private readonly List<IConfigurationProvider> _providers = new();
private readonly List<IDisposable> _changeTokenRegistrations = new();
private void AddSource(IConfigurationSource source)
{
    lock (_providerLock)
    {
        //在IConfigurationSource中得到IConfigurationProvider实例
        var provider = source.Build(this);
        //添加到_providers集合中
        //我们提到过从配置源得到的配置都是通过IConfigurationProvider得到的
        _providers.Add(provider);

        //IConfigurationProvider的Load方法是从配置源中得到配置数据加载到程序内存中
        provider.Load();
        //注册更改令牌操作,使得配置可以进行动态刷新加载
        _changeTokenRegistrations.Add(ChangeToken.OnChange(() => provider.GetReloadToken(), () => RaiseChanged()));
    }
    //添加新的配置源要刷新令牌操作
    RaiseChanged();
}

private ConfigurationReloadToken _changeToken = new();
private void RaiseChanged()
{
    //每次对配置源进行更改操作需要得到新的更改令牌实例,用于可重复通知配置变更相关
    var previousToken = Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken());
    previousToken.OnReload();
}

从上面的ConfigurationSources方法里我们可以看到动态的针对ConfigurationSources里的ConfigurationSource进行更改会每次都调用ReloadSources方法,我们来看一下它的实现[点击查看源码]

private readonly object _providerLock = new();
private void ReloadSources()
{
    lock (_providerLock)
    {
        //释放原有操作
        DisposeRegistrationsAndProvidersUnsynchronized();

        //清除更改令牌
        _changeTokenRegistrations.Clear();
        //清除_providers
        _providers.Clear();

        //重新加载_providers
        foreach (var source in _sources)
        {
            _providers.Add(source.Build(this));
        }

        //重新加载数据添加通知令牌
        foreach (var p in _providers)
        {
            p.Load();
            _changeTokenRegistrations.Add(ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged()));
        }
    }
    RaiseChanged();
}

这个方法几乎是重新清除了原来的操作,然后完全的重新加载一遍数据,理论上来说是一个低性能的操作,不建议频繁使用。还有因为ConfigurationManager实现了IConfigurationBuilder接口所以也必然实现了它的Build方法少不了,看一下它的实现[点击查看源码]

IConfigurationRoot IConfigurationBuilder.Build() => this;

这波操作真的很真的很骚气,我即是IConfigurationRoot我也是IConfigurationBuilder,反正操作都是我自己,所以这里你可劲的Build也不影响啥,反正得到的也都是一个ConfigurationManager实例。到了这里结合我们之前了解到的传统的IConfigurationBuilder和IConfiguration关系,以及我们上面展示的展示的ConfigurationSources类的实现和ConfigurationManager的AddSource方法。其实我们可以发现我们上面展示的ConfigurationManager类的相关操作其实就是实现了之前ConfigurationBuilder类里的操作。其实这里微软可以不用实现ConfigurationSources类完全基于ConfigurationBuilder也能实现一套,但是显然微软没这么做,具体想法咱们不得而知,估计是只想以来抽象,而并不像以来原来的实现方式吧。

我们上面展示的这一部分的ConfigurationManager代码,其实就是替代了原来的ConfigurationBuilder类的功能。

读取操作

上面我们看到了在ConfigurationManager中关于以前ConfigurationManager类的实现。接下来我们看一下读取相关的操作,即在这里ConfigurationManager成为了IConfiguration实例,所以我们先来看下IConfiguration接口的定义[点击查看源码]

public interface IConfiguration
{
    /// <summary>
    /// 通过配置名称获取值
    /// </summary>
    /// <returns></returns>
    string this[string key] { get; set; }

    /// <summary>
    /// 获取一个配置节点
    /// </summary>
    /// <returns></returns>
    IConfigurationSection GetSection(string key);

    /// <summary>
    /// 获取所有子节点
    /// </summary>
    /// <returns></returns>
    IEnumerable<IConfigurationSection> GetChildren();

    /// <summary>
    /// 刷新数据通知
    /// </summary>
    /// <returns></returns>
    IChangeToken GetReloadToken();
}

通过代码我们看到了IConfiguration的定义,也就是在ConfigurationManager类中必然也实现也这几个操作,首先便是通过索引器直接根据配置的名称获取值得操作[点击查看源码]

private readonly object _providerLock = new();
private readonly List<IConfigurationProvider> _providers = new();
/// <summary>
/// 可读可写的操作
/// </summary>
/// <returns></returns>
public string this[string key]
{
    get
    {
        lock (_providerLock)
        {
            //通过在IConfigurationProvider集合中获取配置值
            return ConfigurationRoot.GetConfiguration(_providers, key);
        }
    }
    set
    {
        lock (_providerLock)
        {
            //也可以把值放到IConfigurationProvider集合中
            ConfigurationRoot.SetConfiguration(_providers, key, value);
        }
    }
}

其中_providers中的值是我们在AddSource方法中添加进来的,这里的本质其实还是针对ConfigurationRoot做了封装。ConfigurationRoot实现了IConfigurationRoot接口,IConfigurationRoot实现了IConfiguration接口。而ConfigurationRoot的GetConfiguration方法和SetConfiguration是最直观体现ConfigurationRoot本质就是IConfigurationProvider包装的证据。我们来看一下ConfigurationRoot这两个方法的实现[点击查看源码]

internal static string GetConfiguration(IList<IConfigurationProvider> providers, string key)
{
    //倒序遍历providers,因为Configuration采用的后来者居上的方式,即后注册的Key会覆盖先前注册的Key
    for (int i = providers.Count - 1; i >= 0; i--)
    {
        IConfigurationProvider provider = providers[i];
        //如果找到Key的值就直接返回
        if (provider.TryGet(key, out string value))
        {
            return value;
        }
    }
    return null;
}

internal static void SetConfiguration(IList<IConfigurationProvider> providers, string key, string value)
{
    if (providers.Count == 0)
    {
        throw new InvalidOperationException("");
    }
    //给每个provider都Set这个键值,虽然浪费了一部分内存,但是可以最快的获取
    foreach (IConfigurationProvider provider in providers)
    {
        provider.Set(key, value);
    }
}

关于GetSection的方法实现,本质上是返回ConfigurationSection实例,ConfigurationSection本身也是实现了IConfiguration接口,所有关于配置获取的操作出口都是面向IConfiguration的。

public IConfigurationSection GetSection(string key) => new ConfigurationSection(this, key);

GetChildren方法是获取配置的所有子节点的操作,本质是返回IConfigurationSection的集合,实现方式如如下

private readonly object _providerLock = new();
public IEnumerable<IConfigurationSection> GetChildren()
{
    lock (_providerLock)
    {
        //调用了GetChildrenImplementation方法
        return this.GetChildrenImplementation(null).ToList();
    }
}

这里调用了GetChildrenImplementation方法,而GetChildrenImplementation是一个扩展方法,我们来看一下它的实现[点击查看源码]

internal static IEnumerable<IConfigurationSection> GetChildrenImplementation(this IConfigurationRoot root, string path)
{
    //在当前ConfigurationManager实例中获取到所有的IConfigurationProvider实例
    //然后包装成IConfigurationSection集合
    return root.Providers
        .Aggregate(Enumerable.Empty<string>(),
            (seed, source) => source.GetChildKeys(seed, path))
        .Distinct(StringComparer.OrdinalIgnoreCase)
        .Select(key => root.GetSection(path == null ? key : ConfigurationPath.Combine(path, key)));
}

通过这段代码再次应验了那句话所有获取配置数据都是面向IConfiguration接口的,数据本质都是来自于IConfigurationProvider读取配置源中的数据。

ConfigurationBuilderProperties

在ConfigurationManager中还包含了一个Properties属性,这个属性本质来源于IConfigurationBuilder。在IConfigurationBuilder中它和IConfigurationSource是平行关系,IConfigurationSource用于在配置源中获取数据,而Properties是在内存中获取数据,本质是一个字典

private readonly ConfigurationBuilderProperties _properties = new ConfigurationBuilderProperties(this);
IDictionary<string, object> IConfigurationBuilder.Properties => _properties;

这里咱们就不细说这个具体实现了,我们知道它本质是字典,然后操作都是纯内存的操作即可,来看一下它的定义[点击查看源码]

private class ConfigurationBuilderProperties : IDictionary<string, object>
{
}

基本上许多缓存机制即内存操作都是基于字典做的一部分实现,所以大家对这个实现的方式有一定的认识即可,即使在配置体系的核心操作ConfigurationProvider中读取的配置数据也是存放在字典中的。这个可以去ConfigurationProvider类中自行了解一下[点击查看源码]

protected IDictionary<string, string> Data { get; set; }
protected ConfigurationProvider()
{
    Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}

总结

通过本文我们了解到了.Net6配置体系中的新成员ConfigurationManager,它是一个新内容但不是一个新技术,因为它是在原有的配置体系中封装了一个新的外观,以简化原来对配置相关的操作。原来对配置的操作需要涉及IConfigurationBuilder和IConfiguration两个抽象操作,而新的ConfigurationManager只需要一个类,其本质是因为ConfigurationManage同时实现了IConfigurationBuilder和IConfiguration接口,拥有了他们两个体系的能力。整体来说重写了IConfigurationBuilder的实现为主,而读取操作主要还是借助原来的ConfigurationRoot对节点数据的读取操作。

到此这篇关于.NET6 ConfigurationManager的实现的文章就介绍到这了,更多相关.NET6 ConfigurationManager实现内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • .NET 6全新配置对象ConfigurationManager介绍

    介绍 本节为大家带来.NET 6新增的ConfigurationManager,很多人好奇为啥要讲这个,读取加载配置信息都随手就来了,我们往下看一下. 翻译:这添加了 ASP.NET Core 的新 WebApplcation 和 WebApplicationBuilder已经使用的类型,允许从配置(例如appsettings.json和DOTNET_/ASPNETCORE_环境变量)中读取,同时仍然能够添加新的配置源,而无需显式重建配置.每次通过IConfigurationBuilder界面添

  • asp.net 类库中使用ConfigurationManager.ConnectionStrings

    一直没弄明白怎么在类库中找不到 ConfigurationManager.ConnectionStrings 后面才发现没有添加System.configuration的引用,添加后: 引入命名空间: 复制代码 代码如下: using System.Configuration; 便可以使用了: 复制代码 代码如下: public static string ConnectionString = ConfigurationManager.ConnectionStrings["Conn"]

  • .NET6 ConfigurationManager的实现及使用方式

    前言 友情提示:建议阅读本文之前先了解下.Net Core配置体系相关,也可以参考本人之前的文章<.Net Core Configuration源码探究 >然后对.Net Core的Configuration体系有一定的了解,使得理解起来更清晰. 在.Net6中关于配置相关多出一个关于配置相关的类ConfigurationManager,如果大概了解过Minimal API中的WebApplicationBuilder类相信你肯定发现了,在Minimal API中的配置相关属性Configur

  • 详解WPF如何在基础控件上显示Loading等待动画

    WPF 如何在基础控件上显示 Loading 等待动画 框架使用.NET4 至 .NET6: Visual Studio 2022; 使用方式需引入命名空间后设置控件的附加属性 wd:Loading.IsShow="true",即可显示默认等待动画效果如下: 如需自定义 Loading 一定要 先设置 wd:Loading.Child 在设置 IsShow="true" . 显示不同 Loading 内容需 wd:Loading.Child ={x:Static w

  • 简单聊下.NET6 Minimal API的使用方式

    目录 前言 使用方式 几行代码构建Web程序 更改监听地址 日志操作 基础环境配置 主机相关设置 默认容器替换 中间件相关 请求处理 路由约束 模型绑定 绑定示例 自定义绑定 总结 前言 随着.Net6的发布,微软也改进了对之前ASP.NET Core构建方式,使用了新的Minimal API模式.之前默认的方式是需要在Startup中注册IOC和中间件相关,但是在Minimal API模式下你只需要简单的写几行代码就可以构建一个ASP.NET Core的Web应用,真可谓非常的简单,加之配合c

  • Linux下以守护进程方式运行.NET6

    前言 ​ 在<步步入门> .NET 6 部署到Linux一文中只是演示了控制终端方式运行ASP.ENT,在实际的应用中,这种方式不能确保服务延续性.如果控制终端关闭,或者服务器重启,都会导致web服务不能正常访问.那要怎么解决这个问题呢? 常见的作法有两种 守护进程 什么是守护进程,简单讲就是不受其他进程影响以后台服务的进程,功能类似Windows服务. 守护进程我们使用Supervisor,详细参考这位博友的文章:ASP.NET Core Linux下为 dotnet 创建守护进程(必备知识

  • 关于.NET6 Minimal API的使用方式详解

    目录 前言 使用方式 几行代码构建Web程序 更改监听地址 日志操作 基础环境配置 主机相关设置 默认容器替换 中间件相关 请求处理 路由约束 模型绑定 绑定示例 自定义绑定 总结 前言 随着.Net6的发布,微软也改进了对之前ASP.NET Core构建方式,使用了新的Minimal API模式.之前默认的方式是需要在Startup中注册IOC和中间件相关,但是在Minimal API模式下你只需要简单的写几行代码就可以构建一个ASP.NET Core的Web应用,真可谓非常的简单,加之配合c

  • .NET实现定时发送邮件代码(两种方式)

    有时候我们或许会遇到想在某一个时刻给别人发送一封邮件,就像是在生日的时候,但是我们又怕到时候忘记了,这时就应该 使用发送定时邮件的功能,但是这个定时发送邮件功能是怎么实现的呢?下面用两种方式实现.net定时发送邮件代码,具体请看下面内容. 实现思路.需求添加一个全局应用程序类Global.asax 代码会在访问网站时运行 Global.asax代码: void Application_Start(object sender, EventArgs e) { // 在应用程序启动时运行的代码 Sys

  • ASP.NET页面缓存常见的4种方式

    本文为大家分享了4种常见的ASP.NET页面缓存方式,供大家参考,具体内容如下 1.分布式缓存Memcached,教程下载 2.内存缓存,此占用服务器资源 #region 内存缓存 public class MemoryCache { #region 写 /// <summary> /// 向内存写入数据缓存 /// </summary> /// <remarks>TOMMYHU2011-7-28 10:25创建</remarks> /// <para

  • web.config中配置数据库连接的方式

    在网站开发中,数据库操作是经常要用到的操作,ASP.NET中一般做法是在web.config中配置数据库连接代码,然后在程序中调用数据库连接代码,这样做的好处就是当数据库连接代码需要改变的时候,我们只要修改web.config中的数据库连接代码即可,而不必在修改每一个页面中的数据库连接代码. 在ASP.NET中有两种配置数据库连接代码的方式,它们分别是 appSettings 和 connectionStrings .在使用 appSettings 和 connectionStrings 配置数

  • asp.net使用ODP即oracle连接方式的的防注入登录验证程序

    网上有很多SQL连接方式的登录验证,但没有oracle连接方式的,我摸索了一上午写了这个可执行的函数,分享给大家 复制代码 代码如下: // 用户登录检查 public bool LoginCheck(string f_LoginName, string f_LoginPass) { bool result = false; // 正则表达式检查 if (Regex.IsMatch(f_LoginName,@"^[a-zA-Z0-9]{1,15}$") && Regex

  • c#读写App.config,ConfigurationManager.AppSettings 不生效的解决方法

    我们经常会希望在程序中写入一些配置信息,例如版本号,以及数据库的连接字符串等.你可能知道在WinForm应用程序中可以利用Properties.Settings来进行类似的工作,但这些其实都利用了App.config配置文件. 本文探讨用代码的方式访问 App.config 的方法.关于 App.config 的使用远比上面提到的用途复杂,因此仅讨论最基本的 appSettings 配置节. 一.配置文件概述: 应用程序配置文件是标准的 XML 文件,XML 标记和属性是区分大小写的.它是可以按

随机推荐