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

时间:2015-11-07 22:14:01

标签: c# appdomain

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

  

成员'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();
    });
  }
}

2 个答案:

答案 0 :(得分:1)

IIS经过大量优化,能够快速响应数百个小型并发请求,而且不适合您正在尝试的内容。您可以尝试解决这个问题,但从长远来看,您最好构建一个专为长时间运行的任务而设计的工具。然后,在下次出现此问题时,您将获得预先打包的解决方案。

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

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

虽然设置有点工作,但如果您有多个任务并且需要快速响应,那么将此任务交给Windows服务是一种很好的方法。网上有很多教程可以帮助你创建一个Windows服务,比如http://www.codeproject.com/Articles/106742/Creating-a-simple-Windows-Service,但是你必须建立一个简单的任务执行器,所以如果这就是你想要的方式我寻找一个预先构建的任务引擎(我找不到一个快速但我可能使用错误的搜索短语)。

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

请记住,您仍然必须检测并处理Windows关闭,以便您不会获得半完成的孤立作业 - 至少只是将该任务标记为已中止并完全退出。

答案 1 :(得分:0)

好吧,在使用了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而不是类,并让作业从db加载POCO类。

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

Enqueue()函数返回一个作业ID,以后可以通过BackgroundJob.Delete(jobid)函数在需要时用于取消作业。

在工作方法中,我有了这个

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

使用依赖注入很重要,所以我的类添加了一个参数less less,重新读取连接字符串而不是传入它。

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

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

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