我有一个使用实体框架(4.3.1 代码优先)的 MVC3/.NET 4 应用程序
如此处所述,我已将 EF 包装到 Repository/UnitOfWork 模式中……</p>
通常,正如文章中解释的那样,当我需要创建新记录时,我一直在这样做……</p>
public ActionResult Create(Course course)
{
unitOfWork.CourseRepository.Add(course);
unitOfWork.Save();
return RedirectToAction("Index");
}
但是,当需要的不仅仅是将记录保存到数据库时,我会将逻辑包装到我称为 IService 的内容中。比如……</p>
private ICourseService courseService;
public ActionResult Create(Course course)
{
courseService.ProcessNewCourse(course);
return RedirectToAction("Index");
}
在我的一项服务中,我有以下内容……</p>
public void ProcessNewCourse(Course course)
{
// Save the course to the database…
unitOfWork.CourseRepository.Add(course);
unitOfWork.Save();
// Generate a PDF that email some people about the new course being created, which requires more use of the unitOfWork…
var someInformation = unitOfWork.AnotherRepository.GetStuff();
var myPdfCreator = new PdfCreator();
IEnumerable<People> people = unitOfWork.PeopleRepository.GetAllThatWantNotifiying(course);
foreach(var person in people)
{
var message = “Hi ” + person.FullName;
var attachment = myPdfCreator.CreatePdf();
etc...
smtpClient.Send();
}
}
以上不是实际代码(我的应用程序与课程无关,我使用的是视图模型,并且我已将 PDF 创建和电子邮件消息分离到其他类中),但发生的事情的要点是以上!
我的问题是生成 PDF 并通过电子邮件发送它需要一些时间。用户只需要知道记录已保存到数据库中,所以我想我会将代码放在 unitOfWork.Save(); 进入异步方法。然后可以重定向用户,服务器可以愉快地花时间处理电子邮件、附件以及我需要它做的任何其他事情。
这就是我挣扎的地方。
我已经尝试了一些东西,当前是 ICourseService 中的以下内容……</p>
public class CourseService : ICourseService
{
private delegate void NotifyDelegate(Course course);
private NotifyDelegate notifyDelegate;
public CourseService()
{
notifyDelegate = new NotifyDelegate(this.Notify);
}
public void ProcessNewCourse(Course course)
{
// Save the course to the database…
unitOfWork.CourseRepository.Add(course);
unitOfWork.Save();
notifyDelegate.BeginInvoke(course);
}
private void Notify(Course course)
{
// All the stuff under unitOfWork.Save(); moved here.
}
}
我的问题/问题
我随机收到错误:“已经有一个打开的 DataReader 与此命令关联,必须先关闭。” 在 Notify() 方法中。
这与我试图共享 unitOrWork 并因此跨线程共享 dbContext 的事实有关吗?
如果是这样,有人可以解释为什么这是一个问题吗?
我应该给 Notify 方法一个新的 unitOfWork 实例吗?
我是否使用正确的模式/类来异步调用该方法?或者我应该使用类似的东西......
新 System.Threading.Tasks.Task(() => { Notify(course); }).Start();
我必须说我对异步、并行和并发这些术语感到非常困惑!
任何文章链接(c# async for idiots)将不胜感激!
非常感谢。
更新:
多一点挖掘让我进入了这个 SO 页面:https ://stackoverflow.com/a/5491978/192999它说......
“请注意,尽管 EF 上下文不是线程安全的,即您不能在多个线程中使用相同的上下文。”
...所以我是在努力实现不可能的目标吗?这是否意味着我应该为我的新线程创建一个新的 IUnitOfWork 实例?