You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:33:25