尝试异步方法失败

本文关键字:失败 异步方法 | 更新日期: 2023-09-27 18:18:09

我有一个MVC3/。使用实体框架的。NET 4应用程序(4.3.1 Code First)

我已经将EF包装成这里描述的Repository/UnitOfWork模式…

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

通常,正如本文所解释的,当我需要创建一个新记录时,我一直这样做…

public ActionResult Create(Course course)
{
   unitOfWork.CourseRepository.Add(course);
   unitOfWork.Save();
   return RedirectToAction("Index");
}

然而,当需要的不仅仅是将记录保存到数据库中时,我将逻辑包装到我称之为IService的东西中。例如…

private ICourseService courseService;
public ActionResult Create(Course course)
{
   courseService.ProcessNewCourse(course);
   return RedirectToAction("Index");
}

在我的一个服务中,我有如下内容…

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…

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.   
    }
}

我的问题/问题

我随机得到错误:"已经有一个开放的数据阅读器与这个命令相关联,必须首先关闭。"在Notify()方法中。

  1. 是否与我试图跨线程共享unitOrWork和dbContext这一事实有关?

  2. 如果是这样,有人能解释一下为什么这是一个问题吗?

  3. 我应该给一个新的实例的unitOfWork的通知方法?

  4. 我是否使用正确的模式/类来异步调用方法?或者我应该使用....

    之类的东西吗?

    new System.Threading.Tasks.Task(() => {Notify(course);

    }) .Start ();

    我必须说我对异步、并行和并发这些术语感到非常困惑!!

  5. 任何文章链接(c# async白痴)将不胜感激!!

许多谢谢。

更新:

再深入一点,我找到了这个SO页面:https://stackoverflow.com/a/5491978/192999,上面写着…

"注意,EF上下文不是线程安全的,也就是说,你不能在多个线程中使用相同的上下文。"

…所以我是在尝试实现不可能的目标吗?这是否意味着我应该为我的新线程创建一个新的IUnitOfWork实例?

尝试异步方法失败

您可以创建一个轮询后台线程,它与您的主流程分开执行冗长的操作。这个线程可以扫描数据库寻找新项目(或标记为进程的项目)。这个解决方案非常简单,并确保即使应用程序崩溃(当轮询线程再次启动时,它将被拾取)也能完成任务。

你也可以使用一个同步队列,如果它不是可怕的,如果请求"丢失",在这种情况下,你的应用程序崩溃后,文件被请求和生成/发送之前。

有一件事几乎是肯定的——正如rikitikitik所说——你将需要使用一个新的工作单元,这意味着一个单独的事务。

你也可以看看最佳线程队列示例/最佳实践。