Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 两次发送电子邮件_C#_Asp.net_Email_Locking_Queue - Fatal编程技术网

C# 两次发送电子邮件

C# 两次发送电子邮件,c#,asp.net,email,locking,queue,C#,Asp.net,Email,Locking,Queue,我们在数据库中有一个电子邮件队列表。它包含主题、HTML正文、收件人地址、发件人地址等 在Global.asax的每个间隔中,调用Process()函数来发送一定数量的电子邮件。代码如下: namespace v2.Email.Queue { public class Settings { // How often process() should be called in seconds public const int PROCESS_BATC

我们在数据库中有一个电子邮件队列表。它包含主题、HTML正文、收件人地址、发件人地址等

Global.asax
的每个间隔中,调用
Process()
函数来发送一定数量的电子邮件。代码如下:

namespace v2.Email.Queue
{
    public class Settings
    {
        // How often process() should be called in seconds
        public const int PROCESS_BATCH_EVERY_SECONDS = 1;

        // How many emails should be sent in each batch.  Consult SES send rates.
        public const int EMAILS_PER_BATCH = 20;
    }

    public class Functions
    {
        private static Object QueueLock = new Object();

        /// <summary>
        /// Process the queue
        /// </summary>
        public static void Process()
        {
            lock (QueueLock)
            {
                using (var db = new MainContext())
                {
                    var emails = db.v2EmailQueues.OrderBy(c => c.ID).Take(Settings.EMAILS_PER_BATCH);
                    foreach (var email in emails)
                    {
                        var sent = Amazon.Emailer.SendEmail(email.FromAddress, email.ToAddress, email.Subject,
                                                                email.HTML);
                        if (sent)
                            db.ExecuteCommand("DELETE FROM v2EmailQueue WHERE ID = " + email.ID);
                        else
                            db.ExecuteCommand("UPDATE v2EmailQueue Set FailCount = FailCount + 1 WHERE ID = " + email.ID);
                    }
                }
            }
        }
存在记录时返回:

发现

发现

找不到

如果在删除sql查询后使用此选项,它将返回:

发现

找不到

找不到


然而,仍然不确定这是否是问题的根本原因。我认为锁定肯定会阻止双重发送。

您遇到的问题是由于实体框架执行内部缓存的方式

为了提高性能,实体框架将缓存实体以避免数据库命中

当您在上执行某些操作时,实体框架将更新其缓存

实体框架不理解您的
“DELETE FROM…WHERE…”
语句应该使缓存无效,因为EF不是SQL引擎(并且不知道您编写的语句的含义)。因此,为了让EF完成它的工作,您应该使用EF理解的DbSet方法

for (var email in db.v2EmailQueues.OrderBy(c => c.ID).Take(Settings.EMAILS_PER_BATCH))
{
    // whatever your amazon code was...

    if (sent)
    {
        db.v2EmailQueues.Remove(email);
    }
    else
    {
        email.FailCount++;
    }
}

// this will update the database, and its internal cache.
db.SaveChanges(); 

另一方面,您应该尽可能地利用ORM,它不仅可以节省调试时间,还可以使代码更易于理解。

我不熟悉EF如何缓存数据,但可能是上下文包含EF不知道原始SQL语句可能会使缓存无效的缓存数据。另外,当队列中有电子邮件时,您的
任何
语句都可能是负面优化。我认为问题在于
process()
函数比
1sec
执行时间更长。这导致第一次发送的数据在第二次条件检查中未更新。@avi这就是锁定for@TomGullen当前位置观看
Amazon
非常有趣,我也在这里工作了一段时间。除此之外,我可以看看
QueueLock
包含的内容吗?@Matthew感谢您的关注,您对负面优化的看法是正确的,已经修改。QueueLock只是一个用于锁定静态方法的对象。非常感谢您的解释和回答。已转换为DbSet方法。
for (var email in db.v2EmailQueues.OrderBy(c => c.ID).Take(Settings.EMAILS_PER_BATCH))
{
    // whatever your amazon code was...

    if (sent)
    {
        db.v2EmailQueues.Remove(email);
    }
    else
    {
        email.FailCount++;
    }
}

// this will update the database, and its internal cache.
db.SaveChanges();