views:

2264

answers:

5

My application is using the net.tcp WCF service with a callback channel. For some reason I'm not able to send callbacks on event. Here's what I'm doing (all code server-side):

On initialization:

OperationContext Context { get; protected set; }
...
Context = OperationContext.Current;

On event:

var callback = Context.GetCallbackChannel<IServiceCallbackContract>();
callback.SomeMethod();

This fails on SomeMethod() with following exception: {"Cannot access a disposed object.\r\nObject name: 'System.ServiceModel.Channels.ServiceChannel'."}

Apparently, something disposes callback channel, even though client still able to talk to server using direct (non-callback) channel. This is pretty weird. Which object am I supposed to hold on to in order to issue a callback? Is there a certain thread this must be running in?

+2  A: 

Configure Tracing and see what exception is faulting your channel.

JP Alioto
good idea... let me see what it shows
galets
+1  A: 

I was running into similar problems where my service would make an async call to the Business layer an then wait for an event to fire back on the service. Whenver the event fired the Callback context was lost. I have not delved into the details of why this is but i ended up implementing a workaround of essentially storing a reference to the currentcontext and firing off a seperate Thread to call the to call the business layer and once it is complete fire the callback with the reference i have stored.

1) Create new class that would contain both my input request and a refence to the callback eg.

public struct MyCallbackDetails {
     public MyCallbackDetails(IMyServiceCallback callback, RequestType request) : this() 
         Callback = callback;
         Request = request;
}

public IMyServiceCallback Callback { get; set; }

public RequestType request { get; set; }
}

2) Then i would fire off a seperate thread passing a MyCallbackDetails object instead of just the request:

public ResponseType MyServiceMethod(RequestType request) {
 //...Do Some Stuff
 //Create MyCallbackDetails object to store reference to the callback and keep channel open
 MyCallDetails callDetails = new MyCallDetails(OperationContext.Current.GetCallbackChannel<IMyServiceCallback>(), request);
 //Fire off a new thread to call the BL and do some work
 Thread processThread = new Thread(RunCallbackMethod);
 processThread.Start(callDetails);
}

3) And my RunCallbackMethod would make the BL call and respond with a callback.

void RunCallBackMethod(Object requestDetails)
{
 //Use callbackdetails to make BL calls
 MyCallbackDetails callDetails = (MyCallbackDetails)requestDetails;
 // Make BL call - all code under here is syncrhonous
 ResponseType response = BusinessLayer.BusinessMethod(callDetails.Request);
 //NB: If your responsetype is a business object you will need to convert it to a service object
 callDetails.Callback.SomeMethod(results);
}

NB: Yes i have now done away with having an event from my Business Layer fire back to the Service Layer however as i am firing off a seperate thread for the Business Layer it still runs asynchronously and acts the same as if i was calling the BL directly in an ASync manner and waiting for an event to notify its completion.

PS: Thanks to Rory for the idea and most of the code to implement this.

mundeep
A: 

Did you try to use OperationContext.Current directly instead of the instance variable Context?

Philippe
yea, it is null, since callback runs in another thread
galets
A: 

The issue has been resolved as my error. The callbacks worked as designed, except some were stale, which when called were throwing exceptions. Since I wasn't try/catching them, whole event was breaking on those stale callbacks :(.

Thanks to everyone who tried to answer my question.

galets
A: 

Hi galets,

I am facing the same problem. Can you please give more detail about the solution?

It would be more helpful to me and others.

I appreciate.

Thanks, Jigs

Jigs: my program keeps track of connections in a collection. When connection gets closed, under certain conditions, I wasn't removing a connection from collection as I was supposed to. Basically, connection was closed, but I still held up to object. I doubt your scenario is similar to mine, mine was purely a programming error
galets