Receita de migração: remove MediatR de um projeto .NET e substitui por um dispatcher nativo. Use quando o usuário mencionar migração de MediatR, remover MediatR, ou substituir MediatR.
Migrar o projeto em $ARGUMENTS removendo a dependência do MediatR e substituindo por um dispatcher nativo.
O MediatR é uma biblioteca de mediação para .NET que implementa o padrão Mediator/CQRS. Esta migração remove essa dependência externa, substituindo por interfaces e implementação próprias, reduzindo acoplamento com terceiros.
namespace {Namespace}.Infrastructure;
public interface IRequest<TResponse> { }
namespace {Namespace}.Infrastructure;
public interface IRequestHandler<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken = default);
}
Interface totalmente genérica — sem dynamic, com segurança de tipos em tempo de compilação:
namespace {Namespace}.Infrastructure;
public interface IDispatcher
{
Task<TResponse> Send<TRequest, TResponse>(TRequest request, CancellationToken cancellationToken = default)
where TRequest : IRequest<TResponse>;
}
Implementação sem reflection nem dynamic — o handler é resolvido diretamente pelo tipo genérico:
namespace {Namespace}.Infrastructure;
public class Dispatcher : IDispatcher
{
private readonly IServiceProvider _serviceProvider;
public Dispatcher(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task<TResponse> Send<TRequest, TResponse>(TRequest request, CancellationToken cancellationToken = default)
where TRequest : IRequest<TResponse>
{
var handler = _serviceProvider.GetService<IRequestHandler<TRequest, TResponse>>()
?? throw new InvalidOperationException(
$"No handler registered for '{typeof(TRequest).Name}'. " +
$"Make sure IRequestHandler<{typeof(TRequest).Name}, {typeof(TResponse).Name}> is registered in the DI container.");
return await handler.Handle(request, cancellationToken);
}
}
Registro automático de handlers via assembly scanning — evita registros hardcoded que quebram em runtime:
namespace {Namespace}.Infrastructure;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddHandlers(this IServiceCollection services, Assembly assembly)
{
var handlerInterface = typeof(IRequestHandler<,>);
var handlers = assembly.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract)
.SelectMany(t => t.GetInterfaces()
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == handlerInterface)
.Select(i => (Handler: t, Interface: i)));
foreach (var (handler, iface) in handlers)
services.AddScoped(iface, handler);
return services;
}
}
using MediatR; por using {Namespace}.Infrastructure;IRequest<T> mantém o mesmo nome (agora é local)using MediatR; por using {Namespace}.Infrastructure;IRequestHandler<TRequest, TResponse> agora vem do InfrastructureTask<TResponse> Handle(TRequest request, CancellationToken cancellationToken = default)IMediator por IDispatcher_mediator por _dispatcherusing MediatR; por using {Namespace}.Infrastructure;await _dispatcher.Send(request) → await _dispatcher.Send<TRequest, TResponse>(request)
await _dispatcher.Send<GetCampaignQuery, CampaignDto>(query, cancellationToken)builder.Services.AddMediatR(...)using {Namespace}.Infrastructure;
using System.Reflection;
builder.Services.AddScoped<IDispatcher, Dispatcher>();
builder.Services.AddHandlers(typeof({SomeHandler}).Assembly);
AddScoped<IRequestHandler<...>> hardcodeddotnet remove package MediatRdotnet remove package MediatR.Extensions.Microsoft.DependencyInjection (se presente)IMediator por mocks de IDispatcher.Send<TRequest, TResponse>(...) em vez de .Send(...)ShouldSendToDispatcherAtLeastOnce (não ShouldSentTo...)migration/remove-mediatrrefactor: replace MediatR with native dispatcherrefactor: replace MediatR with native dispatcherPara identificar se um projeto usa MediatR, procure por:
<PackageReference Include="MediatR" no .csprojusing MediatR; nos arquivos .csIMediator nos controllersAddMediatR no Program.cs