.NET 小案例 - 延迟发送邮件

92 阅读3分钟

一、需求

现在在写 API接口供其他项目调用,当该接口发生异常时,将会将错误信息发送到指定的邮箱中;

存在一个问题,当该接口发生异常,且其他程序使用for循环调用该接口,将会产生大量且重复的邮件信息;

现在想要对该种情况做出优化,当发送异常时,将会延迟10分钟再去发送,这期间所有的错误消息将会积累到一个set集合中

二、 核心代码

using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Text;

namespace muti_req_api.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
       // 注意,这里的变量要使用 static 修饰,保证全局唯一
        private static bool isFirst = true;
        private static Dictionary<string,HashSet<string>> dic = new Dictionary<string, HashSet<string>>();

        [HttpGet()]
        public object Get(string orderNumber,string message)
        {
            Console.WriteLine($"控制台输入orderNumber: {orderNumber},message: {message}");

            // 延迟执行时间,这里自定义
            int delayTime = 1000 * 20;
            string key = orderNumber;
            // 由于 10 分钟内,可能存在对同一个订单调用多次接口
            // 且 message 的值可能重复也可能不重复,这里做去重操作
            HashSet<string> value;
            if (dic.TryGetValue(key,out value))
            {
                Console.WriteLine($"存在key {key},追加新值{message}");
                value.Add(message);
            }
            else
            {
                Console.WriteLine($"不存在key {key},新建set集合,初始化值为{message}");
                value = new HashSet<string> {message };
            }
            dic[key] = value;

            // 如果是第一次进入或倒计时结束后访问,则开始倒计时 10 分钟,
            // 到时间后,将会将这10分钟内容发送到指定的邮箱中
            if (isFirst)
            {
                // 如果在10 分钟内,其他请求来访问,获取的都是false
                isFirst = false;
                var task = Task.Run(async delegate
                {
                    await Task.Delay(delayTime);

                    // 这里用控制台输出模拟来模拟发送邮件
                    foreach (KeyValuePair<string, HashSet<string>> kvp in dic)
                    {
                        Console.WriteLine("----------------------------");
                        Console.WriteLine("Order number: " + kvp.Key);
                        StringBuilder setMessage = new StringBuilder();
                        foreach (var item in kvp.Value)
                        {
                            setMessage.Append(item + ";");
                        }
                        Console.WriteLine("Error message: " + setMessage.ToString());
                    }

                    // 初始化设置
                    isFirst = true;
                    dic = new Dictionary<string, HashSet<string>>();
                });
            }

            return null;
        }
    }
}

三、演示案例

控制台输出如下:

控制台输入orderNumber: 000000000001,message: 111
不存在key 000000000001,新建set集合,初始化值为111
控制台输入orderNumber: 000000000001,message: 222
存在key 000000000001,追加新值222
控制台输入orderNumber: 000000000001,message: 333
存在key 000000000001,追加新值333
控制台输入orderNumber: 000000000001,message: 111
存在key 000000000001,追加新值111
控制台输入orderNumber: 000000000002,message: 111
不存在key 000000000002,新建set集合,初始化值为111
控制台输入orderNumber: 000000000002,message: 222
存在key 000000000002,追加新值222
控制台输入orderNumber: 000000000002,message: 333
存在key 000000000002,追加新值333
----------------------------
Order number: 000000000001
Error message: 111;222;333;
----------------------------
Order number: 000000000002
Error message: 111;222;333;

四、 参考

C# 集合(Collection) | 菜鸟教程 (runoob.com)

Dictionary<TKey,TValue>.TryGetValue(TKey, TValue) 方法 (System.Collections.Generic) | Microsoft Learn