C# 根据来自另一个服务的事件修改注入的服务

C# 根据来自另一个服务的事件修改注入的服务,c#,asp.net-core,dependency-injection,C#,Asp.net Core,Dependency Injection,我有以下问题: 我有2服务:SaSb为了让用户能够使用Sb他需要在Sa中执行一个动作,该动作将授予他一个令牌 然后,他将使用此标记执行他将对Sb执行的所有操作 我不希望Sb的所有方法都需要token作为参数。我希望从一开始就将Sb注入servicecollection中,并能够将该token作为内部属性存储(在用户使用Sa之后) 我该怎么做?如何根据另一个服务中的操作更改注入的服务 授予令牌的服务 public class Sa{ //grants token public st

我有以下问题:

我有
2
服务:
Sa

Sb

为了让用户能够使用
Sb
他需要在
Sa
中执行一个动作,该动作将授予他一个
令牌
然后,他将使用此
标记
执行他将对
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(); //<--
var-token=sa.GrantToken();
//现在我想把这个令牌传递给Sb,这样我就可以调用它的动作//而不需要令牌
var result1=sb.Action1();
var result2=sb.Action2();
......

var resultN=sb.action()// 我认为你可以在这里添加另一个抽象概念——抽象工厂

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

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

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

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

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

如注释中所述,您可以创建一个工厂类,该类将负责根据
Sa
授予的令牌创建
Sb
的实例

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);
    }
}
用法

另一种方法: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);
    });
}
public void配置服务(IServiceCollection服务)
{
服务部(sa);
services.AddTransient(提供者=>
{
var sa=provider.GetRequiredService();
var token=sa.GrantToken();
归还新的某人(代币);
});
}

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

如评论中所述,您可以创建一个工厂类,该类将负责根据
Sa
授予的令牌创建
Sb
的实例

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);
    }
}
用法

另一种方法: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);
    });
}
public void配置服务(IServiceCollection服务)
{
服务部(sa);
services.AddTransient(提供者=>
{
var sa=provider.GetRequiredService();
var token=sa.GrantToken();
归还新的某人(代币);
});
}

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

您需要一个sb工厂,该工厂使用从saThat创建的令牌创建实例,或者在调用依赖成员之前在sb上设置令牌。您需要一个sb工厂,该工厂使用从saThat创建的令牌创建实例,或者在调用依赖成员之前在sb上设置令牌,这意味着使用的所有类
ISbFactory
需要依赖于
Sa
才能检索用于创建
Sb
实例的令牌。是的,在此实现中。您可以随时更改术语以创建()并将Sa注入工厂实现。通过这种方式,您封装了创建令牌的逻辑。然而,正确的选择取决于问题的详细信息。这意味着所有使用
ISbFactory
的类都需要依赖
Sa
来检索用于创建
Sb
实例的令牌。是的,在这个实现中。您可以随时更改术语以创建()并将Sa注入工厂实现。通过这种方式,您封装了创建令牌的逻辑。然而,正确的选择取决于问题的细节。比如工厂委托方法。很好的建议。像工厂代表的方法。好建议。