Skip to content

Migration Upgrade to 5 1

quyvu edited this page Oct 19, 2026 · 2 revisions

Upgrade to 5.1

FxMap 5.1 fixes the retry policy and makes the public API smaller: the configuration is published by interfaces, and the internals are internal.

Do you need this guide?

For the usual use, nothing changes: services.AddFxMap(cfg => ...), IDistributedMapper, profiles, entity configurations, AddEntityFrameworkCore, AddMongoDb, and a transport with a lambda all work as before, because the type of the lambda parameter is inferred, and it is the interface now. Read on if you name a configurator type, use the expression engine, call SetRetryPolicy, or have a package compiled against 5.0.0.

What Changed

  • The retry policy waits before each retry, calls onRetry before it, throws the last exception, works when ThrowIfException() is not called, and has a new shouldRetry. See Retry Policy.
  • The configuration is published by interfaces, and the classes that implement them are internal sealed.
  • The internals of the expression engine and a few other helpers are internal.

Step 1: Build, and Replace the Types the Compiler Rejects

AddFxMap(cfg => ...) and every AddXxx(c => ...) take the interface. If the compiler says that a type is inaccessible, use its interface:

Public (use these) Was
IMapConfigurator MapConfigurator
IKafkaConfigurator, IRabbitMqConfigurator, ISqsConfigurator, IGrpcClientsConfigurator KafkaConfigurator, RabbitMqConfigurator, SqsConfigurator, GrpcClientsConfigurator
IEfCoreConfigurator, IMongoDbConfigurator, IHotChocolateConfigurator EfCoreConfigurator, MongoDbConfigurator, HotChocolateConfigurator
INatsConfigurator, IAzureServiceBusConfigurator NatsClientSetting, AzureServiceBusClientSetting
// 5.0
static void AddMyDefaults(MapConfigurator cfg) { /* ... */ }
 
// 5.1
static void AddMyDefaults(IMapConfigurator cfg) { /* ... */ }
 
// 5.0:  Action<MapConfigurator>   5.1:  Action<IMapConfigurator>

The members that only read the settings (ServiceHosts, NatsOption, MaxNestingDepth, SupervisorOptions, ProfileConfigs...) are not part of the interfaces. What AddFxMap returns, for .AddEntityFrameworkCore(...) and .AddMongoDb(...), keeps its members internal. The classes of options that you fill in a callback (RabbitMqCredential, SqsCredential, KafkaSslOptions, FxNatsOpts) are still public.

Step 2: Remove What Left the Public API

These are details of the implementation, so they are internal now. There is no replacement: they were never meant to be called from outside.

  • The expression engine: the nodes of the tree (FilterNode, FunctionNode...), Tokenizer, Token, ExpressionParser, ExpressionParseException, IExpressionNodeVisitor, LinqExpressionBuilder, ProjectionBuilder, and BsonProjectionBuilder of MongoDB.
  • Accessors and helpers: TypeAccessor, ITypeAccessor, PropertyAccessor<,>, the delegates GetEntityConfig, GetProfileConfig, GetTypeAccessor and MapperDelegates, ReceivedPipelinesOrchestrator, RequestContextImpl, JsonSerializer, ServerSupervisor (IServerSupervisor is still public), and the extension helpers.
  • Transports and providers: the gRPC types that Grpc.Tools generates from the .proto, GrpcServer, GrpcRequestClient, MessageRequestWrapped of NATS, and FieldContext of HotChocolate.

Still public on purpose: IFluentProfileConfig, IFluentEntityConfig and what ProfileOf<T> exposes, the interfaces for custom transports and providers (IRequestClient, IRequestServer, IClientRequestHandler, IQueryOfHandler, QueryHandlerBuilder), and the exceptions.

If you wrote a visitor of the expression tree for 5.0 (the guide told you to drop VisitIndexer), it cannot compile against 5.1: IExpressionNodeVisitor is internal now.

Step 3: Recompile Packages Built Against 5.0.0

A package that was compiled against 5.0.0 and calls one of the types that left must be compiled again: binary compatibility is not kept for the types that left the public API. Move every FxMap.* package to 5.1.0, as always on the same version.

Step 4: Check Your Retry Policy

If you call SetRetryPolicy, read what changed in Retry Policy, and look for these:

  • onRetry receives the exception of the attempt that failed, and is called before the wait, not after it. It is not called for the last failure.
  • The exception you catch after the retries is the last one, not the first.
  • A request that a local handler answers is no longer retried. Its errors are thrown at once.
  • With ThrowIfException() not called, requests through a transport are now retried, and the error is suppressed only after the last attempt. If you had a retry policy that did nothing, it starts to work, so check the delay and the count.

Add shouldRetry for the failures that are not worth a retry:

cfg.SetRetryPolicy(
    retryCount: 3,                                                  // retries after the first attempt (at most 4 attempts)
    sleepDurationProvider: n => TimeSpan.FromMilliseconds(          // waited BEFORE retry n (1 = the first retry)
        Random.Shared.Next(0, 200 * (1 << (n - 1)))),               // exponential backoff with jitter
    onRetry: (ex, delay) => logger.LogWarning(ex, "Retry in {Delay}", delay),
    shouldRetry: ex => ex is TimeoutException or IOException);      // retry only what can go away

Checklist

  • Update every FxMap.* package to 5.1.0 (all on the same version).
  • Build. Replace each configurator class the compiler rejects with its interface.
  • Remove code that uses the expression engine, ServerSupervisor or the generated gRPC messages.
  • Recompile the packages you built against 5.0.0.
  • If you call SetRetryPolicy, check onRetry, the exception you catch, and local handlers, and add shouldRetry.

The changelog of the release is docs/changelogs/v5.1.0.md in the repository.


Source: https://fxmapper.net/docs/migrate-to-v5-1/ — the website is always the most up to date version.

Clone this wiki locally