Repository navigation
Transports gRPC
Typed requests between services over HTTP/2, with no broker to run: the client calls the hosts of the services that own the data.
dotnet add package FxMap.GrpcEvery service that maps data needs the core FxMap package, and the owning service also needs a data provider. All FxMap.* packages must use the same version.
List the hosts of the services that own the entities. You do not say which host owns which entity: FxMap asks the hosts the first time it needs a distributed key.
builder.Services.AddFxMap(cfg =>
{
cfg.AddEntitiesFromAssemblyContaining<SomeEntityAssemblyMarker>();
cfg.AddProfilesFromAssemblyContaining<SomeProfileAssemblyMarker>();
cfg.AddGrpcClients(c => c.AddGrpcHosts("http://localhost:5001", "http://localhost:5013"));
});Since 4.1.3, AddGrpcHosts also takes a list of hosts (an IEnumerable<string> or an array), so the hosts can come straight from appsettings.json:
// appsettings.json
// { "FxMap": { "GrpcHosts": [ "https://users:5001", "https://products:5001" ] } }
var hosts = builder.Configuration.GetSection("FxMap:GrpcHosts").Get<string[]>() ?? [];
builder.Services.AddFxMap(cfg =>
{
cfg.AddEntitiesFromAssemblyContaining<SomeEntityAssemblyMarker>();
cfg.AddGrpcClients(c => c.AddGrpcHosts(hosts));
});The three forms are equal: AddGrpcHosts("a", "b"), AddGrpcHosts(["a", "b"]) and AddGrpcHosts(list). A host that is listed twice is used once, and an empty list registers nothing.
Register the entities and a data provider as usual, add gRPC, and map the FxMap endpoint:
builder.Services.AddFxMap(cfg =>
{
cfg.AddEntitiesFromAssemblyContaining<UserConfig>();
})
.AddEntityFrameworkCore(c => c.AddDbContexts(typeof(UserDbContext)));
builder.Services.AddGrpc();
var app = builder.Build();
app.MapFxMapperGrpc();
app.Run();The server needs an HTTP/2 endpoint. Without TLS, use a dedicated HTTP/2-only endpoint next to your HTTP/1.1 one: see the Kestrel guide.
- The first time a distributed key is needed, the client asks the listed hosts which keys they own (
GetDistributedKeys), and remembers the answer. - Each request holds the ids and the expressions for one distributed key and one level. The client sends it to the host that owns the key (
GetItems), and a hundred objects still make one request. - The headers of the
IContextbecome gRPC metadata, so the owner sees them. A channel is created once for each host and reused. - The owner answers with the values, and with the expression errors it isolated (4.1.3+), which travel in the gRPC contract like the values.
// Shared contract
public sealed class UserDistributedKey : IDistributedKey;
// Owner (users service): the entity and how it is exposed
public class UserConfig : EntityConfigureOf<User>
{
protected override void Configure()
{
Id(x => x.Id);
DefaultProperty(x => x.Name);
UseDistributedKey<UserDistributedKey>();
}
}
// Client (orders service): the DTO and where its values come from
public class OrderResponse
{
public string Id { get; set; }
public string UserId { get; set; }
public string? UserName { get; set; }
public string? UserEmail { get; set; }
}
public class OrderResponseProfile : ProfileOf<OrderResponse>
{
protected override void Configure() =>
UseDistributedKey<UserDistributedKey>()
.Of(x => x.UserId)
.For(x => x.UserName)
.For(x => x.UserEmail, "Email");
}
// In an endpoint of the orders service
await distributedMapper.MapDataAsync(orders);A call goes straight to the owner, so there is no broker to run. The brokered transports use the supervisor pattern; gRPC does not, because ASP.NET Core and Kestrel handle the HTTP/2 connections. Each call has a time limit of 3 seconds, and it cannot be changed in 4.1.3.
If a host cannot be reached when FxMap asks which keys it owns, FxMap leaves it aside and asks it again the next time it needs a key it has not found. With ThrowIfException() the error is thrown instead (this works wherever you call it, also after AddGrpcClients, which was a defect before 4.1.2).
FxMap picks the host that owns a key; it does not spread the calls of one key over several instances. To balance the load, give the host one address that does it (a service mesh, Kubernetes Service or a load balancer that understands HTTP/2).
Source: https://fxmapper.net/docs/transports/grpc/ — the website is always the most up to date version.
Introduction
Getting Started
Configuration
- Service Registration
- Entities & Profiles
- Handlers
- Pipelines
- Strongly Typed IDs
- Error Handling
- Retry Policy
- Supervisor
- Telemetry
- Kestrel (HTTP/2)
- Analyzers
Expressions
- Overview
- Property Access
- Filters, Sorting & Paging
- Functions
- Aggregations
- Projections
- Coalesce & Ternary
- GroupBy
Data Providers
Transports
Integrations
Quality
AI Assistants
Migration
Release Notes