DNV.Dapr.Http 2.1.0-preview.1756698443

This is a prerelease version of DNV.Dapr.Http.
dotnet add package DNV.Dapr.Http --version 2.1.0-preview.1756698443
                    
NuGet\Install-Package DNV.Dapr.Http -Version 2.1.0-preview.1756698443
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DNV.Dapr.Http" Version="2.1.0-preview.1756698443" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DNV.Dapr.Http" Version="2.1.0-preview.1756698443" />
                    
Directory.Packages.props
<PackageReference Include="DNV.Dapr.Http" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DNV.Dapr.Http --version 2.1.0-preview.1756698443
                    
#r "nuget: DNV.Dapr.Http, 2.1.0-preview.1756698443"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DNV.Dapr.Http@2.1.0-preview.1756698443
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DNV.Dapr.Http&version=2.1.0-preview.1756698443&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=DNV.Dapr.Http&version=2.1.0-preview.1756698443&prerelease
                    
Install as a Cake Tool

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 and IServiceCollection
  • 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 for IHttpClientBuilder and IServiceCollection
  • ServiceInvocationHandler: DelegatingHandler that converts HTTP requests to Dapr service invocation format
  • DaprHttpClientOptions: Configuration options (from DNV.Dapr.Common)

Request Flow

  1. HttpClient makes a standard HTTP request (e.g., GET /api/users)
  2. ServiceInvocationHandler intercepts the request
  3. Handler transforms the URL to Dapr service invocation format: http://localhost:3500/v1.0/invoke/{appId}/method/api/users
  4. Request is forwarded to Dapr runtime
  5. Dapr handles service discovery, load balancing, and routing
  6. 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
  • 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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