如何在WPF应用中正确注册MediatR?DDD+MVVM场景遇实例缺失问题
解决WPF+Catel+MediatR的注册与领域事件调用问题
1. 正确注册MediatR到Catel ServiceLocator
MediatR不能仅手动注册IMediator和Mediator,还需注册所有通知/请求处理程序及内部依赖。在App.xaml.cs的OnStartup方法中完成完整注册:
using Catel.IoC; using MediatR; using System.Reflection; protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); var serviceLocator = ServiceLocator.Default; // 注册MediatR核心依赖:ServiceFactory用于解析处理程序 serviceLocator.RegisterType<ServiceFactory>(() => type => serviceLocator.ResolveType(type)); serviceLocator.RegisterType<IMediator, Mediator>(); // 扫描并注册所有程序集中的MediatR处理程序 var assembliesToScan = new[] { Assembly.GetExecutingAssembly(), // 当前WPF项目程序集 typeof(AddingAddress).Assembly // 包含领域事件/处理程序的程序集 }; foreach (var assembly in assembliesToScan) { // 注册所有INotificationHandler实现 var handlerTypes = assembly.GetTypes() .Where(t => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(INotificationHandler<>))); foreach (var handlerType in handlerTypes) { var interfaceType = handlerType.GetInterfaces() .First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(INotificationHandler<>)); serviceLocator.RegisterType(interfaceType, handlerType); } // 按需注册IRequestHandler(如果有命令处理场景) var requestHandlerTypes = assembly.GetTypes() .Where(t => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IRequestHandler<,>))); foreach (var handlerType in requestHandlerTypes) { var interfaceType = handlerType.GetInterfaces() .First(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IRequestHandler<,>)); serviceLocator.RegisterType(interfaceType, handlerType); } } // 配置DomainEvents的Mediator获取逻辑(避免领域层直接依赖Catel) DomainEvents.Mediator = () => serviceLocator.ResolveType<IMediator>(); }
2. 修复DomainEvents类
移除重复的ServiceLocator调用,保持领域层纯净,仅通过预配置的Func<IMediator>获取实例:
public static class DomainEvents { public static Func<IMediator> Mediator { get; set; } public static async Task Raise<T>(T args) where T : INotification { if (Mediator == null) { throw new InvalidOperationException("Mediator工厂未初始化"); } var mediator = Mediator.Invoke(); await mediator.Publish(args); } }
3. 核心验证点
- 确保领域事件类实现
INotification接口:public class AddingAddress : INotification { public AddAddressCommand Command { get; } public AddingAddress(AddAddressCommand command) { Command = command; } } - 确保事件处理程序正确实现接口,且所在程序集被扫描注册:
public class AddingAddressHandler : INotificationHandler<AddingAddress> { private readonly IAddressRepository _addressRepository; public AddingAddressHandler(IAddressRepository addressRepository) { _addressRepository = addressRepository; } public async Task Handle(AddingAddress notification, CancellationToken cancellationToken) { // 地址存在性验证逻辑 var existingAddress = await _addressRepository.GetByDetails(notification.Command.Address); if (existingAddress != null) { throw new InvalidOperationException("该地址已存在"); // 或返回ErrorOr类型错误,根据架构调整 } } }
4. 常见问题排查
- 若提示找不到
IMediator:确认注册逻辑在DomainEvents.Raise调用前执行,且ServiceLocator.Default的注册未被覆盖。 - 若处理程序不执行:检查处理程序是否实现正确的泛型接口,且所在程序集被加入扫描列表。
- 跨程序集依赖:领域层仅需引用
MediatR核心包,WPF项目引用领域层、Catel及MediatR相关包。
内容的提问来源于stack exchange,提问作者JeroenZenM
相关产品推荐
相关产品推荐

