DNV.Dapr.Http
2.1.0-preview.1756698443
dotnet add package DNV.Dapr.Http --version 2.1.0-preview.1756698443
NuGet\Install-Package DNV.Dapr.Http -Version 2.1.0-preview.1756698443
<PackageReference Include="DNV.Dapr.Http" Version="2.1.0-preview.1756698443" />
<PackageVersion Include="DNV.Dapr.Http" Version="2.1.0-preview.1756698443" />
<PackageReference Include="DNV.Dapr.Http" />
paket add DNV.Dapr.Http --version 2.1.0-preview.1756698443
#r "nuget: DNV.Dapr.Http, 2.1.0-preview.1756698443"
#:package DNV.Dapr.Http@2.1.0-preview.1756698443
#addin nuget:?package=DNV.Dapr.Http&version=2.1.0-preview.1756698443&prerelease
#tool nuget:?package=DNV.Dapr.Http&version=2.1.0-preview.1756698443&prerelease
DNV.Dapr.Http
A lightweight Dapr HTTP service invocation library that provides HttpClient extensions for seamless integration with Dapr service-to-service communication.
Overview
This library provides HttpClient extensions and message handlers that automatically convert standard HTTP requests into Dapr service invocation calls. It enables you to use familiar HttpClient patterns while leveraging Dapr's service discovery, load balancing, and observability features.
Why This Implementation?
The main purpose of this library is to provide a transparent way to use Dapr service invocation with standard HttpClient patterns. This approach offers:
- Familiar API: Use standard HttpClient methods without learning new Dapr-specific APIs
- Transparent Integration: Existing HTTP client code works with minimal changes
- HttpClient Ecosystem: Full compatibility with HttpClient factories, policies, and handlers
- Configuration Flexibility: Support for both programmatic and configuration-based setup
- Service Discovery: Automatic routing through Dapr's service mesh
- Load Balancing: Built-in load balancing via Dapr runtime
- Observability: Automatic tracing and metrics through Dapr's observability features
Key Features
- HttpClient Extensions: Seamless integration with
IHttpClientBuilder
andIServiceCollection
- Message Handler:
ServiceInvocationHandler
that transforms HTTP requests to Dapr service invocation calls - Configuration Support: Bind configuration sections to
DaprHttpClientOptions
- Named Clients: Support for multiple HttpClient configurations
- Flexible Setup: Configure using app ID, FQDN, or configuration sections
- Environment Variables: Automatic detection of Dapr HTTP port and endpoint
- URL Encoding: Proper encoding of app IDs and method names
- Exception Handling: Leverages underlying Dapr HTTP client exception handling
Architecture
Core Components
DaprHttpClientExtensions
: Extension methods forIHttpClientBuilder
andIServiceCollection
ServiceInvocationHandler
:DelegatingHandler
that converts HTTP requests to Dapr service invocation formatDaprHttpClientOptions
: Configuration options (from DNV.Dapr.Common)
Request Flow
- HttpClient makes a standard HTTP request (e.g.,
GET /api/users
) ServiceInvocationHandler
intercepts the request- Handler transforms the URL to Dapr service invocation format:
http://localhost:3500/v1.0/invoke/{appId}/method/api/users
- Request is forwarded to Dapr runtime
- Dapr handles service discovery, load balancing, and routing
- Response is returned transparently to the calling code
Installation
dotnet add package DNV.Dapr.Http
Quick Start
Basic Setup with App ID
using DNV.Dapr.Http;
var builder = WebApplication.CreateBuilder(args);
// Register HttpClient with Dapr service invocation
builder.Services.AddHttpClient("UserService")
.AddDaprHttpServiceInvocation("user-service");
var app = builder.Build();
Usage
public class UserController : ControllerBase
{
private readonly HttpClient _httpClient;
public UserController(IHttpClientFactory httpClientFactory)
{
_httpClient = httpClientFactory.CreateClient("UserService");
}
[HttpGet]
public async Task<IEnumerable<User>> GetUsers()
{
// This will be automatically converted to:
// http://localhost:3500/v1.0/invoke/user-service/method/api/users
var response = await _httpClient.GetAsync("/api/users");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<IEnumerable<User>>();
}
[HttpPost]
public async Task<User> CreateUser(User user)
{
// This will be automatically converted to:
// http://localhost:3500/v1.0/invoke/user-service/method/api/users
var response = await _httpClient.PostAsJsonAsync("/api/users", user);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<User>();
}
}
Configuration
Using Configuration Sections
{
"Services": {
"UserService": {
"AppIdOrFqdnUrl": "user-service",
"HttpPort": 3500
},
"OrderService": {
"AppIdOrFqdnUrl": "order-service",
"HttpPort": 3501
}
}
}
// Configure using configuration sections
builder.Services.AddHttpClient("UserService")
.AddDaprHttpServiceInvocation(builder.Configuration.GetSection("Services:UserService"));
builder.Services.AddHttpClient("OrderService")
.AddDaprHttpServiceInvocation(builder.Configuration.GetSection("Services:OrderService"));
Using Service Collection Extensions
// Direct configuration with service collection
builder.Services.AddDaprHttpServiceInvocation("UserService", "user-service", 3500);
builder.Services.AddDaprHttpServiceInvocation("OrderService",
builder.Configuration.GetSection("Services:OrderService"));
Using FQDN URLs
// Use FQDN instead of app ID for external services
builder.Services.AddHttpClient("ExternalApi")
.AddDaprHttpServiceInvocation("https://api.external-service.com");
Configuration Options
The DaprHttpClientOptions
class (from DNV.Dapr.Common) supports the following options:
Property | Description | Default |
---|---|---|
AppIdOrFqdnUrl |
Target Dapr app ID or FQDN URL | Required |
HttpPort |
Dapr HTTP port | 3500 (or DAPR_HTTP_PORT env var) |
HttpEndpoint |
Complete Dapr HTTP endpoint | http://localhost:{HttpPort} (or DAPR_HTTP_ENDPOINT env var) |
JsonOptions |
JSON serialization options | Web defaults |
Environment Variables
The library automatically detects the following environment variables:
DAPR_HTTP_PORT
: Overrides the default HTTP port (3500)DAPR_HTTP_ENDPOINT
: Overrides the default HTTP endpoint
Advanced Scenarios
Multiple Service Configurations
builder.Services.AddHttpClient("InternalUserService")
.AddDaprHttpServiceInvocation("user-service");
builder.Services.AddHttpClient("ExternalPaymentService")
.AddDaprHttpServiceInvocation("https://api.payment-provider.com");
builder.Services.AddHttpClient("LegacyOrderService")
.AddDaprHttpServiceInvocation("legacy-orders", 3502);
Custom HttpClient Configuration
builder.Services.AddHttpClient("UserService", client =>
{
client.Timeout = TimeSpan.FromSeconds(30);
client.DefaultRequestHeaders.Add("X-API-Version", "v1");
})
.AddDaprHttpServiceInvocation("user-service")
.AddPolicyHandler(GetRetryPolicy())
.AddPolicyHandler(GetCircuitBreakerPolicy());
Typed Clients
public interface IUserServiceClient
{
Task<IEnumerable<User>> GetUsersAsync();
Task<User> GetUserAsync(int id);
Task<User> CreateUserAsync(User user);
}
public class UserServiceClient : IUserServiceClient
{
private readonly HttpClient _httpClient;
public UserServiceClient(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<IEnumerable<User>> GetUsersAsync()
{
var response = await _httpClient.GetAsync("/api/users");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<IEnumerable<User>>();
}
public async Task<User> GetUserAsync(int id)
{
var response = await _httpClient.GetAsync($"/api/users/{id}");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<User>();
}
public async Task<User> CreateUserAsync(User user)
{
var response = await _httpClient.PostAsJsonAsync("/api/users", user);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<User>();
}
}
// Registration
builder.Services.AddHttpClient<IUserServiceClient, UserServiceClient>()
.AddDaprHttpServiceInvocation("user-service");
URL Transformation Examples
Original Request | Transformed URL |
---|---|
GET /api/users |
http://localhost:3500/v1.0/invoke/user-service/method/api/users |
POST /api/users/123 |
http://localhost:3500/v1.0/invoke/user-service/method/api/users/123 |
GET /health?check=db |
http://localhost:3500/v1.0/invoke/user-service/method/health?check=db |
PUT /api/users/123/status |
http://localhost:3500/v1.0/invoke/user-service/method/api/users/123/status |
Error Handling
The library leverages the underlying HttpClient and Dapr runtime for error handling:
try
{
var response = await httpClient.GetAsync("/api/users");
response.EnsureSuccessStatusCode();
var users = await response.Content.ReadFromJsonAsync<IEnumerable<User>>();
}
catch (HttpRequestException ex)
{
// Handle HTTP-level errors (network, timeout, etc.)
_logger.LogError(ex, "Failed to call user service");
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
// Handle timeout
_logger.LogError(ex, "Request to user service timed out");
}
Testing
The library integrates seamlessly with standard HttpClient testing patterns:
[Test]
public async Task GetUsers_ReturnsExpectedUsers()
{
// Arrange
var mockHandler = new Mock<HttpMessageHandler>();
mockHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(JsonSerializer.Serialize(expectedUsers))
});
var httpClient = new HttpClient(new ServiceInvocationHandler("user-service")
{
InnerHandler = mockHandler.Object
});
var userService = new UserServiceClient(httpClient);
// Act
var result = await userService.GetUsersAsync();
// Assert
result.Should().BeEquivalentTo(expectedUsers);
// Verify the URL was transformed correctly
mockHandler.Protected().Verify("SendAsync", Times.Once(),
ItExpr.Is<HttpRequestMessage>(req =>
req.RequestUri.ToString().Contains("/v1.0/invoke/user-service/method/")),
ItExpr.IsAny<CancellationToken>());
}
Dependencies
- .NET 8.0: Target framework
- Microsoft.Extensions.Http: HttpClient factory and extensions
- DNV.Dapr.Common: Shared options and utilities
Related Libraries
- DNV.Dapr.Common: Shared configuration and utilities
- DNV.Dapr.PubSub: Dapr Pub/Sub client with HttpClient injection
- DNV.Dapr.Caching: Dapr state store caching implementation
- DNV.Dapr.DataProtection: ASP.NET Core Data Protection with Dapr state store
Contributing
This library is part of the DNV Dapr solution package. For contribution guidelines and development setup, please refer to the main solution documentation.
License
[Add appropriate license information]
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- DNV.Dapr.Common (>= 2.1.0-preview.1756698443)
- Microsoft.Extensions.Http (>= 8.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
2.1.0-preview.1756698443 | 117 | 9/1/2025 |
2.1.0-preview.1756370241 | 163 | 8/28/2025 |
2.1.0-preview.1755771145 | 111 | 8/21/2025 |