【发布时间】:2015-02-03 13:11:20
【问题描述】:
当 smtpclient 发送失败时,我正在尝试发送带有少量日志记录的异步邮件。我正在使用 WebAPI 2.2 + EF6 + Autofac。错误说:
操作无法完成,因为 DbContext 已被释放。
我的主要代码:
public class SMTPEmailSender : IEmailSender
{
[...]
public void SendMailAsync(string templateKey, object model, string subject, MailAddress fromAddress, List<MailAddress> toAddresses,
List<MailAddress> ccAddresses = null, List<MailAddress> replyTo = null)
{
try
{
var htmlBody = GenerateHtmlBody(templateKey, model);
var client = new SmtpClient();
var message = new MailMessage
{
From = fromAddress,
Subject = subject,
IsBodyHtml = true,
Body = htmlBody
};
toAddresses.ForEach(m => message.To.Add(m));
if (ccAddresses != null) ccAddresses.ForEach(m => message.CC.Add(m));
if (replyTo != null) replyTo.ForEach(m => message.ReplyToList.Add(m));
client.SendCompleted += SendCompletedCallback;
client.SendAsync(message, message);
}
catch (Exception ex)
{
throw new Exception("Error: " + ex.Message + "<br/><br/>Inner Exception: " + ex.InnerException);
}
}
private void SendCompletedCallback(object s, AsyncCompletedEventArgs e)
{
SmtpClient callbackClient = s as SmtpClient;
MailMessage callbackMailMessage = e.UserState as MailMessage;
var regData = SenderMailLogModel(callbackMailMessage);
if (e.Cancelled)
{
try
{
callbackClient.Send(callbackMailMessage);
}
catch (Exception ex)
{
regData.EmailSenderStatus = EmailSenderStatuses.Cancelled;
regData.Exception = ex.Message;
}
}
if (e.Error != null)
{
regData.EmailSenderStatus = EmailSenderStatuses.Error;
regData.Exception = e.Error.ToString() + " in SendCompletedHandlerEvent";
}
_dbContext.EmailSenderLogs.Add(regData); //here fails
_dbContext.SaveChanges();
callbackClient.Dispose();
callbackMailMessage.Dispose();
}
[...]
}
我的 DataContext 是由 Autofac 注入的。我的容器构建器配置:
[...]
containerBuilder.RegisterType<DbEntities>().AsSelf().InstancePerRequest();
containerBuilder.RegisterType<SMTPEmailSender>().As<IEmailSender>().InstancePerRequest();
[...]
我对此有一个 hacky 解决方案,您可以创建一个新的 DbEntities 对象并使用它来代替 autofac 注入的对象。
【问题讨论】:
-
发生这种情况是因为您使用的是
InstancePerRequest。当Application_EndRequest与HttpContext发生时,这将处理DbContext,这发生在您的邮件发送之前。您的DbEntities生命周期需要某种混合作用域。不确定 AutoFac 是否提供此功能,但 SimpleInjector 提供。 simpleinjector.readthedocs.org/en/latest/lifetimes.html -
Autofac 提供混合生命周期。我不太清楚生命周期范围和处置是如何工作的。我只是想将我的项目迁移到 simpleinjector,它似乎更简单、更快。
-
SimpleInjector 很高兴与 IMO 合作,它是一个很棒的 IoC 工具。
-
虽然我不确定建议 OP 在这里切换工具是否合适,但我同意 @danludwig 关于 Simple Injector 的看法 :-)
-
问题已解决,但不是直接解决。由于 autofac 容器配置和 hangfire 的问题,我刚刚将 ioc 容器切换为简单的注入器。 ioc 很容易配置生命周期范围,并且操作对我来说花费的时间很少。
标签: entity-framework autofac smtpclient