如何使用 C# 代码覆盖 config.json 数据?
How to override config.json data using C# code?
我关注了这个关于如何将 IOC 与 Autofac 结合使用的博客 here,这是第一次听说 IOC 和 autoFac。
我已经从 link 提供的博客下载了该项目,我一直在浏览该项目,我正试图找出 类:
public class DatabaseSettings
{
public string ConnectionString { get; protected set; }
public int TimeoutSeconds { get; protected set; }
}
public class UserSettings
{
public string DefaultUsername { get; protected set; }
public bool ActiveByDefault { get; protected set; }
}
... 无需调用 'Database reader'?
中的加载函数即可填充
是不是因为(这些):
public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
public T LoadSection<T>() where T : class, new() => LoadSection(typeof(T)) as T;
如果是上面的代码,它们是什么(这样我就可以了解它们是如何工作的)?
最后一个问题,是否可以使用这种方法将数据保存回 config.json?
像
这样的条目
public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
只是意味着您可以在函数中访问时使用 "generic" 语法。这比将 Type 作为方法参数传递要简洁一些,并且还意味着您将返回一个 strongly-typed 对象。上面的另一种写法是:
public T Load<T>() where T : class, new()
{
var type = typeof(T);
var loaded = Load(type);
return loaded as T;
}
这是一个有用的语言特性,但与 IoC 本身无关。 IoC 魔法本身主要包含在 SettingsModule 中。这个位:
builder.RegisterInstance(new SettingsReader(_configurationFilePath, _sectionNameSuffix))
.As<ISettingsReader>()
.SingleInstance();
告诉 Autofac 在任何人请求 ISettingsReader(As<> 位)时提供一个 SettingsReader(RegisterInstance 部分)。 .SingleInstance 意味着它将 SettingsReader 视为单例:只会创建其中一个,并将同一对象传递到请求 ISettingsReader 的任何地方。
这一部分
var settings = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.Name.EndsWith(_sectionNameSuffix, StringComparison.InvariantCulture))
.ToList();
settings.ForEach(type =>
{
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(type))
.As(type)
.SingleInstance();
});
只是一种奇特的方式,当它看到对 DatabaseSettings 或 UserSettings 的请求时,自动告诉它该做什么。根据最初的问题,this 是实际调用 Load 函数的地方。一个更简单的方法是:
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(typeof(DatabaseSettings))).As<DatabaseSettings>();
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(typeof(UserSettings))).As<UserSettings>();
您可以将这些逻辑写成 "when a DatabaseSettings object is requested (.As), find an implementation for ISettingsReader, and then call LoadSection on that (the first part)"
容器中的其他地方 class 还有这个:
builder.RegisterType<UserService>().As<IUserService>();
这只是告诉 Autofac 为 IUserService 做什么。
结果是我们在主要应用方法中的位置:
using (var scope = container.BeginLifetimeScope())
{
var userService = scope.Resolve<IUserService>();
如果没有 main 方法 "knowing" 关于它使用的具体类型的任何信息,我们将得到一个功能齐全的 IUserService。在内部,Autofac 将通过插入链中每种类型的所有构造函数参数来解析所需的依赖链。这可能看起来像:
- 已请求 IUserService
- 解析用户服务
- 解析 IDatabase
- return 数据库
- 解析用户设置
- 解析 ISettingsReader
- return 设置阅读器
- 在 ISettingsReader 上调用 LoadSection
- return 生成了 UserSettings 对象
关于你的最后一个问题 - 是的!但是,IoC 不一定能让您这样做。它只是让您绑定在一起并访问您创建的任何自定义 classes 以允许保存。
您可以像这样创建一个新界面
public interface ISettingsWriter
{
void Save<T>(T settings);
}
然后出于某种原因,您添加了一个方法来访问 UserService 中的方法:
public class UserService : IUserService
{
private readonly IDatabase _database;
private readonly UserSettings _userSettings;
private readonly ISettingsWriter _settingsWriter;
public UserService(IDatabase database, UserSettings userSettings, ISettingsWriter settingsWriter)
{
_database = database;
_userSettings = userSettings;
_settingsWriter = settingsWriter;
}
public void UpdateUserSettings()
{
_settingsWriter.Save(new UserSettings());
}
以这种方式使用它比在原始示例代码中更简单一些 - 我建议您采用这种方法,直到您更加习惯为止。这意味着您唯一需要添加的另一件事是设置编写器的注册,例如:
builder.RegisterType<SettingsWriter>()
.As<ISettingsWriter>();
我关注了这个关于如何将 IOC 与 Autofac 结合使用的博客 here,这是第一次听说 IOC 和 autoFac。
我已经从 link 提供的博客下载了该项目,我一直在浏览该项目,我正试图找出 类:
public class DatabaseSettings
{
public string ConnectionString { get; protected set; }
public int TimeoutSeconds { get; protected set; }
}
public class UserSettings
{
public string DefaultUsername { get; protected set; }
public bool ActiveByDefault { get; protected set; }
}
... 无需调用 'Database reader'?
中的加载函数即可填充是不是因为(这些):
public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
public T LoadSection<T>() where T : class, new() => LoadSection(typeof(T)) as T;
如果是上面的代码,它们是什么(这样我就可以了解它们是如何工作的)?
最后一个问题,是否可以使用这种方法将数据保存回 config.json?
像
这样的条目public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
只是意味着您可以在函数中访问时使用 "generic" 语法。这比将 Type 作为方法参数传递要简洁一些,并且还意味着您将返回一个 strongly-typed 对象。上面的另一种写法是:
public T Load<T>() where T : class, new()
{
var type = typeof(T);
var loaded = Load(type);
return loaded as T;
}
这是一个有用的语言特性,但与 IoC 本身无关。 IoC 魔法本身主要包含在 SettingsModule 中。这个位:
builder.RegisterInstance(new SettingsReader(_configurationFilePath, _sectionNameSuffix))
.As<ISettingsReader>()
.SingleInstance();
告诉 Autofac 在任何人请求 ISettingsReader(As<> 位)时提供一个 SettingsReader(RegisterInstance 部分)。 .SingleInstance 意味着它将 SettingsReader 视为单例:只会创建其中一个,并将同一对象传递到请求 ISettingsReader 的任何地方。
这一部分
var settings = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.Name.EndsWith(_sectionNameSuffix, StringComparison.InvariantCulture))
.ToList();
settings.ForEach(type =>
{
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(type))
.As(type)
.SingleInstance();
});
只是一种奇特的方式,当它看到对 DatabaseSettings 或 UserSettings 的请求时,自动告诉它该做什么。根据最初的问题,this 是实际调用 Load 函数的地方。一个更简单的方法是:
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(typeof(DatabaseSettings))).As<DatabaseSettings>();
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(typeof(UserSettings))).As<UserSettings>();
您可以将这些逻辑写成 "when a DatabaseSettings object is requested (.As), find an implementation for ISettingsReader, and then call LoadSection on that (the first part)"
容器中的其他地方 class 还有这个:
builder.RegisterType<UserService>().As<IUserService>();
这只是告诉 Autofac 为 IUserService 做什么。
结果是我们在主要应用方法中的位置:
using (var scope = container.BeginLifetimeScope())
{
var userService = scope.Resolve<IUserService>();
如果没有 main 方法 "knowing" 关于它使用的具体类型的任何信息,我们将得到一个功能齐全的 IUserService。在内部,Autofac 将通过插入链中每种类型的所有构造函数参数来解析所需的依赖链。这可能看起来像:
- 已请求 IUserService
- 解析用户服务
- 解析 IDatabase
- return 数据库
- 解析用户设置
- 解析 ISettingsReader
- return 设置阅读器
- 在 ISettingsReader 上调用 LoadSection
- return 生成了 UserSettings 对象
- 解析 ISettingsReader
- 解析 IDatabase
- 解析用户服务
关于你的最后一个问题 - 是的!但是,IoC 不一定能让您这样做。它只是让您绑定在一起并访问您创建的任何自定义 classes 以允许保存。
您可以像这样创建一个新界面
public interface ISettingsWriter
{
void Save<T>(T settings);
}
然后出于某种原因,您添加了一个方法来访问 UserService 中的方法:
public class UserService : IUserService
{
private readonly IDatabase _database;
private readonly UserSettings _userSettings;
private readonly ISettingsWriter _settingsWriter;
public UserService(IDatabase database, UserSettings userSettings, ISettingsWriter settingsWriter)
{
_database = database;
_userSettings = userSettings;
_settingsWriter = settingsWriter;
}
public void UpdateUserSettings()
{
_settingsWriter.Save(new UserSettings());
}
以这种方式使用它比在原始示例代码中更简单一些 - 我建议您采用这种方法,直到您更加习惯为止。这意味着您唯一需要添加的另一件事是设置编写器的注册,例如:
builder.RegisterType<SettingsWriter>()
.As<ISettingsWriter>();