在与 made 中的 AppDomain 相同的 class 中创建新的 AppDomain 调用方法

Creating new AppDomain calling method in same class as the AppDomain in made

我想从它自己的 AppDomain 中可能较长的 运行 线程下方开始,以防止网络服务器在回收期间中止它。它编译得很好,但是在运行时我得到了这个神秘的错误

Type is not resolved for member 'MyCore.MyWebService,MyCore, Version=5.0.0.0, Culture=neutral, PublicKeyToken=null'.

我如何找出没有解析的成员?

有没有更好的方法运行 MVC 业务服务层中长期存在的线程,不会被服务器回收机制中止?

代码如下:

namespace MyCore
{
  [Serializable]
  public class MyWebService : IMyWebService
  {
      AppDomain domain = AppDomain.CreateDomain("Domain");
      Thread.CurrentThread.Name = "MVCThread";
      domain.SetData("lDatabaseID", lDatabaseID);

      domain.DoCallBack(() =>
      {
        long lID = Convert.ToInt64(AppDomain.CurrentDomain.GetData("lDatabaseID"));
        Thread thread = new Thread(
        (() =>
        {
             PopulateTables(lID );
        }));
        thread.Name = "DomThread";
        thread.Start();
    });
  }
}

IIS 经过大量优化,可以非常快速地响应数百个同时发生的小请求,但这并不是您正在尝试的正确工具。您可以尝试解决这个问题,但从长远来看,您最好构建一个专为 long-running 任务设计的工具。下次出现此问题时,您就有了 pre-packaged 解决方案。

基本思想是创建一个外部应用程序来执行后台处理,并通过某种方式将任务传递给它并取回结果。我喜欢使用数据库进行通信,因为大多数需要基础处理的 Web 应用程序已经使用了数据库。添加一个 'tasks' table 和 {status, startedDateTime, finishedDateTime, parameters, etc},然后编写一个外部应用程序,定期查找新任务,完成它并更新数据库。您的网站可以轮询数据库的状态,或者您的应用程序可以进行 AJAX 调用以在作业完成时通知网站(网站中的一个小 iframe header 显示等待/已完成的任务如果有人会等待工作完成并且很容易完成,这可能很有用。

编辑:在执行上述操作之前,请先查看 HangFire(它在 IIS 中运行,作为 Windows 服务或控制台应用程序)。相同的原则,但 pre-packaged 解决方案。请注意,我还没有实现它,但它看起来不错。

虽然设置起来有点麻烦,但如果您可能有多个任务并需要它们快速响应,那么将此任务交给 Windows 服务是一个很好的方法。网上有很多教程可以帮助您创建 Windows 服务,例如 http://www.codeproject.com/Articles/106742/Creating-a-simple-Windows-Service 但您必须在此基础上构建一个简单的任务执行器,所以如果这是您的方式想去 我会寻找一个 pre-built 任务引擎(我没能很快找到一个,但我可能使用了错误的搜索词组)。

但如果 turn-around 时间不重要,那么这就太过分了,更好的方法可能是创建一个小型控制台应用程序,任务计划程序每五分钟启动一次。它会连接到数据库,执行任何等待的任务,然后再次关闭。这比 Windows 服务更容易调试和安装,并且实现了将任务执行移出 IIS 的相同目标。

请记住,您仍然需要检测和处理 Windows 关闭,这样您就不会得到 half-finished 孤立的作业 - 至少只需将该任务标记为已中止并干净地退出。

好吧,在处理了 Hangfire 之后,我终于让它在 .Net 4.0 和 MVC 3 中工作。必须安装 Common.Logging.Core 2.2.0,因为 NuGet 安装了错误的版本 (3.3.0)

在我的初始控制器中,我添加了以下内容

namespace Core.Controllers
{
...
  public void Configuration(IAppBuilder app)
  {
    app.UseHangfire(config =>
    {
        config.UseSqlServerStorage(ConnectionString.GetTVConnectionString());
        config.UseServer();
    });
  }
...
}

ConnectionString.GetTVConnectionString() 从配置文件中获取连接字符串。

在顶部我添加了以下内容

[assembly: OwinStartup(typeof(Core.Controllers.BaseController))]

在启动后台线程的代码中,我添加了以下内容,传入一个 long 而不是 class 并让作业从数据库加载 POCO class。

BackgroundJob.Enqueue(() => PopulateTables(lDatabaseID, JobCancellationToken.Null));

Enqueue() 函数 returns 一个作业 ID,如果需要,稍后可以通过 BackgroundJob.Delete(jobid) 函数使用它来取消作业。

在工作方法中我有这个

while (idxMin < max)
{
    try
    {
        cancellationToken.ThrowIfCancellationRequested();
        ....
    }
    catch (JobAbortedException jobEx)
    {
        ....
    }
}

使用依赖注入很重要,所以我的 class 添加了一个参数较少的构造函数,它重新读取连接字符串而不是将其传入。

public MyWebService ()
        : this(ConnectionString.GetTVConnectionString())
{
}

public MyWebService (string sConnStr)
{
    msConnStr = sConnStr;
}

之后似乎 运行 很好。许多表被添加到连接字符串中指定的数据库中。到目前为止,这些作业似乎在网络服务器上回收后仍然存在。