我有一个.NET Core 3.1的应用程序。该应用程序应该发送电子邮件,并在电子邮件发送成功(或不成功)时记录到SQL Server数据库。
我已经将数据库注册在了 Startup.cs
:
services.AddDbContext<DataBaseAppContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
我已经在同一个文件中注册了我的电子邮件发件人,就像这样。
services.AddTransient<IEmailSender, EmailSender>();
这是... EmailSender
的实现。
public class EmailSender : IEmailSender
{
private readonly DataBaseAppContext _context;
public EmailSender(DataBaseAppContext context)
{
_context = context;
}
public Task SendEmailAsync(string subject, string message, string email)
{
return Execute(subject, message, email);
}
public Task Execute(string subject, string message, string email)
{
try
{
MailAddress fromAddress = new MailAddress(...);
SmtpClient smtp = new SmtpClient
{
Host = ...,
Port = ...,
...
};
MailMessage md = new MailMessage
{
From = ...,
IsBodyHtml = true,
Subject = subject,
Body = message,
To = ...
};
smtp.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
if (e.Cancelled)
{
//Want to use this statement as well, to log errors
}
if (e.Error != null)
{
//Want to use this statement as well, to log errors
}
else
{
try
{
//Object that should be saved in DB
EmailLogger emailLogger = new EmailLogger()
{
Email = email,
Subject = subject,
Message = message,
DateTime = DateTime.Now
};
_context.EmailLogger.Add(emailLogger);
_context.SaveChanges();
}
catch(Exception ex)
{
//Here I got an error - the *error below
}
}
}
return smtp.SendMailAsync(md);
}
catch (Exception e)
{
throw e;
}
}
}
每当我调用 EmailSender.SendEmailAsync
我得到了以下错误。
无法访问一个被处置的对象。这个错误的常见原因是处置了一个从依赖注入中解析出来的上下文,然后试图在应用程序的其他地方使用同一个上下文实例。如果你在上下文上调用Dispose(),或者在使用语句中包装上下文,就可能发生这种情况。如果你使用依赖注入,你应该让依赖注入容器来处理处置上下文实例。
我知道这是因为服务被注册为 AddTransient
和 _context
在回调发生时已经被处理了。
不知道有什么最好的办法解决这个问题,我试着修改了 AddTransient
到 AddScoped
或 AddSingleton
只是想看看会发生什么,但后来得到的错误在 Program.cs
.
你可以使用 SendMailAsync
方法?- https:/docs.microsoft.comen-usdotnetapisystem.net.mail.smtpclient.sendmailasync?view=netcore-3.1。 这个方法可以被等待,你的上下文不应该被容器处置。
我想如果你坚持使用回调方法,你可以注入工厂,它将在你需要的时候为你创建上下文(在回调中),你可以在回调方法中自己处置上下文。