在一个带有其他参数的类中注入类型化的HttpClient

3

我有一个Worker Service应用程序中的类,它由两个需要被注入的字符串参数构成,因此无法注册为服务:

public MyService(ILogger<MyService> logger, HttpClient client, string username, string password)
{
    this._logger = logger;
    this._client = client;
    this.Username = username;
    this.Password = password;
}

我定义了这个构建器:

var builder = Host.CreateDefaultBuilder(args);
builder.ConfigureServices((c, s) =>
        {
            s.AddHttpClient<MyService>(client => { 
                client.BaseAddress = new Uri("http://www.myserviceurl.com"); 
            });
            s.AddTransient<IMyService>(sp => new MyService(
                sp.GetRequiredService<ILogger<MyService>>(),
                sp.GetRequiredService<HttpClient>(),
                "username", 
                "password"
            ));
        });

但是通过IServiceProvider.GetRequiredService()注入的HttpClient并不是我在IServiceCollection中使用AddHttpClient()方法添加的那个,因为BaseAddress(以及其他我为了简洁省略的默认标头)为空

相反,如果我从构造函数中删除另外两个字符串参数,并让IServiceProvider解析依赖关系,我就可以得到正确的HttpClient实例

我肯定可能没有理解GetRequiredService的工作原理,我仍在学习IServiceProvider的工作原理,我想了解我的错误所在。

编辑:

另外,我发现如果我使用命名客户端而不是类型化客户端

s.AddHttpClient("MyService",client => { 
                client.BaseAddress = new Uri("http://www.myserviceurl.com"); 
            });

我通过以下方式解决依赖关系:

s.AddTransient<IMyService>(sp => new MyService(
                sp.GetRequiredService<ILogger<MyService>>(),
                sp.GetRequiredService<IHttpClientFactory>().CreateClient("MyService"),
                "username", 
                "password"
            ));

一切都如预期的那样工作。与Typed HttpClient有何区别?

2个回答

4

您可以使用此重载的 AddHttpClient

builder.ConfigureServices((c, s) =>
{
    s.AddHttpClient<IMyService, MyService>((client, sp) =>
    {
        client.BaseAddress = new Uri("http://www.myserviceurl.com");

        return new MyService(
            sp.GetRequiredService<ILogger<MyService>>(),
            client,
            "username",
            "password"
        );
    });
});

谢谢您的答复,但我知道它不能注入System.String。 看起来如果我使用具有AddHttpClient定义的GetRequiredService<HttpClient>(),它将尝试从0重新创建MyService构造函数,因此无法注入用户名、密码字符串参数。 - exSnake
为什么要使用 GetRequiredService<HttpClient>()?定义一个类型化的 http 客户端的原因是,这样你就不必将 HttpClient 注入到你的服务中。相反,你注入 IMyService - Dimitris Maragkos
1
我实际上在初始化时犯了一个错误,所以AddHttpClient会完全用这个构造函数替换AddTransient吗? - exSnake
1
是的,它替换了AddTransient。 - Dimitris Maragkos

0

在我看来,不要使用这个。

s.AddTransient<IMyService>(sp => new MyService(
                sp.GetRequiredService<ILogger<MyService>>(),
                sp.GetRequiredService<IHttpClientFactory>().CreateClient("MyService"),
                "username", 
                "password"
            ));

只需从另一个类中注入用户名或密码。或在Configuration中设置值,并在构造函数中设置它。

选项1:

s.AddTransient<IMyService, MyService>(); //I'm omitting code to set up http client

然后在构造函数中

public MyService(ILogger<MyService> logger, HttpClient client, IConfiguration config)
{
    this._logger = logger;
    this._client = client;
    this.Username = config["username"]; //set in user secrets see below
    this.Password = config["password"]; //set in user secrets see below
}

或者选项2

//create a credentials singleton class and inject that in MyService
s.AddSingleton<CredentialsClass>(new CredentialsClass("username","password"));
s.AddTransient<IMyService, MyService>();// I'm omiting code for http client

然后在构造函数中

public MyService(ILogger<MyService> logger, HttpClient client, CredentialsClass creds)
    {
        this._logger = logger;
        this._client = client;
        //creds.UserName and creds.Password
    }

另外:从未有过代码凭证。在本地开发中使用UserSecrets


1
目前凭据来自于一个仅使用IOption实例化的配置文件,我的做法是循环这些配置并实例化各种对象。在这种情况下,我应该如何使用不同的参数实例化多个MyService类型的对象? 实际上我正在做类似于这样的事情:options.MyService.ForEach(p => s.AddTransient<IMyService>(m => new MyService(...., p.Username, p.Password))); 因此,在Worker中我注入了IEnumerable<IMyService>。 - exSnake
那么凭证是根据情况变化的吗?我不确定你在问什么。也许你可以编辑一下你的问题? - Train
不,我会使用不同的参数实例化多个相同类型的对象。 - exSnake
使用不同参数的标准是什么? - Train
它们只是不同的凭据。这是一个后台工作程序,使用不同的凭据向API端点发出查询并解析输出。每个凭据都会产生不同的输出。 - exSnake
在这种情况下,后台工作器应该根据查询设置凭据,而不是注入它们。只需调用类似 .SetCreds(username, password); 的方法即可。 - Train

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接