Microsoft.Extensions.ServiceDiscovery
8.0.0-preview.2.23619.3
Prefix Reserved
See the version list below for details.
dotnet add package Microsoft.Extensions.ServiceDiscovery --version 8.0.0-preview.2.23619.3
NuGet\Install-Package Microsoft.Extensions.ServiceDiscovery -Version 8.0.0-preview.2.23619.3
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="8.0.0-preview.2.23619.3" />
paket add Microsoft.Extensions.ServiceDiscovery --version 8.0.0-preview.2.23619.3
#r "nuget: Microsoft.Extensions.ServiceDiscovery, 8.0.0-preview.2.23619.3"
// Install Microsoft.Extensions.ServiceDiscovery as a Cake Addin #addin nuget:?package=Microsoft.Extensions.ServiceDiscovery&version=8.0.0-preview.2.23619.3&prerelease // Install Microsoft.Extensions.ServiceDiscovery as a Cake Tool #tool nuget:?package=Microsoft.Extensions.ServiceDiscovery&version=8.0.0-preview.2.23619.3&prerelease
Microsoft.Extensions.ServiceDiscovery
The Microsoft.Extensions.ServiceDiscovery
library is designed to simplify the integration of service discovery patterns in .NET applications. Service discovery is a key component of most distributed systems and microservices architectures. This library provides a straightforward way to resolve service names to endpoint addresses.
In typical systems, service configuration changes over time. Service discovery accounts for by monitoring endpoint configuration using push-based notifications where supported, falling back to polling in other cases. When endpoints are refreshed, callers are notified so that they can observe the refreshed results.
How it works
Service discovery uses configured resolvers to resolve service endpoints. When service endpoints are resolved, each registered resolver is called in the order of registration to contribute to a collection of service endpoints (an instance of ServiceEndPointCollection
).
Resolvers implement the IServiceEndPointResolver
interface. They are created by an instance of IServiceEndPointResolverProvider
, which are registered with the .NET dependency injection system.
Developers typically add service discovery to their HttpClient
using the IHttpClientFactory
with the UseServiceDiscovery
extension method.
Services can be resolved directly by calling ServiceEndPointResolverRegistry
's GetEndPointsAsync
method, which returns a collection of resolved endpoints.
Change notifications
Service configuration can change over time. Service discovery accounts for by monitoring endpoint configuration using push-based notifications where supported, falling back to polling in other cases. When endpoints are refreshed, callers are notified so that they can observe the refreshed results. To subscribe to notifications, callers use the ChangeToken
property of ServiceEndPointCollection
. For more information on change tokens, see Detect changes with change tokens in ASP.NET Core.
Extensibility using features
Service endpoints (ServiceEndPoint
instances) and collections of service endpoints (ServiceEndPointCollection
instances) expose an extensible IFeatureCollection
via their Features
property. Features are exposed as interfaces accessible on the feature collection. These interfaces can be added, modified, wrapped, replaced or even removed at resolution time by resolvers. Features which may be available on a ServiceEndPoint
include:
IHostNameFeature
: exposes the host name of the resolved endpoint, intended for use with Server Name Identification (SNI) and Transport Layer Security (TLS).IEndPointHealthFeature
: used for reporting response times and errors from endpoints.IEndPointLoadFeature
: used to query estimated endpoint load.
Resolution order
The resolvers included in the Microsoft.Extensions.ServiceDiscovery
series of packages skip resolution if there are existing endpoints in the collection when they are called. For example, consider a case where the following providers are registered: Configuration, DNS SRV, Pass-through. When resolution occurs, the providers will be called in-order. If the Configuration providers discovers no endpoints, the DNS SRV provider will perform resolution and may add one or more endpoints. If the DNS SRV provider adds an endpoint to the collection, the Pass-through provider will skip its resolution and will return immediately instead.
Getting Started
Installation
To install the library, use the following NuGet command:
dotnet add package Microsoft.Extensions.ServiceDiscovery
Usage example
In the Program.cs file of your project, call the AddServiceDiscovery
extension method to add service discovery to the host, configuring default service endpoint resolvers.
builder.Services.AddServiceDiscovery();
Add service discovery to an individual IHttpClientBuilder
by calling the UseServiceDiscovery
extension method:
builder.Services.AddHttpClient<CatalogServiceClient>(c =>
{
c.BaseAddress = new("http://catalog"));
}).UseServiceDiscovery();
Alternatively, you can add service discovery to all HttpClient
instances by default:
builder.Services.ConfigureHttpClientDefaults(http =>
{
// Turn on service discovery by default
http.UseServiceDiscovery();
});
Resolving service endpoints from configuration
The AddServiceDiscovery
extension method adds a configuration-based endpoint resolver by default.
This resolver reads endpoints from the .NET Configuration system.
The library supports configuration through appsettings.json
, environment variables, or any other IConfiguration
source.
Here is an example demonstrating how to configure a endpoints for the service named catalog via appsettings.json
:
{
"Services": {
"catalog": [
"localhost:8080",
"10.46.24.90:80",
]
}
}
The above example adds two endpoints for the service named catalog: localhost:8080
, and "10.46.24.90:80"
.
Each time the catalog is resolved, one of these endpoints will be selected.
If service discovery was added to the host using the AddServiceDiscoveryCore
extension method on IServiceCollection
, the configuration-based endpoint resolver can be added by calling the AddConfigurationServiceEndPointResolver
extension method on IServiceCollection
.
Configuration
The configuration resolver is configured using the ConfigurationServiceEndPointResolverOptions
class, which offers these configuration options:
SectionName
: The name of the configuration section that contains service endpoints. It defaults to"Services"
.ApplyHostNameMetadata
: A delegate used to determine if host name metadata should be applied to resolved endpoints. It defaults to a function that returnsfalse
.
To configure these options, you can use the Configure
extension method on the IServiceCollection
within your application's startup class or main program file:
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<ConfigurationServiceEndPointResolverOptions>(options =>
{
options.SectionName = "MyServiceEndpoints";
// Configure the logic for applying host name metadata
options.ApplyHostNameMetadata = endpoint =>
{
// Your custom logic here. For example:
return endpoint.EndPoint is DnsEndPoint dnsEp && dnsEp.Host.StartsWith("internal");
};
});
This example demonstrates setting a custom section name for your service endpoints and providing a custom logic for applying host name metadata based on a condition.
Resolving service endpoints using platform-provided service discovery
Some platforms, such as Azure Container Apps and Kubernetes (if configured), provide functionality for service discovery without the need for a service discovery client library. When an application is deployed to one of these environments, it may be preferable to use the platform's existing functionality instead. The pass-through resolver exists to support this scenario while still allowing other resolvers (such as configuration) to be used in other environments, such as on the developer's machine, without requiring a code change or conditional guards.
The pass-through resolver performs no external resolution and instead resolves endpoints by returning the input service name represented as a DnsEndPoint
.
The pass-through provider is configured by-default when adding service discovery via the AddServiceDiscovery
extension method.
If service discovery was added to the host using the AddServiceDiscoveryCore
extension method on IServiceCollection
, the pass-through provider can be added by calling the AddPassThroughServiceEndPointResolver
extension method on IServiceCollection
.
In the case of Azure Container Apps, the service name should match the app name. For example, if you have a service named "basket", then you should have a corresponding Azure Container App named "basket".
Load-balancing with endpoint selectors
Each time an endpoint is resolved by the HttpClient
pipeline, a single endpoint will be selected from the set of all known endpoints for the requested service. If multiple endpoints are available, it may be desirable to balance traffic across all such endpoints. To accomplish this, a customizable endpoint selector can be used. By default, endpoints are selected in round-robin order. To use a different endpoint selector, provide an IServiceEndPointSelector
instance to the UseServiceDiscovery
method call. For example, to select a random endpoint from the set of resolved endpoints, specify RandomServiceEndPointSelector.Instance
as the endpoint selector:
builder.Services.AddHttpClient<CatalogServiceClient>(
static client => client.BaseAddress = new("http://catalog"));
.UseServiceDiscovery(RandomServiceEndPointSelector.Instance);
The Microsoft.Extensions.ServiceDiscovery package includes the following endpoint selector providers:
- Pick-first, which always selects the first endpoint:
PickFirstServiceEndPointSelectorProvider.Instance
- Round-robin, which cycles through endpoints:
RoundRobinServiceEndPointSelectorProvider.Instance
- Random, which selects endpoints randomly:
RandomServiceEndPointSelectorProvider.Instance
- Power-of-two-choices, which attempts to pick the least heavily loaded endpoint based on the Power of Two Choices algorithm for distributed load balancing, degrading to randomly selecting an endpoint when either of the provided endpoints do not have the
IEndPointLoadFeature
feature:PowerOfTwoChoicesServiceEndPointSelectorProvider.Instance
Endpoint selectors are created via an IServiceEndPointSelectorProvider
instance, such as those listed above. The provider's CreateSelector()
method is called to create a selector, which is an instance of IServiceEndPointSelector
. The IServiceEndPointSelector
instance is given the set of known endpoints when they are resolved, using the SetEndPoints(ServiceEndPointCollection collection)
method. To choose an endpoint from the collection, the GetEndPoint(object? context)
method is called, returning a single ServiceEndPoint
. The context
value passed to GetEndPoint
is used to provide extra context which may be useful to the selector. For example, in the HttpClient
case, the HttpRequestMessage
is passed. None of the provided implementations of IServiceEndPointSelector
inspect the context, and it can be ignored unless you are using a selector which does make use of it.
Service discovery in .NET Aspire
.NET Aspire includes functionality for configuring the service discovery at development and testing time. This functionality works by providing configuration in the format expected by the configuration-based endpoint resolver described above from the .NET Aspire AppHost project to the individual service projects added to the application model.
Configuration for service discovery is only added for services which are referenced by a given project. For example, consider the following AppHost program:
var builder = DistributedApplication.CreateBuilder(args);
var catalog = builder.AddProject<Projects.CatalogService>("catalog");
var basket = builder.AddProject<Projects.BasketService>("basket");
var frontend = builder.AddProject<Projects.MyFrontend>("frontend")
.WithReference(basket)
.WithReference(catalog);
In the above example, the frontend project references the catalog project and the basket project. The two WithReference
calls instruct the .NET Aspire application to pass service discovery information for the referenced projects (catalog, and basket) into the frontend project.
Named endpoints
Some services expose multiple, named endpoints. Named endpoints can be resolved by specifying the endpoint name in the host portion of the HTTP request URI, following the format http://_endpointName.serviceName
. For example, if a service named "basket" exposes an endpoint named "dashboard", then the URI http://_dashboard.basket
can be used to specify this endpoint, for example:
builder.Services.AddHttpClient<BasketServiceClient>(
static client => client.BaseAddress = new("http://basket"));
builder.Services.AddHttpClient<BasketServiceDashboardClient>(
static client => client.BaseAddress = new("http://_dashboard.basket"));
In the above example, two HttpClient
s are added: one for the core basket service and one for the basket service's dashboard.
Named endpoints using configuration
With the configuration-based endpoint resolver, named endpoints can be specified in configuration by prefixing the endpoint value with _endpointName.
, where endpointName
is the endpoint name. For example, consider this appsettings.json configuration which defined a default endpoint (with no name) and an endpoint named "dashboard":
{
"Services": {
"basket": [
"10.2.3.4:8080", /* the default endpoint, when resolving http://basket */
"_dashboard.10.2.3.4:9999" /* the "dashboard" endpoint, resolved via http://_dashboard.basket */
]
}
}
Named endpoints in .NET Aspire
.NET Aspire uses the configuration-based resolver at development and testing time, providing convenient APIs for configuring named endpoints which are then translated into configuration for the target services. For example:
var builder = DistributedApplication.CreateBuilder(args);
var basket = builder.AddProject<Projects.BasketService>("basket")
.WithServiceBinding(hostPort: 9999, scheme: "http", name: "admin");
var adminDashboard = builder.AddProject<Projects.MyDashboardAggregator>("admin-dashboard")
.WithReference(basket.GetEndPoint("admin"));
var frontend = builder.AddProject<Projects.Frontend>("frontend")
.WithReference(basket);
In the above example, the "basket" service exposes an "admin" endpoint in addition to the default "http" endpoint which it exposes. This endpoint is consumed by the "admin-dashboard" project, while the "frontend" project consumes all endpoints from "basket". Alternatively, the "frontend" project could be made to consume only the default "http" endpoint from "basket" by using the GetEndPoint(string name)
method, as in the following example:
// The preceding code is the same as in the above sample
var frontend = builder.AddProject<Projects.Frontend>("frontend")
.WithReference(basket.GetEndpoint("http"));
Named endpoints in Kubernetes using DNS SRV
When deploying to Kubernetes, the DNS SRV service endpoint resolver can be used to resolve named endpoints. For example, the following resource definition will result in a DNS SRV record being created for an endpoint named "default" and an endpoint named "dashboard", both on the service named "basket".
apiVersion: v1
kind: Service
metadata:
name: basket
spec:
selector:
name: basket-service
clusterIP: None
ports:
- name: default
port: 8080
- name: dashboard
port: 8888
To configure a service to resolve the "dashboard" endpoint on the "basket" service, add the DNS SRV service endpoint resolver to the host builder as follows:
builder.Services.AddServiceDiscoveryCore();
builder.Services.AddDnsSrvServiceEndPointResolver();
The special port name "default" is used to specify the default endpoint, resolved using the URI http://basket
.
As in the previous example, add service discovery to an HttpClient
for the basket service:
builder.Services.AddHttpClient<BasketServiceClient>(
static client => client.BaseAddress = new("http://basket"));
Similarly, the "dashboard" endpoint can be targeted as follows:
builder.Services.AddHttpClient<BasketServiceDashboardClient>(
static client => client.BaseAddress = new("http://_dashboard.basket"));
Named endpoints in Azure Container Apps
Named endpoints are not currently supported for services deployed to Azure Container Apps.
Feedback & contributing
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. |
-
net8.0
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.Extensions.ServiceDiscovery.Abstractions (>= 8.0.0-preview.2.23619.3)
NuGet packages (22)
Showing the top 5 NuGet packages that depend on Microsoft.Extensions.ServiceDiscovery:
Package | Downloads |
---|---|
Microsoft.Extensions.ServiceDiscovery.Yarp
Provides extensions for service discovery for the YARP reverse proxy. |
|
RESTworld.AspNetCore
Package Description |
|
Eaf.AspNetCore
Enterprise Application Foundation - AspNetCore integration |
|
Microsoft.Extensions.ServiceDiscovery.Dns
Provides extensions to HttpClient to resolve well-known hostnames to concrete endpoints based on DNS records. Useful for service resolution in orchestrators such as Kubernetes. |
|
Rocket.Surgery.LaunchPad.Foundation
Package Description |
GitHub repositories (38)
Showing the top 5 popular GitHub repositories that depend on Microsoft.Extensions.ServiceDiscovery:
Repository | Stars |
---|---|
ardalis/CleanArchitecture
Clean Architecture Solution Template: A starting point for Clean Architecture with ASP.NET Core
|
|
dotnet/orleans
Cloud Native application framework for .NET
|
|
dotnet/eShop
A reference .NET application implementing an eCommerce site
|
|
fullstackhero/dotnet-starter-kit
Production Grade Cloud-Ready .NET 8 Starter Kit (Web API + Blazor Client) with Multitenancy Support, and Clean/Modular Architecture that saves roughly 200+ Development Hours! All Batteries Included.
|
|
dotnet/aspire
Tools, templates, and packages to accelerate building observable, production-ready apps
|
Version | Downloads | Last updated |
---|---|---|
9.0.0 | 61,557 | 11/12/2024 |
9.0.0-rc.1.24511.1 | 13,411 | 10/15/2024 |
8.2.2 | 109,759 | 10/24/2024 |
8.2.1 | 161,461 | 9/26/2024 |
8.2.0 | 252,096 | 8/29/2024 |
8.1.0 | 312,214 | 7/23/2024 |
8.0.2 | 163,459 | 6/28/2024 |
8.0.1 | 278,300 | 5/21/2024 |
8.0.0 | 176,989 | 5/21/2024 |
8.0.0-preview.7.24251.11 | 63,045 | 5/7/2024 |
8.0.0-preview.6.24214.1 | 60,392 | 4/23/2024 |
8.0.0-preview.5.24201.12 | 49,617 | 4/9/2024 |
8.0.0-preview.4.24156.9 | 87,940 | 3/12/2024 |
8.0.0-preview.3.24105.21 | 91,779 | 2/13/2024 |
8.0.0-preview.2.23619.3 | 84,203 | 12/20/2023 |
8.0.0-preview.1.23557.2 | 73,889 | 11/14/2023 |