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

ASP.NET Core 3.1多用户定时检测WooCommerce新订单并邮件通知方案

多用户WooCommerce订单检测后台服务实现

1. 基础实体定义

首先需要两个核心实体类,对应MySQL数据库表:

  • AppUser:存储用户信息和WooCommerce站点配置
  • TrackedOrder:记录已发送通知的订单,避免重复通知
// AppUser.cs - 对应数据库用户表
public class AppUser
{
    public int Id { get; set; }
    public string Email { get; set; }
    public string WooCommerceSiteUrl { get; set; }
    public string WooConsumerKey { get; set; }
    public string WooConsumerSecret { get; set; }
    // 记录最后一次检查订单的时间,用于筛选新订单
    public DateTime LastOrderCheckTime { get; set; } = DateTime.UtcNow.AddHours(-1);
}

// TrackedOrder.cs - 对应已通知订单记录表
public class TrackedOrder
{
    public int Id { get; set; }
    public int AppUserId { get; set; }
    // WooCommerce订单ID
    public long WooOrderId { get; set; }
    public DateTime NotificationSentTime { get; set; } = DateTime.UtcNow;
    
    public AppUser AppUser { get; set; }
}

在DbContext中注册实体并配置约束:

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
    
    public DbSet<AppUser> AppUsers { get; set; }
    public DbSet<TrackedOrder> TrackedOrders { get; set; }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 配置复合唯一键:同一用户的同一订单只能记录一次
        modelBuilder.Entity<TrackedOrder>()
            .HasIndex(t => new { t.AppUserId, t.WooOrderId })
            .IsUnique();
    }
}

2. 后台服务实现

创建继承BackgroundService的后台服务,这是ASP.NET Core实现定时任务的标准方式:

public class WooOrderCheckService : BackgroundService
{
    private readonly IServiceScopeFactory _scopeFactory;
    private readonly ILogger<WooOrderCheckService> _logger;
    // 随机检测间隔(5-10分钟),避免所有用户同时请求API
    private readonly TimeSpan _checkInterval = TimeSpan.FromMinutes(new Random().Next(5, 11));

    public WooOrderCheckService(IServiceScopeFactory scopeFactory, ILogger<WooOrderCheckService> logger)
    {
        _scopeFactory = scopeFactory;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("WooCommerce订单检测服务启动,间隔{Minutes}分钟", _checkInterval.TotalMinutes);
        
        // 循环执行直到服务停止
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // 创建作用域:后台服务是单例,DbContext是Scoped,必须通过作用域获取
                using var scope = _scopeFactory.CreateScope();
                var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
                var emailSender = scope.ServiceProvider.GetRequiredService<IEmailSender>();

                // 获取所有需要检测的用户(可根据实际情况过滤,比如仅启用状态的用户)
                var users = await dbContext.AppUsers.ToListAsync(stoppingToken);
                
                // 并行处理用户任务(用户量大时可通过SemaphoreSlim限制并发数)
                var tasks = users.Select(user => ProcessUserOrdersAsync(user, dbContext, emailSender, stoppingToken));
                await Task.WhenAll(tasks);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "订单检测任务执行失败");
            }
            
            // 等待下一轮检测
            await Task.Delay(_checkInterval, stoppingToken);
        }
        
        _logger.LogInformation("WooCommerce订单检测服务已停止");
    }

    private async Task ProcessUserOrdersAsync(AppUser user, AppDbContext dbContext, IEmailSender emailSender, CancellationToken stoppingToken)
    {
        try
        {
            _logger.LogInformation("开始检测用户{UserId}的WooCommerce订单", user.Id);
            
            // 1. 为当前用户创建WooCommerce客户端实例
            var wooClient = new WooCommerce.NET.WooCommerceAPI(
                user.WooCommerceSiteUrl,
                user.WooConsumerKey,
                user.WooConsumerSecret);

            // 2. 获取最后一次检查时间之后的订单
            var filter = new Dictionary<string, string>
            {
                {"after", user.LastOrderCheckTime.ToString("yyyy-MM-ddTHH:mm:ss")},
                {"status", "processing,pending,on-hold,completed"} // 按需筛选订单状态
            };
            
            var orders = await wooClient.Order.GetAll(filter, stoppingToken);
            
            if (orders == null || !orders.Any())
            {
                _logger.LogInformation("用户{UserId}无新订单", user.Id);
                user.LastOrderCheckTime = DateTime.UtcNow;
                await dbContext.SaveChangesAsync(stoppingToken);
                return;
            }

            // 3. 筛选未通知过的订单
            var trackedOrderIds = await dbContext.TrackedOrders
                .Where(t => t.AppUserId == user.Id)
                .Select(t => t.WooOrderId)
                .ToListAsync(stoppingToken);
            
            var newOrders = orders.Where(o => !trackedOrderIds.Contains(o.id.Value)).ToList();
            
            if (!newOrders.Any())
            {
                _logger.LogInformation("用户{UserId}的订单已全部通知", user.Id);
                user.LastOrderCheckTime = DateTime.UtcNow;
                await dbContext.SaveChangesAsync(stoppingToken);
                return;
            }

            // 4. 发送邮件通知并记录已通知订单
            foreach (var order in newOrders)
            {
                var subject = $"您有新的WooCommerce订单 #{order.id}";
                var message = $"订单编号:{order.id}\n客户姓名:{order.billing.first_name} {order.billing.last_name}\n订单金额:{order.total}\n订单状态:{order.status}";
                
                await emailSender.SendEmailAsync(user.Email, subject, message);
                
                dbContext.TrackedOrders.Add(new TrackedOrder
                {
                    AppUserId = user.Id,
                    WooOrderId = order.id.Value
                });
            }

            // 5. 更新最后检查时间并保存所有变更
            user.LastOrderCheckTime = DateTime.UtcNow;
            await dbContext.SaveChangesAsync(stoppingToken);
            
            _logger.LogInformation("用户{UserId}完成新订单通知,共{Count}条", user.Id, newOrders.Count);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理用户{UserId}订单时出错", user.Id);
        }
    }
}

3. 依赖注入配置

在Startup.cs的ConfigureServices方法中注册服务:

public void ConfigureServices(IServiceCollection services)
{
    // 注册MySQL DbContext
    services.AddDbContext<AppDbContext>(options =>
        options.UseMySql(Configuration.GetConnectionString("DefaultConnection"), 
            new MySqlServerVersion(new Version(8, 0, 26)))); // 根据你的MySQL版本调整

    // 注册后台服务
    services.AddHostedService<WooOrderCheckService>();

    // 注册邮件服务
    services.AddTransient<IEmailSender, EmailSender>();

    // 其他服务注册...
}

4. 邮件服务实现示例

实现IEmailSender接口,使用SMTP发送邮件:

public class EmailSender : IEmailSender
{
    private readonly IConfiguration _configuration;

    public EmailSender(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public async Task SendEmailAsync(string email, string subject, string message)
    {
        using var client = new SmtpClient(_configuration["Smtp:Host"], int.Parse(_configuration["Smtp:Port"]))
        {
            Credentials = new NetworkCredential(_configuration["Smtp:Username"], _configuration["Smtp:Password"]),
            EnableSsl = bool.Parse(_configuration["Smtp:EnableSsl"])
        };

        var mailMessage = new MailMessage(
            from: _configuration["Smtp:FromEmail"],
            to: email,
            subject: subject,
            body: message);
        
        await client.SendMailAsync(mailMessage);
    }
}

在appsettings.json中配置SMTP信息:

{
  "Smtp": {
    "Host": "smtp.example.com",
    "Port": "587",
    "Username": "your-email@example.com",
    "Password": "your-password",
    "EnableSsl": "true",
    "FromEmail": "notifications@your-app.com"
  }
}

内容的提问来源于stack exchange,提问作者Stephan Miller

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 19:23:23