System.Threading.Timer异步-将计时器线程上的更新合并回到主线程

问题描述

我对线程技术还很陌生,所以如果这没有太大意义或者我遗漏了一些明显的东西,我会深表歉意。基本上,我在内存中有一个列表List<Patients>,其中包含4个条目。

public class PatientAreaController : Controller
{
    private List<Patient> patients = new List<Patient>()
    {
        new Patient { ID = 0,FamilyName = "Hill",Givenname = "Chris",LastSelectedDate = DateTime.Now  },new Patient { ID = 1,FamilyName = "Stephens",Givenname = "Sion",LastSelectedDate = DateTime.Now },new Patient { ID = 2,FamilyName = "Murray",Givenname = "Thomas",new Patient { ID = 3,FamilyName = "Dupre",Givenname = "Pierre",LastSelectedDate = DateTime.Now }
    };

然后,我有一个System.Threading.Timer上运行的async,它调用一种方法来更改所述列表。这样可以永远在后台运行。

    public ActionResult Index(string sortOrder)
    {
        Timer timer = new Timer(async (e) =>
        {
            await Task.Delay(10000);
            UpdatePatientsList();
        },null,10000);

        return View(patients);
    }

方法UpdatePatientsList()

    private void UpdatePatientsList()
    {

        switch (addOrRemovePatient)
        {
            case "Add":

                patients.Add(threadPatient);

                break;
            case "Remove":

                Random rnd = new Random();
                int randomId = rnd.Next(3);
                threadPatient = patients.Find(x => x.ID.Equals(randomId));

                patients.Remove(threadPatient);

                break;
            default:
                break;
        }

            if (addOrRemovePatient == "Remove")
                addOrRemovePatient = "Add";
            else
                addOrRemovePatient = "Remove";

    }

这个想法是每10秒钟调用一次此方法,该方法将从列表中删除一个项目,然后10秒钟后将其重新添加

然后,在客户端上,我有一个setInterval调用,返回到服务器以检索此列表。

    setInterval(function () {
        $("#dvPatientListResults").hide().load('@(Url.Action("GetFullAndPartialviewmodel","PatientArea",Request.Url.Scheme))').fadeIn('slow');
    },10000);

setInterval每10秒刷新一次表,并使用GetFullAndPartialviewmodel方法调用中的PatientList中的数据:

    public ActionResult GetFullAndPartialviewmodel()
    {
        return PartialView("PatientList",patients);
    }

但是,检索到的列表从不显示计时器进行的更新,并且始终返回4个项目。如果我单步执行代码,则可以清楚地看到计时器线程具有包含3个项目的列表,但是客户端调用始终返回完整列表4。

我想这是因为计时器位于单独的异步线程上,而这不是ajax回调所引用的内容。我最初的想法是,也许我需要以某种方式将计时器线程合并回主线程,以获取带有更新列表的主线程-但是,即使这件事我也无法弄清楚该如何做。有什么方法可以实现我想要的?

我随后建议SignalR值得研究-但是我对此有时间限制,没有真正的时间弄清楚SignalR(尽管我可以试一试!)

解决方法

因此,您的主要问题是ASP.NET控制器是临时的……这意味着它们是针对指向该控制器的每个请求而新建的。

针对您的问题的快速解决方案是:

private static List<Patient> patients = new List<Patient>()
{
    new Patient { ID = 0,FamilyName = "Hill",GivenName = "Chris",LastSelectedDate = DateTime.Now  },new Patient { ID = 1,FamilyName = "Stephens",GivenName = "Sion",LastSelectedDate = DateTime.Now },new Patient { ID = 2,FamilyName = "Murray",GivenName = "Thomas",new Patient { ID = 3,FamilyName = "Dupre",GivenName = "Pierre",LastSelectedDate = DateTime.Now }
};

将该列表设为static,无论创建多少个控制器,该列表将在应用程序的生存期内持续存在。

之前发生的事情是每次您发出请求时都会返回一个新列表。

一个旁注:您应该look in to IHostedServiceBackgroundService来做这些事情。在控制器内部执行此操作不太像“控制器”。