我正在尝试将
Microsoft.Extensions.DependencyInjection
用于 UI 应用程序,只是因为一个有趣的 UI 框架使用了它。然而,根据我目前的理解,对于这个用例来说,它似乎是有限的。该领域的一个常见用例是在使用现场进行专业化建设。
假设我们在程序启动时注册一个服务:
services.AddScoped<IWorkspace, Workspace>();
当用户想要打开一个新的工作区时,该工作区将需要一些该实例化特有的参数,因为可以有多个工作区,并且工作区的确切路径不是静态固定的。
一种方法是构造类型需要构造后初始化:
var workspace = workspaceProvider.GetRequiredService<IWorkspace>();
workspace.Initialize(pathToWorkspace);
有些人主张注入工厂,人们可以这样做:
var workspaceProvider = serviceProvider.GetRequiredService<IWorkspaceProvider>();
var workspace = workspaceProvider.New(pathToWorkspace);
对于像这样的简单案例来说,这可能就足够了。然而,如果要将这种模式应用于更多类型,那么对我来说,它似乎相当繁琐。
.NET 8 中的密钥服务在这种情况下似乎没有用,因为必须提前知道密钥,因为它是在配置
IServiceProvider
时注册的。
有没有更简单的方法?
我更多地思考的是:
var workspacePath = new WorkspacePath(someWorkspacePathString);
var workspace = serviceProvider.WithTransient<WorkspacePath>(workspacePath).GetRequiredService<IWorkspace>();
有点像“依赖注入的部分应用”。我们部分注册创建实例所需的依赖项,然后在使用站点提供剩余的依赖项 (
WithTransient
)。这也将控制何时创建新实例以及何时重用现有实例,因为 WithTransient
将指定赋予每个实例唯一性的参数。
我认为你需要选项:
public class WorkspaceOptions {
public string Path { get; set; }
}
2a。将适当的数据放入 appsettings.json 并将其绑定到类:
{
"MyWorkspaceOptions" : {
"Path": "/put/your/path/here"
}
}
services.Configure<WorkspaceOptions>(configuration.GetSection("MyWorkspaceOptions"));
services.AddScoped<IWorkspace, Workspace>();
2b。或者直接在代码中赋值:
services.Configure<WorkspaceOptions>(opt => {
opt.Path = "/some/path";
});
services.AddScoped<IWorkspace, Workspace>();
public class Workspace: IWorkspace {
private readonly WorkspaceOptions options;
public Workspace(IOptions<WorkspaceOptions> myOptions) {
options = myOptions.Value;
}
public void Foo() {
var myFile = options.Path + "/filename.txt";
...
}
}
您甚至可以将
IOptions<>
替换为 IOptionsSnapshot<>
,让您的应用在编辑 appsettings.json 时自动更新值而无需重新启动。