Cannot access a disposed object when calling callback method - c#

I've a Duplex TCP IP WCF service. I'm currently unit-testing it.
In everyone of my test, I setup a new server, create a new ChannelFactory, create the InstanceContext and do the call.
Then I trigger the event(it's a Mock on the server side), and the server give me this exception when it tries to reach the client:
Exception thrown: 'System.ObjectDisposedException' in mscorlib.dll
Additional information: Cannot access a disposed object.
Important point, this happens ONLY when I run all the tests in a row(sequentially executed but in the same execution).
There is nothing special about my service:
[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
}
}
And here is how I'm currently UnitTesting it(not exactly, I've a lot of this that has been extracted in some helpers:
[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()
}
}
Funny part is that all of this works when I'm ONLY running TestCallback test, but if I run all the test of the class, it fails, like if the second time, the InstanceContext was not creating properly the callback.
Any idea how to avoid this?

I finally found the issue. I feel a little bit stupid, but in fact, in the Service implementation, I was not unregistering from the OnMessage correctly, so when the event was triggered, the previous service instance were trying to communicate with the already closed client.

Related

Creating WCF services (NOT clients) by code and NOT by configuration

I have a large number of WCF services that are hosted on the IIS.
All these services have the same system.serviceModel configuration. They all have the same binding configuration, behavior configuration and the only thing that is different is the service's contract which is placed in a different custom configuration file for a different use.
Now, Every change I do in the system.serviceModel section needs to get done across all the services and that's annoying.
Since I create my WCF clients with custom C# code and update them to fit the services, I was thinking about somehow creating the service's system.serviceModel via C# code somehow (and every change will be a dll update or something).
So, I guess it's possible to create the service via code.
I also guess that it can be done with creating a custom ServiceHostFactory, but I couldn't really find the place I can choose the service's binding.
What's the best way to achieve something like this?
There is a code example from msdn that seems to fit your question: I'll copy it here for reference.
The binding
// Specify a base address for the service
String baseAddress = "http://localhost/CalculatorService";
// Create the binding to be used by the service.
BasicHttpBinding binding1 = new BasicHttpBinding();
and the endpoint
using(ServiceHost host = new ServiceHost(typeof(CalculatorService)))
{
host.AddServiceEndpoint(typeof(ICalculator),binding1, baseAddress);
Now, this is an other example with a ServiceFactory
public class ServiceHostFactory :
System.ServiceModel.Activation.ServiceHostFactory
{
protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var host = base.CreateServiceHost(serviceType, baseAddresses);
host.Description.Behaviors.Add(ServiceConfig.ServiceMetadataBehavior);
ServiceConfig.Configure((ServiceDebugBehavior)host.Description.Behaviors[typeof(ServiceDebugBehavior)]);
return host;
}
}
with a config done in code:
public static class ServiceConfig
{
public static Binding DefaultBinding
{
get
{
var binding = new BasicHttpBinding();
Configure(binding);
return binding;
}
}
public static void Configure(HttpBindingBase binding)
{
if (binding == null)
{
throw new ArgumentException("Argument 'binding' cannot be null. Cannot configure binding.");
}
binding.SendTimeout = new TimeSpan(0, 0, 30, 0); // 30 minute timeout
binding.MaxBufferSize = Int32.MaxValue;
binding.MaxBufferPoolSize = 2147483647;
binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.ReaderQuotas.MaxArrayLength = Int32.MaxValue;
binding.ReaderQuotas.MaxBytesPerRead = Int32.MaxValue;
binding.ReaderQuotas.MaxDepth = Int32.MaxValue;
binding.ReaderQuotas.MaxNameTableCharCount = Int32.MaxValue;
binding.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
}
public static ServiceMetadataBehavior ServiceMetadataBehavior
{
get
{
return new ServiceMetadataBehavior
{
HttpGetEnabled = true,
MetadataExporter = {PolicyVersion = PolicyVersion.Policy15}
};
}
}
public static ServiceDebugBehavior ServiceDebugBehavior
{
get
{
var smb = new ServiceDebugBehavior();
Configure(smb);
return smb;
}
}
public static void Configure(ServiceDebugBehavior behavior)
{
if (behavior == null)
{
throw new ArgumentException("Argument 'behavior' cannot be null. Cannot configure debug behavior.");
}
behavior.IncludeExceptionDetailInFaults = true;
}
}

Inject parameter at WCF service constructor using NInject

I've seen several examples on Internet setting up an NInject Factory modifying svc file. I don't have this svc file (or I don't know where's it).
I've a slight WCF service:
IService interface:
[ServiceContract]
public interface IFileSystemPluginService
{
[OperationContract]
void saveConfiguration(Configuration.Configuration configuration, string userId);
[OperationContract]
Configuration.Configuration getConfiguration(string userId);
}
IService implementation:
public class Service : IService
{
private IUserConfigurable userConfigurablePlugin;
public Service(IUserConfigurable configurablePlugin)
{
this.configurablePlugin = configurablePlugin;
}
}
In order to kick the service off I'm setting configuration up in code:
private void initializeWCFService()
{
string baseAdress = "xxx";
Uri baseAddressUri = new Uri(baseAdress);
this.serviceHost = new System.ServiceModel.ServiceHost(typeof(Service), baseAddressUri);
this.serviceHost.AddServiceEndpoint(
typeof(IService),
new System.ServiceModel.WSHttpBinding(),
string.Empty
);
System.ServiceModel.Description.ServiceMetadataBehavior smb = new System.ServiceModel.Description.ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri(baseAdress);
this.serviceHost.Description.Behaviors.Add(smb);
this.serviceHost.Open();
}
I need to inject a IUserConfigurable object in Service constructor.

writing a regression test for a wcf service with client

I would like to write an automated regression test whereby my service is started and I can assert that my client can retrieve some things from the service.
Private Blah proxy;
[SetUp]
public void SetUp()
{
proxy= new Blah();
}
[Test]
public void GetStuff()
{
var result = proxy.GetStuff();
Assert.NotNull(result);
}
This doesn't work because my service isn't running. How would I make start my service before the tests?
For integration/acceptance testing of WCF services I suggest you to use Self Hosted WCF Service. Examples you can find here:
Creating a Self Hosted WCF Service
Self Hosting Windows Communication Foundation Services
Create self-hosted service on fixture setup, and close it on fixture tear down:
EndpointAddress address = new EndpointAddress("http://localhost:8080/service1");
ServiceHost host;
IService1 service;
[TestFixtureSetUp]
public void FixtureSetUp()
{
var binding = new BasicHttpBinding();
host = new ServiceHost(typeof(Service1), address.Uri);
host.AddServiceEndpoint(typeof(IService1), binding, address.Uri);
host.Open();
}
[TestFixtureTearDown]
public void FixtureTearDown()
{
if (host == null)
return;
if (host.State == CommunicationState.Opened)
host.Close();
else if (host.State == CommunicationState.Faulted)
host.Abort();
}
With service hosted you can get service proxy:
var binding = new BasicHttpBinding();
ChannelFactory<IService1> factory =
new ChannelFactory<IService1>(binding, address);
service = factory.CreateChannel();
And your test will look like:
[Test]
public void ShouldReturnSomeStuff()
{
var result = service.GetStuff();
Assert.NotNull(result);
}

Host multiple contracts in one WCF service [duplicate]

This question already has answers here:
Run WCF ServiceHost with multiple contracts
(8 answers)
Closed 9 years ago.
Is it possible to host multiple service contracts in one WCF service? If so, how? I've been googling and some posts say you can do it (but not how) and others have said it's just not possible.
When I run the server, I get this error:
The contract name 'ConsoleAppWcfCommon.IBarService' could not be found
in the list of contracts implemented by the service
'ConsoleAppWcfServer.FooService'.
This is my server code:
static void Main(string[] args)
{
string serviceAddress = "net.tcp://localhost:8088/FooBarService";
// I'm stuck here as I have to pick *one* service
ServiceHost selfServiceHost = new ServiceHost(typeof(FooService));
// I can add both endpoints here, but this is what gives me the error.
selfServiceHost.AddServiceEndpoint(typeof(IFooService), new NetTcpBinding(), serviceAddress);
selfServiceHost.AddServiceEndpoint(typeof(IBarService), new NetTcpBinding(), serviceAddress);
selfServiceHost.Open();
Console.ReadLine();
selfServiceHost.Close();
}
And this is the client code:
static void Main(string[] args)
{
NetTcpBinding netTcpBinding = new NetTcpBinding();
EndpointAddress endpointAddress = new EndpointAddress("net.tcp://localhost:8088/FooBarService");
// Call IFooService
var channelFactoryFoo = new ChannelFactory<IFooService>(netTcpBinding, endpointAddress);
IFooService channelFoo = channelFactoryFoo.CreateChannel();
Debug.WriteLine(channelFoo.FooMethod1());
// Call IBarService
var channelFactoryBar = new ChannelFactory<IBarService>(netTcpBinding, endpointAddress);
IBarService channelBar = channelFactoryBar.CreateChannel();
Debug.WriteLine(channelBar.BarMethod1());
}
My goal is to let the client make a call to Foo (or Bar) and only see the methods available to each. In my real application, I have about 10 domain entities with about four operations on each. I'm trying not to have one interface with 40 methods in it. And I don't want to have to host 10 different WCF services to do this.
As marc_s pointed out, the answer was to have one service implementation class that implements both interfaces. Below is the full working code.
Server:
static void Main(string[] args)
{
string serviceAddress = "net.tcp://localhost:8088/FooBarService";
ServiceHost selfServiceHost = new ServiceHost(typeof(FooService));
// The endpoints need to share this binding.
var binding = new NetTcpBinding();
selfServiceHost.AddServiceEndpoint(typeof(IFooService), binding, serviceAddress);
selfServiceHost.AddServiceEndpoint(typeof(IBarService), binding, serviceAddress);
selfServiceHost.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press any key to terminate service.");
Console.WriteLine();
Console.ReadKey();
selfServiceHost.Close();
}
Client:
static void Main(string[] args)
{
NetTcpBinding netTcpBinding = new NetTcpBinding();
EndpointAddress endpointAddress = new EndpointAddress("net.tcp://localhost:8088/FooBarService");
// Call IFooService
var channelFactoryFoo = new ChannelFactory<IFooService>(netTcpBinding, endpointAddress);
IFooService channelFoo = channelFactoryFoo.CreateChannel();
Console.WriteLine(channelFoo.FooMethod1());
// Call IBarService
var channelFactoryBar = new ChannelFactory<IBarService>(netTcpBinding, endpointAddress);
IBarService channelBar = channelFactoryBar.CreateChannel();
Console.WriteLine(channelBar.BarMethod1());
Console.ReadKey();
}
Foo Contract:
[ServiceContract]
public interface IFooService
{
[OperationContract]
string FooMethod1();
[OperationContract]
string FooMethod2();
}
Bar Contract:
[ServiceContract]
public interface IBarService
{
[OperationContract]
string BarMethod1();
[OperationContract]
string BarMethod2();
}
Foo Service:
public class FooService : IFooService, IBarService
{
public string FooMethod1()
{
return "FooMethod1";
}
public string FooMethod2()
{
return "FooMethod2";
}
public string BarMethod1()
{
return "BarMethod1";
}
public string BarMethod2()
{
return "BarMethod2";
}
}

WCF problem after two async calls at once

I am trying to connect my application to azure with wcf role. Everything works fine until i call more than one wcf method at once. I think it is because threading. Exception is:
There was no endpoint listening at http://localhost:57579/Service1.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
I was searching how to add threading to wcf service and i found this:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
or
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall]
I tried to combine this properties but it doesnt work:(
this is my simple code:
Client:
public MainPage()
{
InitializeComponent();
service = new Service1Client();
service.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(getDataCompleted);
service.GetDataAsync(1);
service.GetDataAsync(2);
}
void getDataCompleted(object sender, GetDataCompletedEventArgs e)
{
if (e.Error != null)
{
}
else
{
this.textBlock1.Text = e.Result;
}
}
Server:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
I think the problem is that you're using the same client to do two operations at the same time. Have you tried spinning up two clients and asking each of them to perform the operation?
public MainPage()
{
InitializeComponent();
service1 = new Service1Client();
service1.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(getDataCompleted);
service1.GetDataAsync(1);
service2 = new Service1Client();
service2.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(getDataCompleted);
service2.GetDataAsync(2);
}
Note there are other ways to do the async calls that won't require as much pain with subscribing / unsubscribing the event handlers.

Categories

Resources