Azure Functions 中的依赖注入无法为类型化的 HttpClient 调用配置委托?
Dependency injection in Azure Functions fails to invoke configuration delegate for a typed HttpClient?
我有以下 class:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient<SomeAzureFunction>(c =>
{
// some code
});
}
}
}
委托 c => { // some code }
从未真正被调用过?怎么回事?
Microsoft clearly states 他们在此示例中使用 Microsoft.Extensions.Http
:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient();
builder.Services.AddSingleton<IMyService>((s) => {
return new MyService();
});
builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
}
}
}
我的用法唯一不同的是,我不是简单地注册 IHttpClientFactory
,而是注册一个类型化的客户端。
azure 函数带有定时器触发器。
SomeAzureFunction
的签名如下:
public SomeAzureFunction(HttpClient httpClient)
编辑: 似乎如果我将构造函数更改为接受 IHttpClientFactory
然后对其执行以下操作:IHttpClientFactory.CreateClient(nameof(SomeAzureFunction))
它最终决定执行委托,但我不明白为什么在我注入 HttpClient
.
时它不会自动执行
要了解这里发生了什么,我们需要更深入地研究一下。这与 Azure Functions 无关,与依赖注入和类型化客户端注册为瞬态服务的方式有关。
类型化客户端的类型确实在 DI 容器中注册为临时服务,但它正在注册 Func<IServiceProvider, TService> implementationFactory
delegate。只有当类型被传递到依赖注入的构造函数时才会调用该委托(即它被用于 DI)。
这意味着如果我们有一个类型 A
,并且我们通过 IServiceCollection.AddHttpClient<A>()
将该类型注册为类型化客户端,那么如果我们在任何 Azure Functions 中传递 A
构造函数或控制器(用于 Web 应用程序),它将按我们预期的方式解析 - A
内的 HttpClient
将成功成为 DI.
但我们实际上不希望在其他构造函数中传递 A
。我们希望 A
简单地对“输入的”HttpClient
进行 DI。然后我们只需要在 IServiceCollection
中使用适当的范围注册类型 A
。我们通过调用 IServiceCollection.AddTransient<A>();
.
来做到这一点
我说“类型化”,因为本质上,我上面提到的那个代表实际上就是“类型化”HttpClient
的全部内容。实际上 - 每个 HttpClient
注册的都是一个“命名”客户端 - 包括 Typed
个客户端。它们只会带来将命名的 HttpClient
注册到您定义的类型的好处,因此您可以对该类型使用依赖注入,而不是用注入 IHttpClientFactory
的经典方式来代替,然后调用 IHttpClientFactory.CreateClient("namedClient");
“类型”的名称 HttpClient
是您类型的名称。如果您这样做 IServiceCollection.AddHttpClient<HelloWorld>();
,命名的客户端将被称为“HelloWorld”。
我无法理解为什么 通过 Func<IServiceProvider, TService>
委托注册的服务会以这种方式运行,所以如果有人提供更多详细信息,我将不胜感激。
我有以下 class:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient<SomeAzureFunction>(c =>
{
// some code
});
}
}
}
委托 c => { // some code }
从未真正被调用过?怎么回事?
Microsoft clearly states 他们在此示例中使用 Microsoft.Extensions.Http
:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient();
builder.Services.AddSingleton<IMyService>((s) => {
return new MyService();
});
builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
}
}
}
我的用法唯一不同的是,我不是简单地注册 IHttpClientFactory
,而是注册一个类型化的客户端。
azure 函数带有定时器触发器。
SomeAzureFunction
的签名如下:
public SomeAzureFunction(HttpClient httpClient)
编辑: 似乎如果我将构造函数更改为接受 IHttpClientFactory
然后对其执行以下操作:IHttpClientFactory.CreateClient(nameof(SomeAzureFunction))
它最终决定执行委托,但我不明白为什么在我注入 HttpClient
.
要了解这里发生了什么,我们需要更深入地研究一下。这与 Azure Functions 无关,与依赖注入和类型化客户端注册为瞬态服务的方式有关。
类型化客户端的类型确实在 DI 容器中注册为临时服务,但它正在注册 Func<IServiceProvider, TService> implementationFactory
delegate。只有当类型被传递到依赖注入的构造函数时才会调用该委托(即它被用于 DI)。
这意味着如果我们有一个类型 A
,并且我们通过 IServiceCollection.AddHttpClient<A>()
将该类型注册为类型化客户端,那么如果我们在任何 Azure Functions 中传递 A
构造函数或控制器(用于 Web 应用程序),它将按我们预期的方式解析 - A
内的 HttpClient
将成功成为 DI.
但我们实际上不希望在其他构造函数中传递 A
。我们希望 A
简单地对“输入的”HttpClient
进行 DI。然后我们只需要在 IServiceCollection
中使用适当的范围注册类型 A
。我们通过调用 IServiceCollection.AddTransient<A>();
.
我说“类型化”,因为本质上,我上面提到的那个代表实际上就是“类型化”HttpClient
的全部内容。实际上 - 每个 HttpClient
注册的都是一个“命名”客户端 - 包括 Typed
个客户端。它们只会带来将命名的 HttpClient
注册到您定义的类型的好处,因此您可以对该类型使用依赖注入,而不是用注入 IHttpClientFactory
的经典方式来代替,然后调用 IHttpClientFactory.CreateClient("namedClient");
“类型”的名称 HttpClient
是您类型的名称。如果您这样做 IServiceCollection.AddHttpClient<HelloWorld>();
,命名的客户端将被称为“HelloWorld”。
我无法理解为什么 通过 Func<IServiceProvider, TService>
委托注册的服务会以这种方式运行,所以如果有人提供更多详细信息,我将不胜感激。