1 对于“partial”关键字的一些思考
“partial”关键字主要为类的分布式定义预留扩展空间,如果一个类在最初定义时就使用了“partial”关键字,则该类就支持分布式定义。
类的分布式定义的应用场景主要有两种:
- 一个开发者在不对原类进行任何重构的情况下,增加相应的功能,如果原类使用了“partial”关键字,则该开发者就可定义一个同名的类并在该类中定义所增加的功能,注意:同名类也必须使用“partial”关键字进行限定。
- 在1个大型程序中1个类所实现的所有功能由多个开发者共同定义实现,这时“partial”关键字就派上了用场。
在实际开发中不管是第1种应用场景还是第2种应用场景都不常用,特别是第2种应用场景基本不会出现,最常出现的应用场景反而是:开发者原类定义的基础上进行重构,从而增加或删除相应的功能,所以“partial”关键字的作用就如果曹操的名言:“食之无味,弃之可惜。”,如非开发团队确认在开发过程中会遭遇以上两种应用场景中的任意1种,那么就不要在类的定义中使用“partial”关键字,这样的类的定义形式更加的常见、易懂和简洁。
2 通过类定义实现配置文件(appsettings.json)的读写
2.1 引用System.Configuration.ConfigurationManager
在Data项中,通过Nuget引用System.Configuration.ConfigurationManager
2.2 Data.DataProviderType
using System.Runtime.Serialization;
namespace Data
{
/// <summary>
/// 【数据库软件类型提供程序序--枚举】
/// <remarks>
/// 摘要:
/// 该枚举实例定义了3种数据库软件,通过枚举实例选定其中的1种或多种数据库软件(当前程序只支持1种,多种需要重构),实现当前程序通过CURD中间件与指定数据库软件中的指定数据进行CURD交互操作。
/// </remarks>
/// </summary>
public enum DataProviderType
{
/// <summary>
/// 【未知】
/// <remarks>
/// 摘要:
/// “未知的”数据库软件,即没有数据库软件与当前程序进行数据交互操作。
/// EnumMember特性:
/// 在JSON序列化操作时把该枚举成员实例的值序列化为空字符串,赋值给键/值对中的值。
/// </remarks>
/// </summary>
[EnumMember(Value = "")]
Unknown,
/// <summary>
/// 【SqlServer】
/// <remarks>
/// 摘要:
/// “Microsoft SQL Server”数据库软件,即通过“Microsoft SQL Server”数据库软件中的指定数据库与当前程序进行CURD交互操作。
/// EnumMember特性:
/// 在JSON序列化操作时把该枚举成员实例的值序列化为“sqlserver”字符串,赋值给键/值对中的值。
/// </remarks>
/// </summary>
[EnumMember(Value = "sqlserver")]
SqlServer,
/// <summary>
/// 【MySql】
/// <remarks>
/// 摘要:
/// “MySql”数据库软件,即通过“MySql”数据库软件中的指定数据库与当前程序进行CURD交互操作。
/// EnumMember特性:
/// 在JSON序列化操作时把该枚举成员实例的值序列化为“mysql”字符串,赋值给键/值对中的值。
/// </remarks>
/// </summary>
[EnumMember(Value = "mysql")]
MySql,
}
}
2.3 Data.Configuration.DataConfig
using System.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Data.Configuration
{
/// <summary>
/// 【数据库连接配置--类】
/// <remarks>
/// 摘要:
/// 通过该类中的属性成员实例实现与“appsettings.json”文件中数据库连接相关数据读写操作,为当程序连接到指定数据库软件中的指定数据库提供数据支撑。
/// 说明:
/// 属性成员的名称必须与JSON键/值对中的键相同,且属性成员的个数与键的个数也必须相等,
/// 否则ConfigurationBinder.Bind方法将不支持“appsettings.json”文件中数据库连接相关数据与当前类中的属性成员实例的读写操作。
/// </remarks>
/// </summary>
public class DataConfig/* : IConfig*/
{
#region 属性
/// <summary>
/// 【数据库连接字符串】
/// <remarks>
/// 摘要:
/// 获取/设置1个指定的数据库连接字符串,该字符串中的数据信息包含:所连接数据库名称、安全权限设置、数据库登录用户和密码等。
/// </remarks>
/// </summary>
public string ConnectionString { get; set; } = string.Empty;
/// <summary>
/// 【数据库提供程序】
/// <remarks>
/// 摘要:
/// 获取/设置与1个指定的数据库软件与当前程序进行CURD交互操作的。
/// JsonConverter特性:
/// 当前“DataConfig”类的实例通过JSON中的方法进行序列化/反序化时,需要根据字符字符串枚举方式来实例当前属性成员实例值与JSON键/值对中值的相对转换操作。
/// </remarks>
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public DataProviderType DataProvider { get; set; } = DataProviderType.SqlServer;
/// <summary>
/// 【SQL命令超时】
/// <remarks>
/// 摘要:
/// 获取/设置1个指定数据库的在终止执行SQL命令的尝试并生成错误之前的等待时间值(以秒为单位),如果在当前程序执行SQL命令的时间超过该属性实例的设置值,
/// 则终止程序对指定SQL命令的执行,该属性实例的默认值为:null,即未设置为:0,如果数据库软件中的指定数据库在执行行SQL命令时产生错误时,不必须等待直接输出错误/异常信息。
/// </remarks>
/// </summary>
public int? SQLCommandTimeout { get; set; } = null;
/// <summary>
/// 【名称】
/// <remarks>
/// 摘要:
/// 设定“appsettings.json”文件中数据库连接字符串键/值对中的默认键为:“ConnectionStrings”(由nameof(ConfigurationManager.ConnectionStrings)操作设定)。
/// JsonIgnore特性:
/// 当前“DataConfig”类的实例通过JSON中的方法进行序列化时,该属性成员及其实例值将不会被序列化,更不会被持久化到“appsettings.json”文件中,
/// 即该属性成员实例只为数据库连接设定1个指定且唯一的JSON根节点,而不是在“appsettings.json”文件的数据库连接配置中设定: "Name": "ConnectionStrings"JSON键/值对。
/// </remarks>
/// </summary>
[JsonIgnore]
public string Name => nameof(ConfigurationManager.ConnectionStrings);
#endregion
#region 方法--接口实现
///<summary>
/// 【获取顺序】
/// <remarks>
/// 摘要:
/// 在对所有继承于“IConfig”接口的具体实现类的所有实例进行排序操作时,设定“DataConfig”类的实例在所有实例中的次序。
/// 说明:
/// 1、该方法是“IConfig”接口中同名方法的重新定义,“IConfig”接口中同名方法中的默认值为:1,而该方法中的默认值为:0,所以以顺序方式进行排序时,
/// “DataConfig”类的实例在所有实例中的排第1。
/// 2、并不是所有继承于“IConfig”接口的具体实现类都重新定义该同名方法,如果没有重新定义该同名方法,则该类的实例的顺序值为:1,所以可能有多个顺序值为:1的实例。
/// </remarks>
/// <returns>
/// 返回:
/// “DataConfig”类的实例在所有实例中的排序的顺序值(第1)。
/// </returns>
/// </summary>
public int GetOrder() => 0; //设定“DataConfig”类的实例在所有实例中的排第1。
#endregion
}
}
2.4 重构appsettings.json文件中的数据库连接配置
"ConnectionStrings": {
//Trusted_Connection=true或Integrated Security=true/SSPI:“Windows凭据”对SQL Server进行身份验证,表示可以在不知道数据库用户名和密码的情况下时,依然可以连接SQL Server数据库。
//"integrated":"security=true是通过“Windows身份认证”对SQL Server数据库进行身份验证,并与SQL Server数据库进行连接;表示可以在不知道数据库用户名和密码的情况下时,依然可以连接SQL Server数据库,如果integrated", "security=false","或者不写,表示一定要输入正确的数据库登录名和密码。": null。
//Persist Security Info:该配置只用于通过“SQL Server身份认证”对SQL Server数据库进行身份验证,并与SQL Server数据库进行连接;简单的理解为"ADO在数据库连接成功后是否保存密码信息",True表示保存,False表示不保存.ADO缺省为True(ADO.net缺省为False,未测试,根据参考资料上说的)。
//MultipleActiveResultSets:它允许在单个连接上执行多重的数据库查询或存储过程,目前只适用于Sql Server 2005及其以上版本;如果不用MultipleActiveResultSets ,则一般报错为sqldatareader未关闭,即需要关闭了之后才能打开另一个。
//Trust Server Certificate:是否使用SSL证书和加密方式,对SQL Server数据库的连接字符串进行加密,该操作属性安全性配置,目前只适用于Sql Server 2005及其以上版本;
//"SqlServerWindows": "Data Source=.;Initial Catalog=ShopDemo;Integrated Security=true;MultipleActiveResultSets=true;Trust Server Certificate=True"
//IIS发布部署连接字符串必须使用“SQL Server身份认证”数据库连接方式,才能实现发布部署程序与数据库的CURD的操作
//SqlServer数据库软件的连接字符串。
"ConnectionString": "Data Source=.;Initial Catalog=ShopDemo;Integrated Security=False;Persist Security Info=False;User ID=zz;Password=zz;MultipleActiveResultSets=true;Trust Server Certificate=True",
"DataProvider": "sqlserver",
//Allow User Variables=True:MySql数据库软件是否支持执行带有参数的SQL命令语句,True:支持。
//MySql数据库软件的连接字符串。
//"ConnectionString": "Server=localhost;User ID=root;Password=xxxxxx;Database=ShopDemo;Allow User Variables=True",
//"DataProvider": "mysql",
"SQLCommandTimeout": "" //注意该值被设定为:空字符串,在“appsettings.json”中如果设定为:null,则会出现警告信息,即使设定为:空字符串,在反序列化操作时依然会实例化为:null。
},
2.5 重构Program.cs文件中的数据库连接依赖注入
//初始化1个数据库连接配置实例。
DataConfig _dataConfig = new DataConfig();
//通过“appsettings.json”文件中数据库连接相关数据,实例化数据库连接配置实例。
builder.Configuration.GetSection(_dataConfig.Name).Bind(_dataConfig, options => options.BindNonPublicProperties = true);
//说明:如果想要“EntityFrameworkCore”中间件支持多数据库软件,则把选择条件中的所有中间件都注入到依赖注入到.Net(Core)框架内置容器即可,
//选择条件来限定当前程序只支持所设定的1个数据库软件,当然“DataConfig”类与“appsettings.json”文件也必须为支持多数据库软件进行重构。
if (_dataConfig.DataProvider.ToString().Equals("sqlserver", StringComparison.InvariantCultureIgnoreCase))
{
//实例化“EntityFrameworkCore”中间件只支持“SqlServer”数据库软件与当前程序进行CURD交互操作。
//把“Microsoft.EntityFrameworkCore.SqlServer”中间件实例,依赖注入到.Net(Core)框架内置容器中。
builder.Services.AddDbContext<EFCoreContext>(
//通过“DbContextOptionsBuilder”实例中的参数实例,为“Microsoft.EntityFrameworkCore.SqlServer”中间件的实例化提供参数实例,
//最终把“Microsoft.EntityFrameworkCore.SqlServer”中间件实例,依赖注入到.Net(Core)框架内置容器中。
//IIS发布部署连接字符串必须使用“SQL Server身份认证”数据库连接方式,才能实现发布部署程序与数据库的CURD的操作。
options => options.UseSqlServer(_dataConfig.ConnectionString));
}
else if (_dataConfig.DataProvider.ToString().Equals("mysql", StringComparison.InvariantCultureIgnoreCase))
{
//实例化“EntityFrameworkCore”中间件只支持“MySql”数据库软件与当前程序进行CURD交互操作。
//把“Microsoft.EntityFrameworkCore.SqlServer”中间件和“Pomelo.EntityFrameworkCore.MySql”实例,依赖注入到.Net(Core)框架内置容器中。
builder.Services.AddDbContext<EFCoreContext>(
//实现“Microsoft.EntityFrameworkCore”中间件实例与“MySql”数据库的连接。
options => options.UseMySql(_dataConfig.ConnectionString, MySqlServerVersion.LatestSupportedServerVersion));
}
F5执行程序不管在 “Microsoft SQL Server”数据库软件中,还是在“MySql”数据库软件中都能自动生“ShopDemo” 数据库及其表。
对以上功能更为具体实现和注释见:230114_009shopDemo(通过类定义实现配置文件(appsettings.json)的读写 )。