调用回调方法时无法访问已处置的对象

时间:2017-07-27 12:05:46

标签: c# wcf duplex

我有双工TCP IP WCF服务。我目前正在进行单元测试。

在我的测试中,我设置了一个新服务器,创建了一个新的ChannelFactory,创建了InstanceContext并进行了调用。

然后我触发事件(它是服务器端的模拟),服务器在尝试联系客户端时给我这个例外:

  

抛出异常:mscorlib.dll中的“System.ObjectDisposedException”   附加信息:无法访问已处置的对象。

重要的一点是,只有当我连续运行所有测试时(顺序执行但执行相同)才会发生这种情况。

我的服务没有什么特别之处:

while($r = mysqli_fetch_assoc($sth)) {
    $rows['data'][] = array(
        "Date.UTC(" . str_replace('-', ',', $r['date_insert']) . ")",
        $r['valeur']
    );
}

以下是我目前正在进行单元测试的方式(不完全是,我已经在一些助手中提取了很多这些:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IMyServiceCallback))]
public interface IMyService{
    [OperationContract]
    void SomeVariousMethods();
} 

[ServiceContract]
public interface IMyServiceCallback
{
    [OperationContract]
    void HandleMessageFromServer(String message);
}


[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService{
    public MyService(ISomeServerComponent component){
        component.OnMessage += OnMessageReceived;
    }

    public void SomeVariousMethods(){
        //...
    }

    private void OnMessageReceived(object sender, EventArgs<String> e){
        IMyServiceCallback callback = OperationContext.Current.GetCallbackChannel<IMyServiceCallback>();
        callBack.HandleMessageFromServer(e.Data);//Crash here
    }
}

有趣的是,当我只运行[TestFixture] public class MyServiceTest:IMyServiceCallback{ private Mock<ISomeServerComponent> _mock; [OneTimeSetUp] public void Setup(){ //... Creating a mock for the ISomeServerComponent that the MyService receives } [Test] public void TestSomeVariousMethods(){ string serviceName = nameof(TestSomeVariousMethods); using(ServiceHost host = CreateServer(_mock.Object,serviceName)){ using (IMyService service = CreateClient(serviceName, this)){ service.SomeVariousMethods(); } } } [Test] public void TestCallback(){ string serviceName = nameof(TestSomeVariousMethods); using(ServiceHost host = CreateServer(_mock.Object,serviceName)){ using (IMyService service = CreateClient(serviceName, this)){ _mock.TriggerCallBack(); //Assert-that-the-flag-has-been-set } } } public void HandleMessageFromServer(String msg){ //Flag that this method has been called } private ServiceHost CreateServer(ISomeServerComponent mock, string serviceName){ UnityServiceHost serviceHost = new UnityServiceHost(m_container);//This extends ServiceHost to be able to inject some objects to my services NetTcpBinding binding = new NetTcpBinding(SecurityMode.None); binding.ReliableSession.Enabled = true; binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None; binding.MaxBufferPoolSize = Int64.MaxValue; binding.MaxBufferSize = Int32.MaxValue; binding.MaxReceivedMessageSize = Int32.MaxValue; Uri uri = new Uri(String.Format("net.tcp://{0}:{1}/{2}", IPAddress.Any, 9999, serviceName)); ServiceEndpoint serviceEndpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(IMyService)), binding, uri); serviceEndpoint.EndpointBehaviors.Add(new ProtoEndpointBehavior()); serviceHost.AddServiceEndpoint(serviceEndpoint); return serviceHost; } private IMyService CreateClient(string serviceName, IMyServiceCallback callback){ UnityServiceHost serviceHost = new UnityServiceHost(m_container);//This extends ServiceHost to be able to inject some objects to my services NetTcpBinding binding = new NetTcpBinding(SecurityMode.None); binding.ReliableSession.Enabled = true; binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None; binding.MaxBufferPoolSize = Int64.MaxValue; binding.MaxBufferSize = Int32.MaxValue; binding.MaxReceivedMessageSize = Int32.MaxValue; Uri uri = new Uri(String.Format("net.tcp://{0}:{1}/{2}", IPAddress.Loopback, 9999, serviceName)); InstanceContext context = new InstanceContext(callBack); DuplexChannelFactory channelFactory = new DuplexChannelFactory<T>(context, binding, new EndpointAddress(uri)); return channelFactory.CreateChannel() } } 测试时,所有这些都有效,但是如果我运行了该类的所有测试,它就会失败,就像第二次TestCallback一样没有正确地创建回调。

知道如何避免这种情况吗?

1 个答案:

答案 0 :(得分:2)

我终于找到了这个问题。我觉得有点愚蠢,但实际上,在Service实现中,我没有正确地从OnMessage取消注册,因此当事件被触发时,之前的服务实例正在尝试与已经关闭的客户端进行通信。