我有一个自托管 wcf 双工回调服务的问题。我收到一条InvalidOperationException
消息:
此操作将死锁,因为在当前消息完成处理之前无法接收到回复。如果要允许无序消息处理,请在 CallbackBehaviorAttribute 上指定 Reentrant 或 Multiple 的 ConcurrencyMode。
这是我的服务行为:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = true)]
这是我的服务合同:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IClientCallback))]
[ServiceContract]
public interface IClientToService
{
[OperationContract(IsOneWay = false)]
LVSSStatus GetLvssStatus();
[OperationContract(IsOneWay = true)]
void PickSpecimen(long trackingNumber, int destCode);
[OperationContract(IsOneWay = true)]
void CancelCurrentPickTransaction();
}
这是我的回调接口:
public interface ILvssClientCallback
{
[OperationContract(IsOneWay = true)]
void SendClientCallback(LvssCallbackMessage callbackMessage);
[OperationContract(IsOneWay = false)]
List<SpecimenTemplateDescriptor> GetTemplateDescriptorList(DrawerLayout drawerLayout);
[OperationContract(IsOneWay = false)]
SpecimenTemplate SelectSpecimenTemplate(string templateName, int version);
[OperationContract]
void SpecimenStoredInContainer(string containerID, bool isValidRackID, int rackRow, int rackCol, int deckRow, int deckCol,
int drawerRow, int drawerCol, long trackingNumber, RobotErrors robotError);
[OperationContract]
void LvssRobotStatusChange(LVSSStatus status);
}
我知道这InvalidOperationException
是在客户端上调用回调操作时引起的,该服务已经被锁定以处理当前操作。因此,发生了死锁。
我尝试将我的 ConcurrencyMode 更改为多个,并将 UseSynchronizationContext 更改为 false。
我的服务仍然存在两个问题:
首先: 以下服务操作在GetLvssStatus()
快速调用时冻结我的客户端 wpf 应用程序(通过快速单击 UI 按钮)。该方法不是一种方式,而是从服务同步返回一个枚举类型给客户端。
[OperationContract(IsOneWay = false)]
LVSSStatus GetLvssStatus();
* 在这种情况下,是什么导致我的 wpf 应用程序冻结?*我可以做些什么来防止应用程序冻结?如果我使用 backgroundworker 线程作为异步调用,应用程序不会冻结。我真的需要这种方法来同步工作。
第二:当我将回调方法 LvssRobotStatusChange 分配给 时IsOneWay = true
,我得到一个 ObjectDisposedException:无法访问已处置的对象。对象名称:'System.ServiceModel.Channels.ServiceChannel'
。
[OperationContract(IsOneWay = true)]
void LvssRobotStatusChange(LVSSStatus status);
* 是什么导致了这个 ObjectDisposedException?*在这种情况下可以省略 IsOneWay 赋值吗?在这种情况下省略 IsOneWay 允许回调完成而没有任何异常。
* 这些问题可能是由于缺少线程安全代码造成的吗?
*如果是这样,使 ConcurrencyMode.Multiple 服务行为线程安全的最佳实践是什么?
非常感谢您对这些问题的任何帮助。
*第一次编辑关于创建我的双工频道的更多信息。我的 wpf 视图模型创建了一个代理对象,负责处理我的频道的创建。到目前为止,当服务尝试使用回调对象时,任何尝试在客户端的新线程上设置我的通道都会导致 ObjectDisposedException。
*第二次编辑我相信如果我可以使用 void 方法设置 IsOneWay = true 的操作合同,我的服务应该可以工作。在可重入并发的情况下,主通道线程应该让这些方法通过,而不管任何锁定。
这是我的回调接口:
public interface ILvssClientCallback
{
[OperationContract(IsOneWay = true)]
void SendClientCallback(LvssCallbackMessage callbackMessage);
[OperationContract]
List<SpecimenTemplateDescriptor> GetTemplateDescriptorList(DrawerLayout drawerLayout);
[OperationContract]
SpecimenTemplate SelectSpecimenTemplate(string templateName, int version);
[OperationContract(IsOneWay = true)]
void SpecimenStoredInContainer(string containerID, bool isValidRackID, int rackRow, int rackCol, int deckRow, int deckCol,
int drawerRow, int drawerCol, long trackingNumber, RobotErrors robotError);
[OperationContract(IsOneWay = true)]
void LvssRobotStatusChange(LVSSStatus status);
}
当我将方法 LvssRobotStatuschange 操作合同设置为 IsOneWay = true 时,我的缓存回调通道会引发 CommunicationObjectAbortedException。由于某种原因,我的回调属性被中止。
***什么会导致回调通道中止?