Skip to content

在非 Web 应用中使用 MediatR ​

📋 概述 ​

MediatR 不仅适用于 Web 应用,还可以在各种非 Web 场景中发挥价值。本文将详细介绍如何在控制台应用、Worker Service、桌面应用和 Blazor 中集成 MediatR。

学习目标 ​

  • ✅ 在控制台应用中使用 MediatR
  • ✅ Worker Service 后台服务集成
  • ✅ WPF/WinForms 桌面应用集成
  • ✅ Blazor WebAssembly/Server 集成
  • ✅ 理解不同场景的最佳实践

💻 控制台应用集成 ​

基础示例 ​

项目结构 ​

ConsoleApp/
├── Program.cs
├── Commands/
│   └── ProcessDataCommand.cs
├── Handlers/
│   └── ProcessDataHandler.cs
└── Services/
    └── IDataProcessor.cs

安装 NuGet 包 ​

bash
dotnet new console
dotnet add package MediatR
dotnet add package Microsoft.Extensions.DependencyInjection

实现代码 ​

csharp
// Commands/ProcessDataCommand.cs
using MediatR;

public record ProcessDataCommand(string FilePath) : IRequest<ProcessResult>;

public record ProcessResult
{
    public bool Success { get; init; }
    public int RecordsProcessed { get; init; }
    public string? ErrorMessage { get; init; }
}

// Handlers/ProcessDataHandler.cs
public class ProcessDataHandler : IRequestHandler<ProcessDataCommand, ProcessResult>
{
    private readonly ILogger<ProcessDataHandler> _logger;
    
    public ProcessDataHandler(ILogger<ProcessDataHandler> logger)
    {
        _logger = logger;
    }
    
    public async Task<ProcessResult> Handle(
        ProcessDataCommand request, 
        CancellationToken cancellationToken)
    {
        try
        {
            _logger.LogInformation("开始处理文件: {FilePath}", request.FilePath);
            
            // 模拟数据处理
            await Task.Delay(1000, cancellationToken);
            
            var result = new ProcessResult
            {
                Success = true,
                RecordsProcessed = 1000
            };
            
            _logger.LogInformation("处理完成: {RecordsProcessed} 条记录", 
                result.RecordsProcessed);
            
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理失败");
            
            return new ProcessResult
            {
                Success = false,
                ErrorMessage = ex.Message
            };
        }
    }
}

// Program.cs
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

var services = new ServiceCollection();

// 配置日志
services.AddLogging(builder =>
{
    builder.AddConsole();
    builder.SetMinimumLevel(LogLevel.Information);
});

// 注册 MediatR
services.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
});

// 注册其他服务
services.AddSingleton<IDataProcessor, DataProcessor>();

var serviceProvider = services.BuildServiceProvider();

// 使用 MediatR
var mediator = serviceProvider.GetRequiredService<IMediator>();

Console.WriteLine("开始数据处理...");

var result = await mediator.Send(new ProcessDataCommand("data.csv"));

if (result.Success)
{
    Console.WriteLine($"成功处理 {result.RecordsProcessed} 条记录");
}
else
{
    Console.WriteLine($"处理失败: {result.ErrorMessage}");
}

Console.WriteLine("按任意键退出...");
Console.ReadKey();

高级示例:带管道行为 ​

csharp
// Behaviors/LoggingBehavior.cs
public class LoggingBehavior<TRequest, TResponse> 
    : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
    
    public async Task<TResponse> Handle(
        TRequest request,
        RequestHandlerDelegate<TResponse> next,
        CancellationToken cancellationToken)
    {
        _logger.LogInformation("执行命令: {RequestType}", typeof(TRequest).Name);
        
        var stopwatch = Stopwatch.StartNew();
        
        try
        {
            var response = await next();
            
            stopwatch.Stop();
            _logger.LogInformation("命令执行成功,耗时: {ElapsedMs}ms", 
                stopwatch.ElapsedMilliseconds);
            
            return response;
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            _logger.LogError(ex, "命令执行失败,耗时: {ElapsedMs}ms", 
                stopwatch.ElapsedMilliseconds);
            throw;
        }
    }
}

// Behaviors/RetryBehavior.cs
public class RetryBehavior<TRequest, TResponse> 
    : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    private readonly ILogger<RetryBehavior<TRequest, TResponse>> _logger;
    private const int MaxRetries = 3;
    
    public async Task<TResponse> Handle(
        TRequest request,
        RequestHandlerDelegate<TResponse> next,
        CancellationToken cancellationToken)
    {
        Exception? lastException = null;
        
        for (int i = 0; i < MaxRetries; i++)
        {
            try
            {
                return await next();
            }
            catch (Exception ex)
            {
                lastException = ex;
                _logger.LogWarning(ex, 
                    "执行失败,第 {RetryCount} 次重试", i + 1);
                
                if (i < MaxRetries - 1)
                {
                    await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i)), 
                        cancellationToken);
                }
            }
        }
        
        throw lastException!;
    }
}

// 注册
services.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
});

services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RetryBehavior<,>));

🔧 Windows Service / Worker Service ​

Background Service 集成 ​

项目结构 ​

WorkerService/
├── Program.cs
├── Worker.cs
├── Commands/
│   └── ProcessQueueCommand.cs
└── Handlers/
    └── ProcessQueueHandler.cs

创建 Worker Service ​

bash
dotnet new worker
dotnet add package MediatR

实现代码 ​

csharp
// Commands/ProcessQueueCommand.cs
public record ProcessQueueCommand : IRequest<Unit>
{
    public string QueueName { get; init; }
    public int BatchSize { get; init; } = 10;
}

// Handlers/ProcessQueueHandler.cs
public class ProcessQueueHandler : IRequestHandler<ProcessQueueCommand, Unit>
{
    private readonly ILogger<ProcessQueueHandler> _logger;
    private readonly IQueueService _queueService;
    
    public ProcessQueueHandler(
        ILogger<ProcessQueueHandler> logger,
        IQueueService queueService)
    {
        _logger = logger;
        _queueService = queueService;
    }
    
    public async Task<Unit> Handle(
        ProcessQueueCommand request, 
        CancellationToken cancellationToken)
    {
        _logger.LogInformation("开始处理队列: {QueueName}, 批次大小: {BatchSize}",
            request.QueueName, 
            request.BatchSize);
        
        var messages = await _queueService.DequeueAsync(
            request.QueueName, 
            request.BatchSize, 
            cancellationToken);
        
        foreach (var message in messages)
        {
            try
            {
                await ProcessMessageAsync(message, cancellationToken);
                await _queueService.AcknowledgeAsync(message.Id, cancellationToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "处理消息失败: {MessageId}", message.Id);
                await _queueService.NackAsync(message.Id, cancellationToken);
            }
        }
        
        _logger.LogInformation("队列处理完成: {QueueName}", request.QueueName);
        
        return Unit.Value;
    }
    
    private async Task ProcessMessageAsync(QueueMessage message, CancellationToken ct)
    {
        // 处理消息逻辑
        await Task.Delay(100, ct);
    }
}

// Worker.cs
public class Worker : BackgroundService
{
    private readonly IMediator _mediator;
    private readonly ILogger<Worker> _logger;
    private readonly IConfiguration _configuration;
    
    public Worker(
        IMediator mediator,
        ILogger<Worker> logger,
        IConfiguration configuration)
    {
        _mediator = mediator;
        _logger = logger;
        _configuration = configuration;
    }
    
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Worker 启动于: {Time}", DateTimeOffset.Now);
        
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // 定期处理队列
                await _mediator.Send(new ProcessQueueCommand
                {
                    QueueName = _configuration["QueueName"] ?? "default",
                    BatchSize = 10
                }, stoppingToken);
                
                // 等待一段时间后再次检查
                await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
            }
            catch (OperationCanceledException)
            {
                // 正常取消
                break;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Worker 执行出错");
                await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
            }
        }
        
        _logger.LogInformation("Worker 停止于: {Time}", DateTimeOffset.Now);
    }
}

// Program.cs
using MediatR;

var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        // 注册 MediatR
        services.AddMediatR(cfg =>
        {
            cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
        });
        
        // 注册其他服务
        services.AddSingleton<IQueueService, RabbitMqQueueService>();
        
        // 注册 Worker
        services.AddHostedService<Worker>();
    })
    .Build();

await host.RunAsync();

定时任务调度 ​

csharp
// Workers/ScheduledWorker.cs
public class ScheduledWorker : BackgroundService
{
    private readonly IMediator _mediator;
    private readonly ILogger<ScheduledWorker> _logger;
    private Timer? _timer;
    
    public ScheduledWorker(IMediator mediator, ILogger<ScheduledWorker> logger)
    {
        _mediator = mediator;
        _logger = logger;
    }
    
    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("定时任务 Worker 启动");
        
        // 每天凌晨2点执行
        _timer = new Timer(async _ => await ExecuteScheduledTasks(), 
            null, 
            TimeSpan.Zero, 
            TimeSpan.FromHours(24));
        
        return Task.CompletedTask;
    }
    
    private async Task ExecuteScheduledTasks()
    {
        try
        {
            _logger.LogInformation("执行定时任务");
            
            // 清理过期数据
            await _mediator.Send(new CleanupExpiredDataCommand());
            
            // 生成日报
            await _mediator.Send(new GenerateDailyReportCommand());
            
            // 发送通知
            await _mediator.Send(new SendDailyNotificationCommand());
            
            _logger.LogInformation("定时任务执行完成");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "定时任务执行失败");
        }
    }
    
    public override async Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("定时任务 Worker 停止");
        
        _timer?.Change(Timeout.Infinite, 0);
        
        await base.StopAsync(cancellationToken);
    }
    
    public override void Dispose()
    {
        _timer?.Dispose();
        base.Dispose();
    }
}

🖥️ WPF / WinForms 桌面应用集成 ​

WPF 集成 ​

项目结构 ​

WpfApp/
├── App.xaml.cs
├── MainWindow.xaml.cs
├── ViewModels/
│   └── MainViewModel.cs
├── Commands/
│   └── LoadDataCommand.cs
└── Handlers/
    └── LoadDataHandler.cs

安装 NuGet 包 ​

bash
dotnet add package MediatR
dotnet add package Microsoft.Extensions.DependencyInjection
dotnet add package CommunityToolkit.Mvvm

实现代码 ​

csharp
// App.xaml.cs
using MediatR;
using Microsoft.Extensions.DependencyInjection;

public partial class App : Application
{
    public static IServiceProvider ServiceProvider { get; private set; } = default!;
    
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        
        var services = new ServiceCollection();
        
        // 注册 MediatR
        services.AddMediatR(cfg =>
        {
            cfg.RegisterServicesFromAssembly(typeof(App).Assembly);
        });
        
        // 注册 ViewModel
        services.AddTransient<MainViewModel>();
        
        // 注册其他服务
        services.AddSingleton<IDataService, DataService>();
        
        ServiceProvider = services.BuildServiceProvider();
        
        // 显示主窗口
        var mainWindow = new MainWindow();
        mainWindow.Show();
    }
}

// ViewModels/MainViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MediatR;

public partial class MainViewModel : ObservableObject
{
    private readonly IMediator _mediator;
    
    [ObservableProperty]
    private ObservableCollection<OrderDto> _orders = new();
    
    [ObservableProperty]
    private bool _isLoading;
    
    [ObservableProperty]
    private string? _statusMessage;
    
    public MainViewModel(IMediator mediator)
    {
        _mediator = mediator;
    }
    
    [RelayCommand]
    private async Task LoadDataAsync()
    {
        if (IsLoading) return;
        
        IsLoading = true;
        StatusMessage = "正在加载数据...";
        
        try
        {
            var result = await _mediator.Send(new LoadOrdersQuery());
            
            Orders.Clear();
            foreach (var order in result)
            {
                Orders.Add(order);
            }
            
            StatusMessage = $"加载完成,共 {result.Count} 条记录";
        }
        catch (Exception ex)
        {
            StatusMessage = $"加载失败: {ex.Message}";
        }
        finally
        {
            IsLoading = false;
        }
    }
    
    [RelayCommand]
    private async Task CreateOrderAsync()
    {
        var dialog = new CreateOrderDialog();
        var result = dialog.ShowDialog();
        
        if (result == true)
        {
            var command = new CreateOrderCommand
            {
                CustomerName = dialog.CustomerName,
                Amount = dialog.Amount
            };
            
            await _mediator.Send(command);
            
            // 重新加载数据
            await LoadDataAsync();
        }
    }
}

// Commands/LoadOrdersQuery.cs
public record LoadOrdersQuery : IRequest<List<OrderDto>>;

// Handlers/LoadOrdersHandler.cs
public class LoadOrdersHandler : IRequestHandler<LoadOrdersQuery, List<OrderDto>>
{
    private readonly IDataService _dataService;
    
    public LoadOrdersHandler(IDataService dataService)
    {
        _dataService = dataService;
    }
    
    public async Task<List<OrderDto>> Handle(
        LoadOrdersQuery request, 
        CancellationToken cancellationToken)
    {
        return await _dataService.GetOrdersAsync(cancellationToken);
    }
}

// MainWindow.xaml.cs
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        
        DataContext = App.ServiceProvider.GetRequiredService<MainViewModel>();
    }
}

WinForms 集成 ​

csharp
// Program.cs
using MediatR;
using Microsoft.Extensions.DependencyInjection;

static class Program
{
    public static IServiceProvider ServiceProvider { get; private set; } = default!;
    
    [STAThread]
    static void Main()
    {
        ApplicationConfiguration.Initialize();
        
        var services = new ServiceCollection();
        
        // 注册 MediatR
        services.AddMediatR(cfg =>
        {
            cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
        });
        
        // 注册 Form
        services.AddTransient<MainForm>();
        
        ServiceProvider = services.BuildServiceProvider();
        
        Application.Run(ServiceProvider.GetRequiredService<MainForm>());
    }
}

// MainForm.cs
public partial class MainForm : Form
{
    private readonly IMediator _mediator;
    private DataGridView _dataGridView;
    private Button _loadButton;
    
    public MainForm(IMediator mediator)
    {
        _mediator = mediator;
        InitializeComponent();
        SetupUI();
    }
    
    private void SetupUI()
    {
        _dataGridView = new DataGridView { Dock = DockStyle.Fill };
        _loadButton = new Button { Text = "加载数据", Dock = DockStyle.Top };
        _loadButton.Click += LoadButton_Click;
        
        Controls.Add(_dataGridView);
        Controls.Add(_loadButton);
    }
    
    private async void LoadButton_Click(object? sender, EventArgs e)
    {
        _loadButton.Enabled = false;
        
        try
        {
            var orders = await _mediator.Send(new LoadOrdersQuery());
            _dataGridView.DataSource = orders;
        }
        catch (Exception ex)
        {
            MessageBox.Show($"加载失败: {ex.Message}");
        }
        finally
        {
            _loadButton.Enabled = true;
        }
    }
}

🌐 Blazor WebAssembly / Server ​

Blazor Server 集成 ​

项目结构 ​

BlazorApp/
├── Program.cs
├── Pages/
│   └── Orders.razor
├── Components/
│   └── OrderList.razor
└── Features/
    ├── Orders/
    │   ├── Queries/
    │   └── Commands/
    └── Shared/

安装 NuGet 包 ​

bash
dotnet new blazorserver
dotnet add package MediatR

实现代码 ​

csharp
// Program.cs
using MediatR;

var builder = WebApplication.CreateBuilder(args);

// 添加 Blazor Server 服务
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

// 注册 MediatR(Scoped 生命周期)
builder.Services.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
    cfg.Lifetime = ServiceLifetime.Scoped; // Blazor Server 推荐 Scoped
});

// 注册其他服务
builder.Services.AddScoped<IOrderService, OrderService>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();
razor
@* Pages/Orders.razor *@
@page "/orders"
@inject IMediator Mediator
@inject NavigationManager Navigation

<h3>订单管理</h3>

@if (isLoading)
{
    <p>加载中...</p>
}
else if (errorMessage != null)
{
    <div class="alert alert-danger">@errorMessage</div>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>订单号</th>
                <th>客户</th>
                <th>金额</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var order in orders)
            {
                <tr>
                    <td>@order.OrderNumber</td>
                    <td>@order.CustomerName</td>
                    <td>¥@order.Amount.ToString("F2")</td>
                    <td>
                        <button class="btn btn-sm btn-primary" 
                                @onclick="() => EditOrder(order.Id)">
                            编辑
                        </button>
                        <button class="btn btn-sm btn-danger" 
                                @onclick="() => DeleteOrder(order.Id)">
                            删除
                        </button>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    
    <button class="btn btn-success" @onclick="CreateNewOrder">新建订单</button>
}

@code {
    private List<OrderDto> orders = new();
    private bool isLoading;
    private string? errorMessage;
    
    protected override async Task OnInitializedAsync()
    {
        await LoadOrdersAsync();
    }
    
    private async Task LoadOrdersAsync()
    {
        isLoading = true;
        errorMessage = null;
        
        try
        {
            orders = await Mediator.Send(new ListOrdersQuery());
        }
        catch (Exception ex)
        {
            errorMessage = $"加载失败: {ex.Message}";
        }
        finally
        {
            isLoading = false;
        }
    }
    
    private async Task CreateNewOrder()
    {
        Navigation.NavigateTo("/orders/create");
    }
    
    private async Task EditOrder(int id)
    {
        Navigation.NavigateTo($"/orders/edit/{id}");
    }
    
    private async Task DeleteOrder(int id)
    {
        var confirmed = await JSRuntime.InvokeAsync<bool>(
            "confirm", "确定要删除这个订单吗?");
        
        if (confirmed)
        {
            await Mediator.Send(new DeleteOrderCommand(id));
            await LoadOrdersAsync();
        }
    }
}
razor
@* Pages/CreateOrder.razor *@
@page "/orders/create"
@inject IMediator Mediator
@inject NavigationManager Navigation

<h3>创建订单</h3>

<EditForm Model="@orderModel" OnValidSubmit="@HandleSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    
    <div class="form-group">
        <label>客户名称</label>
        <InputText @bind-Value="orderModel.CustomerName" class="form-control" />
    </div>
    
    <div class="form-group">
        <label>金额</label>
        <InputNumber @bind-Value="orderModel.Amount" class="form-control" />
    </div>
    
    <button type="submit" class="btn btn-primary" disabled="@isSubmitting">
        @(isSubmitting ? "提交中..." : "提交")
    </button>
    <button type="button" class="btn btn-secondary" @onclick="Cancel">取消</button>
</EditForm>

@if (errorMessage != null)
{
    <div class="alert alert-danger mt-3">@errorMessage</div>
}

@code {
    private OrderFormModel orderModel = new();
    private bool isSubmitting;
    private string? errorMessage;
    
    private async Task HandleSubmit()
    {
        isSubmitting = true;
        errorMessage = null;
        
        try
        {
            var command = new CreateOrderCommand
            {
                CustomerName = orderModel.CustomerName,
                Amount = orderModel.Amount
            };
            
            await Mediator.Send(command);
            
            Navigation.NavigateTo("/orders");
        }
        catch (Exception ex)
        {
            errorMessage = $"创建失败: {ex.Message}";
        }
        finally
        {
            isSubmitting = false;
        }
    }
    
    private void Cancel()
    {
        Navigation.NavigateTo("/orders");
    }
    
    public class OrderFormModel
    {
        [Required]
        [StringLength(100)]
        public string CustomerName { get; set; } = "";
        
        [Required]
        [Range(0.01, double.MaxValue)]
        public decimal Amount { get; set; }
    }
}

Blazor WebAssembly 集成 ​

csharp
// Program.cs (WebAssembly)
using MediatR;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");

// 注册 MediatR
builder.Services.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
    cfg.Lifetime = ServiceLifetime.Singleton; // WASM 推荐 Singleton
});

// 注册 HTTP 客户端
builder.Services.AddScoped(sp => 
    new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

await builder.Build().RunAsync();

注意:在 WebAssembly 中,所有代码都在浏览器中运行,因此:

  • 使用 Singleton 生命周期
  • 需要通过 HTTP API 调用后端
  • Handler 中应该调用 HTTP 客户端而非直接访问数据库
csharp
// Handlers/CreateOrderHandler.cs (WebAssembly)
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, int>
{
    private readonly HttpClient _httpClient;
    
    public CreateOrderHandler(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
    
    public async Task<int> Handle(
        CreateOrderCommand request, 
        CancellationToken cancellationToken)
    {
        var response = await _httpClient.PostAsJsonAsync(
            "api/orders", 
            request, 
            cancellationToken);
        
        response.EnsureSuccessStatusCode();
        
        var orderId = await response.Content.ReadFromJsonAsync<int>(cancellationToken);
        
        return orderId;
    }
}

🎯 各场景对比总结 ​

场景生命周期注意事项推荐度
控制台应用Singleton手动构建 ServiceProvider⭐⭐⭐⭐
Worker ServiceSingleton注意异步取消⭐⭐⭐⭐⭐
WPFSingletonUI 线程同步⭐⭐⭐⭐
WinFormsSingletonUI 线程同步⭐⭐⭐
Blazor ServerScoped每个 Circuit 独立⭐⭐⭐⭐⭐
Blazor WASMSingleton通过 HTTP 调用后端⭐⭐⭐⭐

💡 最佳实践 ​

✅ 推荐做法 ​

  1. 选择合适的生命周期

    • 控制台/桌面应用:Singleton
    • Blazor Server:Scoped
    • Blazor WASM:Singleton
  2. 正确处理取消令牌

    csharp
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            await DoWorkAsync(stoppingToken); // 传递取消令牌
        }
    }
  3. UI 线程同步

    csharp
    // WPF
    Application.Current.Dispatcher.Invoke(() =>
    {
        // 更新 UI
    });
    
    // WinForms
    this.Invoke(() =>
    {
        // 更新 UI
    });
  4. 异常处理

    csharp
    try
    {
        await _mediator.Send(command);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "操作失败");
        // 向用户显示友好错误消息
    }

❌ 避免做法 ​

  1. 不要在 UI 线程执行耗时操作
  2. 不要忽略取消令牌
  3. 不要在 Blazor WASM 中直接访问数据库
  4. 不要忘记释放资源

📚 参考资源 ​

Released under the CC BY-SA 4.0 License.