如果在与当前上下文相同的线程中调用WCF回调,则锁定
本文关键字:WCF 调用 回调 锁定 线程 上下文 如果 | 更新日期: 2023-09-27 18:11:35
我希望我能正确地表达出来。我有一个正在使用的WCF服务(双工通道通信),其中一个客户端向服务注册。服务的注册方法返回一个值。我希望被调用的服务注册方法的方法也调用回调方法,该方法将发送客户端注册通知(我有我的原因,在这里解释它只会混淆问题)。问题是客户端实现的回调必须在主应用程序线程中运行才能正常工作(主要是由于与第三方应用程序的集成)。服务注册方法调用也发生在同一个线程中,因此它有效地锁定,因为客户端正在寻找服务注册方法的返回,从而阻止回调方法能够运行。如果我让它调用所有上下文的所有回调功能除了刚刚注册的那个,它会工作得很好。但是如果我让它包含它,显然它会被锁住因为那个线程已经被锁住了。我可以将usesynsynchronationcontext的回调属性设置为false,但这意味着回调方法是在与主线程分开的线程上调用的,现在程序的其余部分将无法工作。如有任何帮助,我将不胜感激。
这就是注册方法(初稿…)
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
UseSynchronizationContext = false,
ConcurrencyMode = ConcurrencyMode.Multiple,
Namespace = "http://MyApp/Design/CADServiceTypeLibrary/2012/12")]
public class DTOTransactionService : IDTOTransactionService, IDisposable
{
//some more stuff
public CADManager RegisterCADManager(int processID, bool subscribeToMessages)
{
List<CADManager> cadMgrs = this.CADManagers;
bool registered = false;
//Create new CADManager mapped to process id
CADManager regCADManager = new CADManager(processID);
//Add to CADManagers List and subscribe to messages
if (regCADManager.IsInitialized)
{
cadMgrs.Add(regCADManager);
this.CADManagers = cadMgrs;
//Subscribe to callbacks
if (subscribeToMessages)
SubscribeCallBack(regCADManager.ID);
registered = true;
}
//Send registration change notification
RegistrationState state;
if (registered)
state = RegistrationState.Registered;
else
state = RegistrationState.RegistrationException;
foreach (CallBackSubscriber subscriber in this.CallBackSubscribers)
{
subscriber.CallBackProxy.CADManagerRegistrationNotification(regCADManager.ID, state);
}
return regCADManager;
}
}
我想我已经弄明白了。令我震惊的是,更深层次的原因是,由于对服务方法的调用期望返回值,并且由于回调将发生在与期望返回值的客户端方法相同的线程中,因此这可能是死锁条件的结果。然后,我决定尝试使用不同的线程调用服务中的回调方法,以绕过当前线程条件。换句话说,要绕过方法尚未从服务方法提供返回值的当前线程。它工作!这是正确的方法吗?我在这方面有足够的经验,所以如果别人的经验表明这是错误的处理方式,我洗耳恭听。
Thread notifyThread = new Thread(delegate()
{
foreach (CallBackSubscriber subscriber in this.CallBackSubscribers)
{
subscriber.CallBackProxy.CADManagerRegistrationNotification(regCADManager.ID, state);
}
});
更新:
是的,线程和死锁条件是问题所在,但是我最近发现更合适的修复方法是使用SynchronizationContext。要使用,请创建SynchronizationContext类型的属性或字段,然后在您希望使用SynchronizationContext. current捕获的上下文中将值赋给该字段/属性。然后,在服务调用的回调方法中使用Post()方法(通过SendOrPostCallback对象为其提供委托)。一个简短的例子:
private SynchronizationContext _appSyncContext = null;
private DTOCommunicationsService()
{
this.AppSyncContext = SynchronizationContext.Current;
//Sets up the service proxy, etc, etc
Open();
}
// Callback method
public void ClientSubscriptionNotification(string clientID, SubscriptionState subscriptionState)
{
SendOrPostCallback callback = delegate(object state)
{
object[] inputArgs = (object[])state;
string argClientID = (string)inputArgs[0];
SubscriptionState argSubState = (SubscriptionState)inputArgs[1];
//Do stuff with arguments
};
_appSyncContext.Post(callback, new object[] { clientID, subscriptionState });
}