更新依赖注入的单例

jay*_*y93 8 c# .net-core asp.net-core-2.0

我在运行时生成一个单例

public void ConfigureServices(IServiceCollection services)
{
    var applications = Utils.generateApplications()
    services.AddSingleton<ApplicationModel[]>(applications);
    services.AddMvc();
}
Run Code Online (Sandbox Code Playgroud)

我以后如何更新注入ApplicationModel[]全新的ApplicationModel[]. 我的应用程序中有一个功能,用户可以使用该功能来触发应用程序上的数据刷新,但是如何更新底层注入的单例,以便所有未来的注入都将使用更新的应用程序?我有一个函数Utils.generateApplications()可以获取最新的应用程序列表并返回ApplicationModel[]. 如果有意义的话,如何用新对象覆盖旧的注入单例以注入到将来的调用中?

我有一些代码:

public void UpdateData()
{
    var applications = Utils.generateApplications()
    //How do I set applications to replace the injected singleton for all future injections?
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*man 5

您应该使用额外的间接层。我认为最简单的方法是使用抽象工厂。定义一个类似这样的接口:

interface IApplicationModelFactory
{
    public ApplicationModel[] GetModel();
}
Run Code Online (Sandbox Code Playgroud)

使用更新模型所需的方法定义第二个接口:

interface IApplicationModelUpdate
{
    void UpdateModel();
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以将ApplicationModel[]注册从单一实例更改为范围并委托给工厂:

var modelFactory = new ApplicationModelFactory();
services.AddSingleton<IApplicationModelFactory>(modelFactory);
services.AddSingleton<IApplicationModelUpdate>(modelFactory);

services.AddScoped<ApplicationModel[]>(provider =>
    provider.GetRequiredService<IApplicationModelFactory>().GetModel());
Run Code Online (Sandbox Code Playgroud)

注入IApplicationModelUpdate更新模型的类型和ApplicationModel[]使用模型的类型。这样做的优点是,为同一请求解析的所有类型都将获得模型的一致视图,即使它在处理该请求的过程中发生了变化。

您也可以注入IApplicationModelFactory消费者代码,但我认为直接注入模型更好。使用工厂可能会导致不同的代码在同一请求期间看到不同的模型。模型的可变性也是消费者代码不必担心的实现细节。


Joh*_* Wu 5

我不会那样胡闹依赖注入。相反,注入一个工厂,并编写返回正确实例所需的任何逻辑。

简单工厂:

interface IApplicationModelFactory
{
    ApplicationModel[] Model { get; }
}

class ApplicationModelFactory : IApplicationModelFactory
{
    public ApplicationModel[] Model { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

登记:

services.AddSingleton<IApplicationModelFactory>
(
    new ApplicationModelFactory[] { Model = util.generateApplications() }
)
Run Code Online (Sandbox Code Playgroud)

接收注入的类:

class Foo
{
    protected readonly IApplicationModelFactory _factory;

    public Foo(IApplicationModelFactory injected)
    {
        _factory = injected;
    }

    protected ApplicationModel[] => _factory.Model;

    public void Bar()
    {
        DoSomethingWithModel(this.ApplicationModel);
    }
}      
Run Code Online (Sandbox Code Playgroud)