diff --git a/src/Dapr.AI/Conversation/DaprConversationClientBuilder.cs b/src/Dapr.AI/Conversation/DaprConversationClientBuilder.cs
index a8a7983f1..f37105749 100644
--- a/src/Dapr.AI/Conversation/DaprConversationClientBuilder.cs
+++ b/src/Dapr.AI/Conversation/DaprConversationClientBuilder.cs
@@ -13,6 +13,7 @@
using System.Diagnostics.CodeAnalysis;
using Dapr.Common;
+using Dapr.Common.Http;
using Microsoft.Extensions.Configuration;
using Autogenerated = Dapr.Client.Autogen.Grpc.v1.Dapr;
@@ -23,7 +24,7 @@ namespace Dapr.AI.Conversation;
///
/// An optional to configure the client with.
[Experimental("DAPR_CONVERSATION", UrlFormat = "https://docs.dapr.io/developing-applications/building-blocks/conversation/conversation-overview/")]
-public sealed class DaprConversationClientBuilder(IConfiguration? configuration = null) : DaprGenericClientBuilder(configuration)
+public sealed class DaprConversationClientBuilder(IDaprHttpClientFactory daprHttpClientFactory, IConfiguration? configuration = null) : DaprGenericClientBuilder(daprHttpClientFactory, configuration)
{
///
/// Builds the client instance from the properties of the builder.
@@ -35,7 +36,7 @@ public sealed class DaprConversationClientBuilder(IConfiguration? configuration
[Experimental("DAPR_CONVERSATION", UrlFormat = "https://docs.dapr.io/developing-applications/building-blocks/conversation/conversation-overview/")]
public override DaprConversationClient Build()
{
- var daprClientDependencies = BuildDaprClientDependencies(typeof(DaprConversationClient).Assembly);
+ var daprClientDependencies = BuildDaprClientDependencies();
var client = new Autogenerated.DaprClient(daprClientDependencies.channel);
return new DaprConversationGrpcClient(client, daprClientDependencies.httpClient, daprClientDependencies.daprApiToken);
}
diff --git a/src/Dapr.AI/Conversation/Extensions/DaprAiConversationBuilderExtensions.cs b/src/Dapr.AI/Conversation/Extensions/DaprAiConversationBuilderExtensions.cs
index ba7c7b914..f3af22ffc 100644
--- a/src/Dapr.AI/Conversation/Extensions/DaprAiConversationBuilderExtensions.cs
+++ b/src/Dapr.AI/Conversation/Extensions/DaprAiConversationBuilderExtensions.cs
@@ -30,5 +30,16 @@ public static IDaprAiConversationBuilder AddDaprConversationClient(
this IServiceCollection services,
Action? configure = null,
ServiceLifetime lifetime = ServiceLifetime.Singleton) => services
- .AddDaprClient(configure, lifetime);
+ .AddDaprClient(configure, null, lifetime);
+
+ ///
+ /// Registers the necessary functionality for the Dapr AI Conversation functionality.
+ ///
+ [Experimental("DAPR_CONVERSATION", UrlFormat = "https://docs.dapr.io/developing-applications/building-blocks/conversation/conversation-overview/")]
+ public static IDaprAiConversationBuilder AddDaprConversationClient(
+ this IServiceCollection services,
+ Action? configure = null,
+ Action? configureHttpClient = null,
+ ServiceLifetime lifetime = ServiceLifetime.Singleton) => services
+ .AddDaprClient(configure, configureHttpClient, lifetime);
}
diff --git a/src/Dapr.Common/DaprGenericClientBuilder.cs b/src/Dapr.Common/DaprGenericClientBuilder.cs
index 3e29a2eff..6674c81c6 100644
--- a/src/Dapr.Common/DaprGenericClientBuilder.cs
+++ b/src/Dapr.Common/DaprGenericClientBuilder.cs
@@ -11,8 +11,8 @@
// limitations under the License.
// ------------------------------------------------------------------------
-using System.Reflection;
using System.Text.Json;
+using Dapr.Common.Http;
using Grpc.Net.Client;
using Microsoft.Extensions.Configuration;
@@ -23,11 +23,16 @@ namespace Dapr.Common;
///
public abstract class DaprGenericClientBuilder where TClientBuilder : class, IDaprClient
{
+ private readonly IDaprHttpClientFactory daprHttpClientFactory;
+
///
/// Initializes a new instance of the class.
///
- protected DaprGenericClientBuilder(IConfiguration? configuration = null)
+ protected DaprGenericClientBuilder(IDaprHttpClientFactory daprHttpClientFactory, IConfiguration? configuration = null)
{
+ ArgumentNullException.ThrowIfNull(daprHttpClientFactory);
+ this.daprHttpClientFactory = daprHttpClientFactory;
+
this.GrpcEndpoint = DaprDefaults.GetDefaultGrpcEndpoint();
this.HttpEndpoint = DaprDefaults.GetDefaultHttpEndpoint();
@@ -52,11 +57,6 @@ protected DaprGenericClientBuilder(IConfiguration? configuration = null)
///
internal string HttpEndpoint { get; private set; }
- ///
- /// Property exposed for testing purposes.
- ///
- internal Func? HttpClientFactory { get; set; }
-
///
/// Property exposed for testing purposes.
///
@@ -94,27 +94,6 @@ public DaprGenericClientBuilder UseHttpEndpoint(string httpEndpo
return this;
}
- ///
- /// Exposed internally for testing purposes.
- ///
- internal DaprGenericClientBuilder UseHttpClientFactory(Func factory)
- {
- this.HttpClientFactory = factory;
- return this;
- }
-
- ///
- /// Overrides the legacy mechanism for building an HttpClient and uses the new
- /// introduced in .NET Core 2.1.
- ///
- /// The factory used to create instances.
- ///
- public DaprGenericClientBuilder UseHttpClientFactory(IHttpClientFactory httpClientFactory)
- {
- this.HttpClientFactory = httpClientFactory.CreateClient;
- return this;
- }
-
///
/// Overrides the gRPC endpoint used by the Dapr client for communicating with the Dapr runtime.
///
@@ -184,9 +163,8 @@ public DaprGenericClientBuilder UseTimeout(TimeSpan timeout)
/// Builds out the inner DaprClient that provides the core shape of the
/// runtime gRPC client used by the consuming package.
///
- /// The assembly the dependencies are being built for.
///
- protected internal (GrpcChannel channel, HttpClient httpClient, Uri httpEndpoint, string daprApiToken) BuildDaprClientDependencies(Assembly assembly)
+ protected internal (GrpcChannel channel, HttpClient httpClient, Uri httpEndpoint, string daprApiToken) BuildDaprClientDependencies()
{
var grpcEndpoint = new Uri(this.GrpcEndpoint);
if (grpcEndpoint.Scheme != "http" && grpcEndpoint.Scheme != "https")
@@ -207,40 +185,17 @@ protected internal (GrpcChannel channel, HttpClient httpClient, Uri httpEndpoint
}
//Configure the HTTP client
- var httpClient = ConfigureHttpClient(assembly);
- this.GrpcChannelOptions.HttpClient = httpClient;
+ var httpClient = daprHttpClientFactory.CreateClient();
- var channel = GrpcChannel.ForAddress(this.GrpcEndpoint, this.GrpcChannelOptions);
- return (channel, httpClient, httpEndpoint, this.DaprApiToken);
- }
-
- ///
- /// Configures the HTTP client.
- ///
- /// The assembly the user agent is built from.
- /// The HTTP client to interact with the Dapr runtime with.
- private HttpClient ConfigureHttpClient(Assembly assembly)
- {
- var httpClient = HttpClientFactory is not null ? HttpClientFactory() : new HttpClient();
-
- //Set the timeout as necessary
+ //Update the timeout to use the one provided in this builder
if (this.Timeout > TimeSpan.Zero)
{
httpClient.Timeout = this.Timeout;
}
+ this.GrpcChannelOptions.HttpClient = httpClient;
- //Set the user agent
- var userAgent = DaprClientUtilities.GetUserAgent(assembly);
- httpClient.DefaultRequestHeaders.Add("User-Agent", userAgent.ToString());
-
- //Set the API token
- var apiTokenHeader = DaprClientUtilities.GetDaprApiTokenHeader(this.DaprApiToken);
- if (apiTokenHeader is not null)
- {
- httpClient.DefaultRequestHeaders.Add(apiTokenHeader.Value.Key, apiTokenHeader.Value.Value);
- }
-
- return httpClient;
+ var channel = GrpcChannel.ForAddress(this.GrpcEndpoint, this.GrpcChannelOptions);
+ return (channel, httpClient, httpEndpoint, this.DaprApiToken);
}
///
diff --git a/src/Dapr.Common/Extensions/DaprClientBuilderExtensions.cs b/src/Dapr.Common/Extensions/DaprClientBuilderExtensions.cs
index 1070133c2..e828e4f2b 100644
--- a/src/Dapr.Common/Extensions/DaprClientBuilderExtensions.cs
+++ b/src/Dapr.Common/Extensions/DaprClientBuilderExtensions.cs
@@ -12,8 +12,10 @@
// ------------------------------------------------------------------------
using System.Reflection;
+using Dapr.Common.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Http;
using Autogenerated = Dapr.Client.Autogen.Grpc.v1.Dapr;
namespace Dapr.Common.Extensions;
@@ -32,12 +34,14 @@ internal static class DaprClientBuilderExtensions
/// The type of the static builder used to build the Dapr ot client.
/// The collection of services to which the Dapr client and associated services are being registered.
/// An optional method used to provide additional configurations to the client builder.
+ /// An optional method used to configure the HttpClient used by Dapr.
/// The registered lifetime of the Dapr client.
/// The collection of DI-registered services.
//internal static TBuilderInterface AddDaprClient(
internal static TServiceBuilder AddDaprClient(
this IServiceCollection services,
Action? configure = null,
+ Action? configureHttpClient = null,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
where TClient : class, IDaprClient
where TConcreteClient : TClient
@@ -61,16 +65,46 @@ internal static TServiceBuilder AddDaprClient(serviceProvider =>
+ {
+ var httpClientFactory = serviceProvider.GetRequiredService();
+ var configuration = serviceProvider.GetService();
+
+ return new DefaultDaprHttpClientFactory(httpClientFactory, client =>
+ {
+ // Configure the HTTP client
+ if (configuration is not null)
+ {
+ //Get the API token header
+ var daprApiToken = DaprDefaults.GetDefaultDaprApiToken(configuration);
+ var apiTokenHeader = DaprClientUtilities.GetDaprApiTokenHeader(daprApiToken);
+ if (apiTokenHeader is not null)
+ {
+ client.DefaultRequestHeaders.Add(apiTokenHeader.Value.Key, apiTokenHeader.Value.Value);
+ }
+
+ // Set the user agent
+ var assembly = Assembly.GetExecutingAssembly();
+ var userAgent = DaprClientUtilities.GetUserAgent(assembly);
+ client.DefaultRequestHeaders.Add("User-Agent", userAgent.ToString());
+ }
+
+ // Apply any configuration provided at registration by the developer, if available
+ configureHttpClient?.Invoke(serviceProvider, client);
+ });
+ });
var registration = new Func(provider =>
{
var configuration = provider.GetService();
- var builder = (TClientBuilder)Activator.CreateInstance(typeof(TClientBuilder), configuration)!;
-
- builder.UseDaprApiToken(DaprDefaults.GetDefaultDaprApiToken(configuration));
+ var daprHttpClientFactory = provider.GetRequiredService();
+ var builder = (TClientBuilder)Activator.CreateInstance(typeof(TClientBuilder), daprHttpClientFactory, configuration)!;
+
+ builder.UseDaprApiToken(DaprDefaults.GetDefaultDaprApiToken(configuration));
configure?.Invoke(provider, builder);
var (channel, httpClient, _, daprApiToken) =
- builder.BuildDaprClientDependencies(Assembly.GetExecutingAssembly());
+ builder.BuildDaprClientDependencies();
var daprClient = new Autogenerated.DaprClient(channel);
return (TClient)Activator.CreateInstance(typeof(TConcreteClient), daprClient, httpClient, daprApiToken)!;
});
diff --git a/src/Dapr.Common/Http/DefaultDaprHttpClientFactory.cs b/src/Dapr.Common/Http/DefaultDaprHttpClientFactory.cs
new file mode 100644
index 000000000..516e1404f
--- /dev/null
+++ b/src/Dapr.Common/Http/DefaultDaprHttpClientFactory.cs
@@ -0,0 +1,15 @@
+namespace Dapr.Common.Http;
+
+///
+/// Concrete implementation of a .
+///
+public sealed class DefaultDaprHttpClientFactory(IHttpClientFactory httpClientFactory, Action configure) : IDaprHttpClientFactory
+{
+ ///
+ public HttpClient CreateClient()
+ {
+ var client = httpClientFactory.CreateClient();
+ configure(client);
+ return client;
+ }
+}
diff --git a/src/Dapr.Common/Http/IDaprHttpClientFactory.cs b/src/Dapr.Common/Http/IDaprHttpClientFactory.cs
new file mode 100644
index 000000000..fe85f6c5a
--- /dev/null
+++ b/src/Dapr.Common/Http/IDaprHttpClientFactory.cs
@@ -0,0 +1,13 @@
+namespace Dapr.Common.Http;
+
+///
+/// Factory for creating Dapr-configured instances.
+///
+public interface IDaprHttpClientFactory
+{
+ ///
+ /// Produces a Dapr-configured instance.
+ ///
+ ///
+ HttpClient CreateClient();
+}
diff --git a/src/Dapr.Cryptography/Encryption/DaprEncryptionClientBuilder.cs b/src/Dapr.Cryptography/Encryption/DaprEncryptionClientBuilder.cs
index 833a849f3..80854b0ab 100644
--- a/src/Dapr.Cryptography/Encryption/DaprEncryptionClientBuilder.cs
+++ b/src/Dapr.Cryptography/Encryption/DaprEncryptionClientBuilder.cs
@@ -13,6 +13,7 @@
using System.Diagnostics.CodeAnalysis;
using Dapr.Common;
+using Dapr.Common.Http;
using Microsoft.Extensions.Configuration;
using Autogenerated = Dapr.Client.Autogen.Grpc.v1;
@@ -23,7 +24,7 @@ namespace Dapr.Cryptography.Encryption;
///
/// An optional instance of .
[Experimental("DAPR_CRYPTOGRAPHY", UrlFormat = "https://docs.dapr.io/developing-applications/building-blocks/cryptography/cryptography-overview/")]
-public sealed class DaprEncryptionClientBuilder(IConfiguration? configuration = null) : DaprGenericClientBuilder(configuration)
+public sealed class DaprEncryptionClientBuilder(IDaprHttpClientFactory daprHttpClientFactory, IConfiguration? configuration = null) : DaprGenericClientBuilder(daprHttpClientFactory, configuration)
{
///
/// Builds the client instance from the properties of the builder.
@@ -31,7 +32,7 @@ public sealed class DaprEncryptionClientBuilder(IConfiguration? configuration =
/// The Dapr client instance.
public override DaprEncryptionClient Build()
{
- var daprClientDependencies = this.BuildDaprClientDependencies(typeof(DaprEncryptionClient).Assembly);
+ var daprClientDependencies = this.BuildDaprClientDependencies();
var client = new Autogenerated.Dapr.DaprClient(daprClientDependencies.channel);
return new DaprEncryptionGrpcClient(client, daprClientDependencies.httpClient, daprClientDependencies.daprApiToken);
}
diff --git a/src/Dapr.Cryptography/Encryption/Extensions/DaprCryptographyServiceCollectionExtensions.cs b/src/Dapr.Cryptography/Encryption/Extensions/DaprCryptographyServiceCollectionExtensions.cs
index 825591104..55931a819 100644
--- a/src/Dapr.Cryptography/Encryption/Extensions/DaprCryptographyServiceCollectionExtensions.cs
+++ b/src/Dapr.Cryptography/Encryption/Extensions/DaprCryptographyServiceCollectionExtensions.cs
@@ -20,7 +20,8 @@ namespace Dapr.Cryptography.Encryption.Extensions;
///
/// Contains extension methods for using Dapr cryptography with dependency injection.
///
-[Experimental("DAPR_CRYPTOGRAPHY", UrlFormat = "https://docs.dapr.io/developing-applications/building-blocks/cryptography/cryptography-overview/")]
+[Experimental("DAPR_CRYPTOGRAPHY",
+ UrlFormat = "https://docs.dapr.io/developing-applications/building-blocks/cryptography/cryptography-overview/")]
public static class DaprCryptographyServiceCollectionExtensions
{
///
@@ -39,6 +40,27 @@ public static IDaprCryptographyBuilder AddDaprEncryptionClient(
services.AddTransient();
return services
.AddDaprClient(configure, lifetime);
+ DaprEncryptionClientBuilder>(configure, null, lifetime);
+ }
+
+ ///
+ /// Adds Dapr encryption/decryption support to the service collection.
+ ///
+ /// The .
+ /// Optionally allows greater configuration of the using injected services.
+ /// Optionally allows greater configuration of the used by the .
+ /// The lifetime of the registered services.
+ ///
+ public static IDaprCryptographyBuilder AddDaprEncryptionClient(
+ this IServiceCollection services,
+ Action? configure = null,
+ Action? configureHttpClient = null,
+ ServiceLifetime lifetime = ServiceLifetime.Singleton)
+ {
+ services.AddTransient();
+ services.AddTransient();
+ return services
+ .AddDaprClient(configure, configureHttpClient, lifetime);
}
}
diff --git a/src/Dapr.Jobs/DaprJobsClientBuilder.cs b/src/Dapr.Jobs/DaprJobsClientBuilder.cs
index 979f7fb8a..9e60cfffa 100644
--- a/src/Dapr.Jobs/DaprJobsClientBuilder.cs
+++ b/src/Dapr.Jobs/DaprJobsClientBuilder.cs
@@ -13,6 +13,7 @@
using System.Diagnostics.CodeAnalysis;
using Dapr.Common;
+using Dapr.Common.Http;
using Microsoft.Extensions.Configuration;
using Autogenerated = Dapr.Client.Autogen.Grpc.v1;
@@ -23,7 +24,7 @@ namespace Dapr.Jobs;
///
/// An optional instance of .
[Experimental("DAPR_JOBS", UrlFormat = "https://docs.dapr.io/developing-applications/building-blocks/jobs/jobs-overview/")]
-public sealed class DaprJobsClientBuilder(IConfiguration? configuration = null) : DaprGenericClientBuilder(configuration)
+public sealed class DaprJobsClientBuilder(IDaprHttpClientFactory daprHttpClientFactory, IConfiguration? configuration = null) : DaprGenericClientBuilder(daprHttpClientFactory, configuration)
{
///
/// Builds the client instance from the properties of the builder.
@@ -31,7 +32,7 @@ public sealed class DaprJobsClientBuilder(IConfiguration? configuration = null)
/// The Dapr client instance.
public override DaprJobsClient Build()
{
- var daprClientDependencies = this.BuildDaprClientDependencies(typeof(DaprJobsClient).Assembly);
+ var daprClientDependencies = this.BuildDaprClientDependencies();
var client = new Autogenerated.Dapr.DaprClient(daprClientDependencies.channel);
return new DaprJobsGrpcClient(client, daprClientDependencies.httpClient, daprClientDependencies.daprApiToken);
}
diff --git a/src/Dapr.Jobs/Extensions/DaprJobsServiceCollectionExtensions.cs b/src/Dapr.Jobs/Extensions/DaprJobsServiceCollectionExtensions.cs
index 3103e072b..85b1d4c86 100644
--- a/src/Dapr.Jobs/Extensions/DaprJobsServiceCollectionExtensions.cs
+++ b/src/Dapr.Jobs/Extensions/DaprJobsServiceCollectionExtensions.cs
@@ -34,5 +34,20 @@ public static IDaprJobsBuilder AddDaprJobsClient(
this IServiceCollection services,
Action? configure = null,
ServiceLifetime lifetime = ServiceLifetime.Singleton) =>
- services.AddDaprClient(configure, lifetime);
+ services.AddDaprClient(configure, null, lifetime);
+
+ ///
+ /// Adds Dapr Jobs client support to the service collection.
+ ///
+ /// The .
+ /// Optionally allows greater configuration of the using injected services.
+ /// Optionally allows greater configuration of the used by the .
+ /// The lifetime of the registered services.
+ ///
+ public static IDaprJobsBuilder AddDaprJobsClient(
+ this IServiceCollection services,
+ Action? configure = null,
+ Action? configureHttpClient = null,
+ ServiceLifetime lifetime = ServiceLifetime.Singleton) =>
+ services.AddDaprClient(configure, configureHttpClient, lifetime);
}
diff --git a/src/Dapr.Messaging/PublishSubscribe/DaprPublishSubscribeClientBuilder.cs b/src/Dapr.Messaging/PublishSubscribe/DaprPublishSubscribeClientBuilder.cs
index 691ff9d38..9c0ed4bb5 100644
--- a/src/Dapr.Messaging/PublishSubscribe/DaprPublishSubscribeClientBuilder.cs
+++ b/src/Dapr.Messaging/PublishSubscribe/DaprPublishSubscribeClientBuilder.cs
@@ -12,6 +12,7 @@
// ------------------------------------------------------------------------
using Dapr.Common;
+using Dapr.Common.Http;
using Microsoft.Extensions.Configuration;
using Autogenerated = Dapr.Client.Autogen.Grpc.v1;
@@ -21,7 +22,7 @@ namespace Dapr.Messaging.PublishSubscribe;
/// Builds a .
///
/// An optional instance of .
-public sealed class DaprPublishSubscribeClientBuilder(IConfiguration? configuration = null) : DaprGenericClientBuilder(configuration)
+public sealed class DaprPublishSubscribeClientBuilder(IDaprHttpClientFactory daprHttpClientFactory, IConfiguration? configuration = null) : DaprGenericClientBuilder(daprHttpClientFactory,configuration)
{
///
/// Builds the client instance from the properties of the builder.
@@ -32,7 +33,7 @@ public sealed class DaprPublishSubscribeClientBuilder(IConfiguration? configurat
///
public override DaprPublishSubscribeClient Build()
{
- var daprClientDependencies = BuildDaprClientDependencies(typeof(DaprPublishSubscribeClient).Assembly);
+ var daprClientDependencies = BuildDaprClientDependencies();
var client = new Autogenerated.Dapr.DaprClient(daprClientDependencies.channel);
return new DaprPublishSubscribeGrpcClient(client, daprClientDependencies.httpClient, daprClientDependencies.daprApiToken);
}
diff --git a/src/Dapr.Messaging/PublishSubscribe/Extensions/PublishSubscribeServiceCollectionExtensions.cs b/src/Dapr.Messaging/PublishSubscribe/Extensions/PublishSubscribeServiceCollectionExtensions.cs
index 954940e53..141462106 100644
--- a/src/Dapr.Messaging/PublishSubscribe/Extensions/PublishSubscribeServiceCollectionExtensions.cs
+++ b/src/Dapr.Messaging/PublishSubscribe/Extensions/PublishSubscribeServiceCollectionExtensions.cs
@@ -1,4 +1,5 @@
using Dapr.Common.Extensions;
+using Dapr.Common.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Dapr.Messaging.PublishSubscribe.Extensions;
@@ -8,17 +9,33 @@ namespace Dapr.Messaging.PublishSubscribe.Extensions;
///
public static class PublishSubscribeServiceCollectionExtensions
{
+ ///
+ /// Adds Dapr Publish/Subscribe support to the service collection.
+ ///
+ /// The .
+ /// Optionally allows greater configuration of the using injected services.
+ /// The lifetime of the registered services.
+ ///
+ public static IDaprPubSubBuilder AddDaprPubSubClient(
+ this IServiceCollection services,
+ Action? configure = null,
+ ServiceLifetime lifetime = ServiceLifetime.Singleton) =>
+ services.AddDaprClient(
+ configure, null, lifetime);
+
///
/// Adds Dapr Publish/Subscribe support to the service collection.
///
/// The .
/// Optionally allows greater configuration of the using injected services.
+ /// Optionally allows greater configuration of the used by the .
/// The lifetime of the registered services.
///
public static IDaprPubSubBuilder AddDaprPubSubClient(
this IServiceCollection services,
Action? configure = null,
+ Action? configureHttpClient = null,
ServiceLifetime lifetime = ServiceLifetime.Singleton) =>
services.AddDaprClient(
- configure, lifetime);
+ configure, configureHttpClient, lifetime);
}