播种数据库时处理依赖注入
Handling dependency injection when seeding the database
我需要为应用程序数据库设置默认用户。我在这个项目中没有使用 Entity Framework,我决定使用 Dapper 来代替。
我能做的最简单的事情就是拥有一个简单的 class,例如 DatabaseConfig
(或 AccountsConfig
)和一个 Seed()
静态方法:
public class DatabaseConfig {
public static void Seed() {
using(var conn = new SqlConnection()) {
conn.ConnectionString = GetConnectionString();
conn.Open();
var query = "insert into users (username, [password]) values (@username, @password)";
var queryParams = new {
username = "Admin",
password = HashedPassword.CreateHash("DefaultSecretKey")
}
conn.Execute(query, queryParams);
}
}
private static string GetConnectionString() {
return ConfigurationManager.ConnectionStrings["appDb"].ConnectionString;
}
}
然后在Global.asax中调用它:
DatabaseConfig.Seed();
我这里有两个依赖:
我调用了一个ConfigurationManager
来获取连接字符串。我不知道这是否是一个坏方法。对于我在应用程序中使用的其他服务,我将连接字符串作为 SimpleInjector 初始化程序中的构造函数参数传递:
private static void InitializeContainer(Container container) {
var appDbConnString = ConfigurationManager.ConnectionStrings["appDb"].ConnectionString;
container.RegisterSingleton<IUsersRepository>(new UsersRepository(appDbConnString));
}
另一个依赖是HashedPassword
class。我不希望它随着时间而改变,但这仍然是一种依赖。我应该解决它吗?我该如何解决?
您正在以静态方式访问 HashedPassword 和 ConfigurationManager,这意味着您需要将它们更改为非静态 classes 以便依赖注入它们。这可以通过更改它们来完成(这可能是不可能的,因为它们不是您的 classes)或将它们包装在实例 class.
中
I call a ConfigurationManager to get a connection string. I don't know if this is a bad approach.
一般情况下,您应该只在应用程序启动时读取配置文件,并且最好只在应用程序的启动路径内。这允许配置文件的读取集中在一个地方,并且它允许应用程序在某些配置值丢失的情况下快速失败。
你似乎遵循了这种做法,所以我会说你做的很好。
The other dependency is HashedPassword class. I don't expect it to change with time but still this is a dependency. Should I resolve it?
因为这个 Seed
方法似乎是你的组合根的一部分,所以对你系统中的其他 classes 有很强的依赖性是可以的。或者让我换种说法,如果使用此依赖项不会造成任何问题(因为您不想孤立地测试代码,或者想要替换、包装、装饰或拦截其中的代码 class), 我会说这没问题。
如果您希望此 HashesPassword
class 可注入,则必须将其设为实例 class。在那种情况下,您可能应该将其隐藏在抽象背后(如 IHashPashword
)并将其作为参数传递给 Seed()
方法,或者您应该将 DatabaseConfig
提升为非静态 class 使用非静态方法并将 IHashPashword
抽象注入其构造函数。这允许您从容器中解析 DatabaseConfig
。
我需要为应用程序数据库设置默认用户。我在这个项目中没有使用 Entity Framework,我决定使用 Dapper 来代替。
我能做的最简单的事情就是拥有一个简单的 class,例如 DatabaseConfig
(或 AccountsConfig
)和一个 Seed()
静态方法:
public class DatabaseConfig {
public static void Seed() {
using(var conn = new SqlConnection()) {
conn.ConnectionString = GetConnectionString();
conn.Open();
var query = "insert into users (username, [password]) values (@username, @password)";
var queryParams = new {
username = "Admin",
password = HashedPassword.CreateHash("DefaultSecretKey")
}
conn.Execute(query, queryParams);
}
}
private static string GetConnectionString() {
return ConfigurationManager.ConnectionStrings["appDb"].ConnectionString;
}
}
然后在Global.asax中调用它:
DatabaseConfig.Seed();
我这里有两个依赖:
我调用了一个
ConfigurationManager
来获取连接字符串。我不知道这是否是一个坏方法。对于我在应用程序中使用的其他服务,我将连接字符串作为 SimpleInjector 初始化程序中的构造函数参数传递:private static void InitializeContainer(Container container) { var appDbConnString = ConfigurationManager.ConnectionStrings["appDb"].ConnectionString; container.RegisterSingleton<IUsersRepository>(new UsersRepository(appDbConnString)); }
另一个依赖是
HashedPassword
class。我不希望它随着时间而改变,但这仍然是一种依赖。我应该解决它吗?我该如何解决?
您正在以静态方式访问 HashedPassword 和 ConfigurationManager,这意味着您需要将它们更改为非静态 classes 以便依赖注入它们。这可以通过更改它们来完成(这可能是不可能的,因为它们不是您的 classes)或将它们包装在实例 class.
中I call a ConfigurationManager to get a connection string. I don't know if this is a bad approach.
一般情况下,您应该只在应用程序启动时读取配置文件,并且最好只在应用程序的启动路径内。这允许配置文件的读取集中在一个地方,并且它允许应用程序在某些配置值丢失的情况下快速失败。
你似乎遵循了这种做法,所以我会说你做的很好。
The other dependency is HashedPassword class. I don't expect it to change with time but still this is a dependency. Should I resolve it?
因为这个 Seed
方法似乎是你的组合根的一部分,所以对你系统中的其他 classes 有很强的依赖性是可以的。或者让我换种说法,如果使用此依赖项不会造成任何问题(因为您不想孤立地测试代码,或者想要替换、包装、装饰或拦截其中的代码 class), 我会说这没问题。
如果您希望此 HashesPassword
class 可注入,则必须将其设为实例 class。在那种情况下,您可能应该将其隐藏在抽象背后(如 IHashPashword
)并将其作为参数传递给 Seed()
方法,或者您应该将 DatabaseConfig
提升为非静态 class 使用非静态方法并将 IHashPashword
抽象注入其构造函数。这允许您从容器中解析 DatabaseConfig
。