【发布时间】:2013-01-01 20:04:36
【问题描述】:
我有一个自托管 wcf 双工回调服务的问题。我收到带有消息的InvalidOperationException:
此操作会因为无法收到回复而死锁 直到当前消息完成处理。如果你想允许 乱序消息处理,指定 Reentrant 的 ConcurrencyMode 或 CallbackBehaviorAttribute 上的多个。
这是我的服务行为:
[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()(通过快速单击 UI 按钮)时,以下服务操作会冻结我的客户端 wpf 应用程序。该方法不是一种方式,而是从服务同步返回一个枚举类型给客户端。
[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。由于某种原因,我的回调属性被中止。
***什么会导致回调通道中止?
【问题讨论】:
-
你的应用托管是什么(服务或回调接口)?
-
我的应用程序正在托管回调接口。从我的 wpf 视图模型中,我创建了一个代理类,负责创建代理和双工通道。然后我在该类上调用 Connect() 来创建双工通道。代理类负责为我的客户端实现回调接口。在我的场景中,总会有一个服务和一个客户端。