使用 SSIS 调用 .Net 程序集:邮件框架






4.43/5 (3投票s)
本文演示了一个 SSIS 包的使用,该包有助于调用包含邮件组件的 .Net 程序集。
引言
有一个需求,需要自动向大约 25000 个用户发送邮件。在这种情况下,我们需要将详细信息从数据库服务器拉取到安装了 Windows 服务的 Web 服务器来发送邮件。这种方法在性能方面对我们的设计造成了很大的影响。因此,我们将设计转移到数据库服务器。这样就可以减少 Web 服务器的负载。现在将这个功能迁移到数据库服务器带来了一个问题,因为我们的邮件模板内容是 HTML 格式存储在平面文件中的,从 SQL Server 读取这个平面文件是个问题。一种方法是将这些邮件内容保存在数据库表中。但编辑这些邮件内容会涉及大量的测试和审查工作。因此,我们求助于 SSIS (Sql Server Integration services),它调用包含邮件组件的 .net 程序集。SSIS 包调用此类的 notification 方法,该方法反过来从数据库获取用户详细信息,并选择正确的邮件模板将邮件发送给收件人。此包在 SQL Server 2005 的 SQL Server Agent 下作为作业进行计划。这不仅解决了邮件内容管理的问题,还降低了 Web 服务器的负载。到目前为止,这已被证明是我们业务解决方案的一个很好的工作模型。
系统要求
邮件框架的特点
物理架构
逻辑架构
交互/序列图
邮件框架的实现
让我们开始实现邮件组件。创建邮件组件
此静态构造函数从 app.config 文件加载配置设置。由于此程序集在 GAC 中,因此引用其 app.config 存在问题。所以我们提供了物理路径。所有设置信息都存储在通用集合 Dictionary 中。所以需要通过键来获取所需的值。
static EmailServices()
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load("D:/EmailFramework/EmailFramework/EmailFramework/app.config");
XmlNodeList nodeList = xmlDocument.SelectNodes("configuration/appSettings/add");
int index = 0;
foreach (XmlNode node in nodeList) {
string key = node.Attributes.GetNamedItem("key").Value;
string value = node.Attributes.GetNamedItem("value").Value;
emailSettings.Add(key, value);
index += 1;
}
}
这会将邮件内容记录到文本文件中。
public static void GenerateTraceLog(string content)
{
System.IO.File.AppendAllText(emailSettings["EmailTraceLogPath"], content);
}
此块通过 smtp 服务器发送邮件。
public static void SendRegisterNotification(MailContent mailContent, Hashtable templateVars, string templateFileName)
{
string hostName = null;
System.Net.Mail.SmtpClient smtpClient = null;
int port = 0;
MailMessage mailMessage = new MailMessage();
try {
hostName = emailSettings["SMTPServerName"];
if (hostName == null | hostName == string.Empty) {
throw new Exception
("Invalid Configuration.
The configuration could not be found. Please contact support professionals.");
}
port = Convert.ToInt16(emailSettings["PortNumber"]);
if (port == 0) {
port = C_DEFAULT_PORT;
}
GenerateTraceLog("***EMAIL SENDING REPORT STARTED*****");
// Creating the instance of SMTP Client
smtpClient = new SmtpClient(hostName, port);
smtpClient.EnableSsl = false;
GenerateTraceLog("Mail From :" + mailContent.MailFrom);
if ((Convert.ToInt16(emailSettings["IsProduction"]) == 1)) {
//TO List
if ((mailContent.ToList == null)) {
GenerateTraceLog("Mail To :" + mailContent.MailTo);
mailMessage = new MailMessage(mailContent.MailFrom, mailContent.MailTo);
}
else {
foreach (string recipient in mailContent.ToList) {
GenerateTraceLog("To List :" + recipient);
mailMessage.To.Add(new MailAddress(recipient));
}
mailMessage.From = new MailAddress(mailContent.MailFrom);
}
//CC List
if ((mailContent.CCList == null)) {
GenerateTraceLog("CC :" + mailContent.MailCC);
if ((string.IsNullOrEmpty(mailContent.MailCC) == false)) {
mailMessage.CC.Add(mailContent.MailCC);
}
}
else {
foreach (string recipient in mailContent.CCList) {
GenerateTraceLog("CC List :" + recipient);
mailMessage.CC.Add(new MailAddress(recipient));
}
}
//BCC List
if ((mailContent.BCCList == null)) {
GenerateTraceLog("BCC :" + mailContent.MailBCC);
if ((string.IsNullOrEmpty(mailContent.MailBCC) == false)) {
mailMessage.Bcc.Add(mailContent.MailBCC);
}
}
else {
foreach (string recipient in mailContent.BCCList) {
GenerateTraceLog("BCC List :" + recipient);
mailMessage.Bcc.Add(new MailAddress(recipient));
}
}
}
else {
mailMessage = new MailMessage(mailContent.MailFrom, emailSettings["ToTestID"]);
}
//Subject
GenerateTraceLog("Subject :" + mailContent.Subject);
mailMessage.Subject = mailContent.Subject;
//Attachment
//This internal attachment through system
if ((string.IsNullOrEmpty(mailContent.AttachmentPath) == false)) {
GenerateTraceLog("AttachmentPath :" + mailContent.AttachmentPath);
Attachment mailAttachment = new Attachment(mailContent.AttachmentPath);
mailMessage.Attachments.Add(mailAttachment);
}
Attachment mailAttachmentEntity = null;
if ((mailContent.AttachmentList != null)) {
foreach (string attachmentPath in mailContent.AttachmentList) {
GenerateTraceLog("AttachmentPath :" + attachmentPath);
mailAttachmentEntity = new Attachment(attachmentPath);
mailMessage.Attachments.Add(mailAttachmentEntity);
}
}
//This is uploaded using external interface.
if ((string.IsNullOrEmpty(mailContent.AttachmentFileName) == false)) {
GenerateTraceLog("External Attachment :" + mailContent.AttachmentFileName);
Attachment mailAttachment =
new Attachment(mailContent.AttachmentFileContent, mailContent.AttachmentFileName);
mailMessage.Attachments.Add(mailAttachment);
}
mailMessage.IsBodyHtml = mailContent.IsBodyHTML;
mailMessage.Priority = (MailPriority)mailContent.MessagePriority;
//Parse Email Template
if ((string.IsNullOrEmpty(mailContent.MessageText) == true)) {
EmailTemplateParser.EmailTemplateParser.Parser parser = null;
parser =
new EmailTemplateParser.EmailTemplateParser.Parser(templateFileName, templateVars);
mailMessage.Body = parser.Parse();
GenerateTraceLog("Body:" + parser.Parse());
}
else {
GenerateTraceLog("Body ");
GenerateTraceLog("Body Content :" + mailContent.MessageText);
mailMessage.Body = mailContent.MessageText;
}
if ((Convert.ToString(emailSettings["IsSendMail"]) == "NO"))
{
GenerateTraceLog("*****EMAIL SENDING REPORT ENDED******");
mailMessage.Dispose();
return;
}
else {
smtpClient.Send(mailMessage);
mailMessage.Dispose();
}
GenerateTraceLog("*****EMAIL SENDING REPORT ENDED******");
}
catch (Exception ex) {
GenerateTraceLog(
ex.Message + "***ERROR SENDING EMAIL THROUGH APPLICATION *****");
}
}
创建 Notification Manager 类
此类包含所有方法,并且每个方法都指定给 SSIS 的脚本任务包,然后计划为作业。
public class NotificationManager
{
private static IDictionary configSettings = new Dictionary();
static NotificationManager()
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load("D:/EmailFramework/EmailFramework/EmailFramework/app.config");
XmlNodeList nodeList = xmlDocument.SelectNodes("configuration/appSettings/add");
int index = 0;
foreach (XmlNode node in nodeList)
{
string key = node.Attributes.GetNamedItem("key").Value;
string value = node.Attributes.GetNamedItem("value").Value;
configSettings.Add(key, value);
index += 1;
}
}
public static void NotifyDueForCreditPayment()
{
MailContent mailContent=new MailContent();
try
{
mailContent.MailTo = "xyz@addd.com";
mailContent.MailFrom = "xyz@addd.com";
mailContent.Subject = "THIS TEST MAILER";
//Body Content
Hashtable templatePlaceHolder = new Hashtable();
templatePlaceHolder.Add("To", "xyz");
templatePlaceHolder.Add("Credit_Card_Number",104562321373263 );
templatePlaceHolder.Add("Due_Date", DateTime.Now);
mailContent.IsBodyHTML = true;
mailContent.MessagePriority = 1;
mailContent.MessageText = string.Empty;
EmailServices.SendRegisterNotification
(mailContent, templatePlaceHolder, configSettings["ET_DueForCreditPayment"]);
}
catch
{
}
}
public static void NotifyCreditCardExpiry()
{
}
public static void NotifyApplicationForAddOnCard()
{
}
创建 SSIS - Dtsx 包:脚本任务
打开 Business Intelligence Studio 并创建一个新的 SSIS 包。将脚本任务拖到控制面板屏幕。
将脚本任务的 enable 属性设置为 true,然后双击任务块以打开脚本设置对话框。
单击 Design Script 打开 vbscript 编码部分。
注意
现在像截图所示那样为此包添加引用。
部署到生产环境
***EMAIL SENDING REPORT STARTED*****Mail From :xyz@xyz.comMail To :zzz@zzzz.comCC :BCC :Subject :THIS TEST MAILERBody:<html> <head> <style > p { font-family: Verdana; } </style > </head > <body > <p > <small >*** THIS IS AN AUTOGENERATED MAIL.PLEASE DO NOT REPLY TO THIS MESSAGE ***</small></p> <p> <small>xyz</small></p> <p> <small>Credit Card No. 104562321373263 has due date on 10/21/2008 5:08:22 PM . Please pay you bill before due date. </small> </p> <p> <small></small> <br> <small>Regards </small> <br> <small>ZCZC Bank</small> <br>
缺点
我设计的唯一问题是,app.config 被显式解析,因为它需要保留在 GAC 中。需要一位了解如何配置 GAC 中的程序集及其配置的人员的帮助。
参考
邮件模板解析器:作者 Alexandra Email Templates
结论
任何更正、批评和建议都非常欢迎。