Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.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# 在ASP.NET MVC中发送多种电子邮件类型的最佳方法_C#_Asp.net_Asp.net Mvc_Email_Architecture - Fatal编程技术网

C# 在ASP.NET MVC中发送多种电子邮件类型的最佳方法

C# 在ASP.NET MVC中发送多种电子邮件类型的最佳方法,c#,asp.net,asp.net-mvc,email,architecture,C#,Asp.net,Asp.net Mvc,Email,Architecture,你好,这里是苏的好朋友们 这更多的是一个设计问题,所以我将进入一个详细的示例 让我解释一下我们发送电子邮件的方式。 在应用程序的各个部分中,我们在通知表中为可能需要发送的不同类型的电子邮件创建条目。 例如,NotificationQueue表如下所示: NotificationQueueID OrderID EmailType Notes SentDatetime 1 461196 OrderU

你好,这里是苏的好朋友们

这更多的是一个设计问题,所以我将进入一个详细的示例

让我解释一下我们发送电子邮件的方式。 在应用程序的各个部分中,我们在
通知
表中为可能需要发送的不同类型的电子邮件创建条目。 例如,
NotificationQueue
表如下所示:

NotificationQueueID OrderID         EmailType           Notes       SentDatetime
1                   461196          OrderUpdate         SomeNote1   2020-09-01 14:45:13.153
2                   461194          OrderCancellation   SomeNote2   2020-09-01 14:45:13.153
使用DbContext中的属性访问它,如下所示:

public DbSet<NotificationQueue> NotificationQueues { get; set; }
我们有一个
EmailModel
类,它有一个
TicketsInNotificationQueue
属性,该属性包含我们拥有的任何电子邮件类型的列表。例如:在任何给定的时间,它都可以有
UpdatedTickets
canceledtickets
的列表。电子邮件类型说明
TicketsInNotificationQueue
属性中的票证类型

public class EmailModel
{
    public EmailModel(TypeOfEmail emailType, TicketsInNotificationQueue ticketsInNotificationQueue)
    {
        EmailType = emailType;
        TicketsInNotificationQueue = ticketsInNotificationQueue;
    }

    public TypeOfEmail EmailType { get; set; }
    public TicketsInNotificationQueue TicketsInNotificationQueue { get; set; }
}

public class TicketsInNotificationQueue
{
    public List<OrderCancellation> CancelledTickets { get; set; }
    public List<OrderUpdate> UpdatedTickets { get; set; }
}

public class OrderCancellation : CommonOrderInformation
{
    public string SomeOrderId { get; set; }
}

public class OrderUpdate: CommonOrderInformation
{
    public string SomeUpdateRelatedProperty { get; set; }
}

public class CommonOrderInformation
{
    public int NotificationQueueId { get; set; }
    public string ReferenceNumber { get; set; }
}
现在,我只需要获取这个列表,过滤掉我刚刚收到的票据类型的
通知ID
,然后继续处理它们。(我需要那些
notificationid
来设置通知发送后的
SentDatetime

var ticketsReceived=false;
notificationIds=新列表();
if(ticketsNotificationQueue.CancelledTickets!=null&&ticketsNotificationQueue.CancelledTickets.Any())
{
ticketsReceived=真;
NotificationId=ticketsNotificationQueue.Canceledtickets.Select(x=>x.NotificationQueueId.ToList();
}
else if(ticketsInNotificationQueue.UpdatedTickets!=null&&ticketsInNotificationQueue.UpdatedTickets.Any())
{
ticketsReceived=真;
NotificationId=ticketsNotificationQueue.UpdatedTickets.Select(x=>x.NotificationQueueId.ToList();
}
如果(收到票)
{
//继续发送电子邮件的过程,并设置“SentDateTime”`
}
我在这里看到的问题是,随着
电子邮件的类型越来越大,比如说
10-20
,检索票据并在以后过滤它们的方法需要变得越来越大,以至于在可读性和代码可管理性方面会失控,而我一点都不喜欢这些。我需要检查在获取中请求了什么
emailType
,以及收到了什么
emailType
(以获取
SentDateTime
更新的相应
notificationid
)。 那么,有没有其他方法来设计这个工作流(我甚至愿意使用反射之类的方法)以使它更易于管理和简洁呢


任何帮助都将不胜感激

您可以对现有系统和现有代码进行重大改进。为了得到一个更完整的答案,我将推荐一个不太昂贵的系统大修,然后继续你的确切答案

不同的行业标准方法 您已经有了正确的数据结构,这对于分布式持久队列来说是一个完美的工作,您不需要担心查询数据库的问题;相反,您只需将消息排队,并由一个处理器处理它们。既然您使用的是C#和.net,我强烈建议您检查一下。这实际上是一个大队列,您可以在其中发送消息(在您的情况下发送电子邮件请求),并且您可以根据消息类型将消息排队到服务总线中的不同通道

您还可以考虑创建一个现成的队列处理器。一旦你的电子邮件被发送,然后你可以写信给你的数据库,我们已经发送了这封电子邮件

所以,好的设计看起来像

  • 拥有分布式持久队列,直接向其发送电子邮件请求
  • 如果您想以一种节奏处理它们,请使用cron运行处理器,大多数行业解决方案都支持cron
  • 如果您想在它们进入队列时处理它们,请使用触发器
您可以根据您的场景丰富处理器,它看起来与订单有关,因此您可能需要处理取消订单后不发送已排队的电子邮件等情况

改进现有的 由于某些情况,您可能无法使用上面的解决方案,因此让我们开始吧

查看如何重构switch语句(因为您有一个带有
if
/
else if
s的语句)

您可以通过多态性实现这一点,只需创建一个基本邮件类型并重写子类中的行为。这样,您就可以将正确的队列与正确的电子邮件类型关联起来

例如:

var results=wait getsomeemail(OrderMail);
//返回从基本处理器继承的单独处理器,以不同方式实现。
var processor=ProcessorFactory.Create(OrderMail);
等待处理器。发送(结果);
还有一些改进
在这个循环中,您不必要地反复检查电子邮件类型,您应该将这些语句移到for上方,并检查传入的参数,因为您已经知道要查询的类型。

谢谢您的回答@Mavi-Domates

但这就是我最后所做的: 我修改了
EmailModel
TicketsInNotificationQueue
属性,这样就不用为不同类型的电子邮件提供不同类型的类,而只需要一种类型的公共类。这将避免我们按照原始问题中的说明,将这些检查放在获取逻辑中,以检查请求了哪种类型的电子邮件,同时也可以检索下一行的
通知ID
(在发送电子邮件后更新
SentDateTime

public class EmailModel
{
    public EmailModel(TypeOfEmail emailType, IEnumerable<CommonEmailModel> ticketsInNotificationQueue)
    {
        EmailType = emailType;
        TicketsInNotificationQueue = ticketsInNotificationQueue;
    }

    public TypeOfEmail EmailType { get; set; }
    public IEnumerable<CommonEmailModel> TicketsInNotificationQueue { get; set; }
}

public enum TypeOfEmail
{
    OrderCancellation,
    OrderUpdate
}
我只是通过以下方式获取记录:

var emailRecords = await CommonEmailModel.GetEmailBodyRecordsAsync(emailType);
只需将其作为
ticketsInNotificationQueue
参数传递给
EmailModel
构造函数即可。不需要做所有额外的检查来确定某些
电子邮件类型的记录是否正确<
    var ticketsReceived = false;
    notificationIds = new List<int>();

    if (ticketsInNotificationQueue.CancelledTickets != null && ticketsInNotificationQueue.CancelledTickets.Any())
    {
        ticketsReceived = true;
        notificationIds = ticketsInNotificationQueue.CancelledTickets.Select(x => x.NotificationQueueId).ToList();
    }
    else if (ticketsInNotificationQueue.UpdatedTickets != null && ticketsInNotificationQueue.UpdatedTickets.Any())
    {
        ticketsReceived = true;
        notificationIds = ticketsInNotificationQueue.UpdatedTickets.Select(x => x.NotificationQueueId).ToList();
    }

    if (ticketsReceived)
    {
        // Proceed with the process of sending the email, and setting the `SentDateTime`
    }
 foreach (var ntf in notifications)
        {
            if (ntf.EmailType == TypeOfEmail.OrderCancellation.ToString())
public class EmailModel
{
    public EmailModel(TypeOfEmail emailType, IEnumerable<CommonEmailModel> ticketsInNotificationQueue)
    {
        EmailType = emailType;
        TicketsInNotificationQueue = ticketsInNotificationQueue;
    }

    public TypeOfEmail EmailType { get; set; }
    public IEnumerable<CommonEmailModel> TicketsInNotificationQueue { get; set; }
}

public enum TypeOfEmail
{
    OrderCancellation,
    OrderUpdate
}
public class CommonEmailModel
{
    // Common to all email types. A lot of email types only need these first 4 properties
    public string EmailType { get; set; }
    public int NotificationQueueId { get; set; }
    public string OrderId { get; set; }
    public string Notes { get; set; }

    // Cancellation related
    public string SomeOrderId { get; set; }

    // Update related
    public string SomeUpdateRelatedProperty { get; set; }

    public static async Task<IEnumerable<CommonEmailModel>> GetEmailBodyRecordsAsync(TypeOfEmail emailType)
    {
        var emailModels = new List<CommonEmailModel>();
        var emailEntries = await EmailNotificationQueue.GetEmailEntriesAsync(emailType);
        var relevantOrdIds = emailEntries.Select(x => x.OrderID).Distinct().ToList();

        using (var dbCon = GetSomeDbContext())
        {
            orders = dbCon.Orders.Where(x => relevantOrdIds.Contains(x.OrdNumber)).ToList();
        }

        foreach (var record in emailEntries)
        {
            var emailModel = new CommonEmailModel
            {
                EmailType = emailType,
                NotificationQueueId = record.NotificationQueueID,
                OrderId = record.OrderID,
                Notes = record.Notes,
                SomeOrderId = orders?.FirstOrDefault(o => o.OrdNumber == record.OrderID)?.SomeOrderIdINeed,
                SomeUpdateRelatedProperty = orders?.FirstOrDefault(o => o.OrdNumber == record.OrderID)?.UpdateRelatedPropertyINeed
            };

            emailModels.Add(emailModel);
        }

        return emailModels;
    }
}
var emailRecords = await CommonEmailModel.GetEmailBodyRecordsAsync(emailType);
if (emailRecords.Any())
{
    var emailModel = new EmailModel(emailType, emailRecords);
}
if (emailWasSent)
{
    await UpdateNotificationSentTimeAsync(emailRecords.Select(t => t.NotificationQueueId));
}