在来自其他服务的事件上修改注入的服务

时间:2019-01-17 10:51:36

标签: c# asp.net-core dependency-injection

我有以下问题:

我有2服务:
Sa
Sb
为了使用户能够使用sb他需要在Sa中执行一项操作,这将授予他token
然后,他将使用此token来执行将在Sb上执行的所有操作。

我不希望Sb的所有方法都需要token作为参数。我想从一开始就将Sb插入servicecollection中,并能够存储token作为内部属性(在用户使用Sa之后),

我该怎么做?如何根据另一个服务中的操作更改注入的服务。

授予令牌的服务

public class Sa{
    //grants token
    public string GrantToken(string username);
}

对事件具有可设置属性的服务

public class Sb{
    private internalService internalService;
    public ClassName(InternalService internalService)
    {
        this.internalService=internalService;
    }
    public string Token{get;set;}


    ///all these actions would  need the user to provide the token as parameter
    /// i want to somehow set the `Token` property of Sb after the Sa grants the token
    public void Action1(/*string token */){
        this.internalService.DoAction1(Token);

    }
    public void Action2(/*string token */){
        this.internalService.DoAction2(Token);
    }
    public void ActionN(){
        this.internalService.DoActionN(Token);
    }
}


//internal service that needs the token
public class InternalService
{
    public void DoAction1(string token);
    public void DoAction2(string token);
    //.....//
    public void DoActionN(string token);
}
`

启动

 public void ConfigureServices(IServiceCollection services) {
    Sa sa=new Sa();
    Sb sb=new Sb(); //i want this injected from the get-go but to have the `Token` property set-able 
    InternalService ins=new InternalService();
    services.AddSingleton(ins);
    services.AddTransient(sa);
    services.AddTransient(sb);
}

场景

///我们所在的类中有一个Sa和一个Sb

var token=sa.GrantToken(); 
//i want now this token to be passed to Sb so i can then call its actions //without the need of the token
var result1=sb.Action1();
var result2=sb.Action2();
......
var resultN=sb.ActionN(); //<--

2 个答案:

答案 0 :(得分:2)

正如注释中已经提到的那样,您可以创建一个工厂类,该工厂类将根据Sb授予的令牌来创建Sa的实例。

public interface ISbFactory
{
    Sb Create();
}

public class SbFactory : ISbFactory
{
    private readonly Sa _sa;

    public SbFactory(Sa sa) => _sa = sa;

    public Sb Create()
    {
        var token = _sa.GrantToken();
        return new Sb(token);
    }
}

用法

public class ConsumerOfSb
{
    private readonly ISbFactory _sbFactory;

    public ConsumerOfSb(ISbFactory sbFactory) => _sbFactory = sbFactory;

    public void Execute()
    {
        var sb = _sbFactory.Create();
        sb.ExecuteActionOne();
    }
}

另一种方法:ASP.NET依赖项注入提供带有“工厂动作”的重载方法。因此,您可以注册一个函数,该函数将在每次需要Sb实例作为依赖项时调用。

public void ConfigureServices(IServiceCollection services) 
{
    services.AddTransient(sa);
    services.AddTransient<Sb>(provider =>
    {
        var sa = provider.GetRequiredService<Sa>();
        var token = sa.GrantToken();
        return new Sb(token);
    });
}

使用这种方法,Sb的使用者不需要依赖工厂。

答案 1 :(得分:0)

我认为您可以在此处添加另一个抽象-例如Sb的抽象工厂。

    public interface ISbFactory
    {
        SbFactory Create(string token);
    }

现在依赖于Sb的客户端类应将其更改为ISbFactory。通过这种方法,您可以负责将令牌设置为出厂,而不是修改已经创建的服务。