我想在它自己的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();
});
}
}
答案 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;
}
之后它似乎运行得很好。许多表都添加到连接字符串中指定的数据库中。到目前为止,似乎这些工作在网络服务器上的回收中幸存下来。