所以我有以下场景。我的 WCF 中有一个方法,客户端将在其中发送请求,然后 WCF 服务将执行一些后台处理并调用外部 Web 服务方法,并且该方法将立即响应确认(在后台处理完成之前) )。
我想到的方法是让我的 WCF 方法在生成线程进行后台处理后返回响应,并调用外部 Web 服务。流程是这样的:
主叫方向 INITIAL_CALL 发送请求
WCF启动一个调用PROCESS的线程
WCF 返回 true
PROCESS 调用 EXTERNALWS 并在 postResponse 中获取响应
postReponse 被记录到数据库
请参阅下面的示例代码:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service : IService
public bool INITIAL_CALL()
{
new Thread(()=>
{
PROCESS();
}).Start();
return true;
}
private void PROCESS()
{
//Do some background processing and create request for call below
var processRequest = "Request goes here";
using (var client = new EXTERNALWS.ResponseTypeClient())
{
var postResponse = client.POST(processRequest);
//Log postResponse to database
}
}
考虑到 PROCESS() 可能会运行很长时间,我只是想看看是否有更好的方法使用 WCF 和 IIS 来执行此操作?或者如果有任何我必须考虑的陷阱,即 IIS 应用程序池回收会破坏线程。
我已经找到了解决方案。我最终使用 Hangfire 进行所需的后台处理(https://www.hangfire.io/)。 Hangfire 似乎是专门为此而设计的。我按照他们主页上的文档在一个单独的 ASP MVC 应用程序中实现了它。我还将其配置为始终在 IIS 上运行。设置 Hangfire 来执行此操作的所有说明和示例代码都可以在此处找到https://docs.hangfire.io/en/latest/index.html。我必须更改流程(因为我没有像以前那样手动生成任何新线程),并且还在数据库中创建一个新表,以便 WCF 应用程序中的 INITIAL_CALL 将对所有长时间运行的作业进行排队(稍后将被拾取)并由 Hangfire 处决)。请记住,这与 Hangfire 的队列是分开的,Hangfire 将在预定义的时间间隔内检查此表,并将检查此数据库表,该表存储要调用的函数、其参数以及指示符(如果作业已由 Hangfire 拾取)是否 Hangfire(以避免此处描述的重入场景https://docs.hangfire.io/en/latest/best-practices.html)。有点额外的工作,但效果很好。
现在流程的工作方式如下:
主叫方向 INITIAL_CALL 发送请求
在 INITIAL_CALL 中,在新的数据库表中创建一个条目(这是作业 Hangfire 将按预定义的时间间隔检查的队列)。
INITIAL_CALL 返回 true
Hangfire 使用 PROCESS_JOBS 以预定义的时间间隔检查此数据库表(此时间间隔可以在 Hangfire 本身中定义)。
如果有排队项目,PROCESS_JOBS 会继续调用 EXTERNALWS 并在 postResponse 中获取响应。如果没有,它只是退出并且不做任何进一步的事情。
postReponse 被记录到数据库中。
请参阅下面更新的示例代码:
WCF申请
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service : IService
public bool INITIAL_CALL()
{
//Add job queue entry in database table to be picked up by Hangfire
return true;
}
Hangfire 应用程序
public void PROCESS_JOBS()
{
//Check in a predefined interval if there is a pending job in the queue.
//If there is continue with below, otherwise exit function.
//Do some background processing and create request for call below
var processRequest = "Request goes here";
using (var client = new EXTERNALWS.ResponseTypeClient())
{
var postResponse = client.POST(processRequest);
//Log postResponse to database
}
}