利用仅初始化设置程序,使配置选项在ASP.NET Core MVC 5中不可变,以避免不必要的分配并消除出现错误的机会。

不变性使代码随着时间的推移更易于编写,测试和维护。但是,许多编程语言不支持不变性。直到最近,C#才开箱即用地支持不变性。这在C#9中会有所变化。
现在,您可以利用仅初始化属性将应用程序选项配置为不可变实例。毕竟,它们基本上是应用程序常数。您不希望在应用程序的生存期内更改它们。
本文讨论了不可变的对象,为什么我们要使我们的配置信息不可变,以及如何在ASP.NET Core MVC 5中实现这一点。
若要使用本文提供的代码示例,您应该在系统中安装Visual Studio 2019。如果您还没有副本,则可以在此处下载Visual Studio 2019。
在Visual Studio 2019中创建ASP.NET Core MVC 5项目
首先,让我们在Visual Studio中创建一个ASP.NET Core项目。按照这些步骤将在Visual Studio 2019中创建一个新的ASP.NET Core MVC 5项目。
- 启动Visual Studio IDE。
- 点击“创建新项目”。
- 在“创建新项目”窗口中,从显示的模板列表中选择“ ASP.NET Core Web App(模型-视图-控制器)”。
- 点击下一步。
- 在“配置新项目”窗口中,指定新项目的名称和位置。
- 根据您的喜好,可以选择选中“将解决方案和项目放在同一目录中”复选框。
- 点击下一步。
- 在接下来显示的“其他信息”窗口中,从顶部的下拉列表中选择.NET 5.0作为目标框架。将“身份验证类型”保留为“无”(默认)。
- 确保未选中“启用Docker”,“配置HTTPS”和“启用Razor运行时编译”复选框,因为在此我们将不使用任何这些功能。
- 单击创建。
将创建一个新的ASP.NET Core MVC 5项目。我们将在本文的后续部分中使用该项目。
什么是不可变的对象?
不可变对象定义为创建后不能更改的对象。字符串是C#中不可变类型的示例。创建字符串对象后,您将无法更改它。当您尝试更改字符串对象时,会在内存中创建一个新的字符串实例,并在其中包含新数据。
相比之下,StringBuilder的实例是可变对象。C#中的StringBuilder是可变的字符序列,可以根据需要扩展为存储更多字符。与更改字符串不同,更改StringBuilder实例不会在内存中创建新实例。
对于许多用例,例如数据库配置元数据类,不变性是理想的功能。不变性的另一个用例是数据传输对象(DTO)。DTO实例通常被序列化,因此它可以独立于用户端使用的技术。自然地,当在数据库和客户端之间传输数据对象时,您要确保不能更改该对象-这正是DTO的目的。
您还可以在C#中拥有不可变的集合。不可变集合是类型的集合,其成员在创建后就不能更改。要使用不可变集合,应在项目中安装System.Collection.Immutable NuGet包。您可以阅读我以前的文章更不可变的集合在这里。
使IOptions在ASP.NET Core MVC 5中不可变
在ASP.NET Core MVC 5中工作时,通常会将应用程序的设置存储在诸如appsettings.json之类的文件中,然后在应用程序需要它们时将其读回。要读取应用程序中的那些设置,可以使用IOptions <T>在Startup类的ConfigureServices方法中利用依赖项注入。
现在考虑以下代码片段,该片段显示了一个名为DbConfiguration的类,该类用于存储数据库配置信息。
public class DbConfiguration { public string Server { get; init; } public string Provider { get; init; } public string Database { get; init; } public int Port { get; init; } public string UserName { get; init; } public string Password { get; init; } }
请注意上面每个数据库配置属性的仅初始化设置器的声明。仅初始化设置器允许您以通常的方式设置这些值,但是这些属性在其初始构造完成后将变为只读。
您可以在appsettings.json文件中指定数据库配置信息,如下所示。
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "DbConfiguration": { "Server": "Server01", "Provider": "Provider01", "Database": "Database01", "Port": 1433, "UserName": "User01", "Password": "Password01" }, "AllowedHosts": "*" }
以下代码段显示了如何将appsettings.json文件中指定的数据库配置信息绑定到DbConfiguration的实例。
services.Configure<DbConfiguration> (options => Configuration.GetSection("DbConfiguration").Bind(options));
或者,您可以使用以下代码进行绑定,然后将数据库配置实例添加为单例服务。
var dbConfiguration = new DbConfiguration(); Configuration.Bind("DbConfiguration", dbConfiguration); services.AddSingleton(dbConfiguration);
这是ConfigureServices方法的完整代码供您参考:
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.Configure<DbConfiguration> (options => Configuration.GetSection("DbConfiguration").Bind(options)); }
在ASP.NET Core MVC 5中的控制器中读取配置数据
在HomeController类中,声明一个DbConfiguration类型的只读实例变量,如下所示。
private readonly DbConfiguration _dbConfiguration;
要从控制器访问DbConfiguration实例,我们将利用构造注入,如下面的代码片段所示。
public HomeController(ILogger<HomeController> logger, IOptions<DbConfiguration> dbConfiguration) { _logger = logger; _dbConfiguration = dbConfiguration.Value; }
注意上面构造函数的参数中IOptions <DbConfiguration>实例的用法。使用Value属性在构造函数中初始化名为_dbConfiguration的DbConfiguration实例。
如果现在尝试将值分配给DbConfiguration实例的任何init-only属性或索引器,则将看到下面的图1所示的编译时错误消息。

这正是我们想要实现的目标。名为_dbConfiguration的DbConfiguration实例是不可变的。您可以从其属性读取值,但不能以任何方式更改其任何属性的值。
从C#9开始,您可以使用init访问器来代替属性和索引器的set访问器。这样做将确保这些属性是只读的。您只能在创建它们所属的类的实例时将值分配给这些属性。
原创文章,作者:冰封一夏,如若转载,请注明出处:http://www.nncjzx.com/1373.html
关注本站公众号获取更多实时内容