Reputation: 18482
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?
Upvotes: 2
Views: 9653
Reputation: 2875
I had a similar issue in my chat app. If I closed my app and then tried opening again I kept getting Cannot access a disposed object
when opening the channel.
Tracing backwards through the app I did the following to hit the root cause.
The problem was, and WCF experts do correct me if I am wrong, that the OperationContract was like so
[OperationContract(IsInitiating = false, IsTerminating = true)]
bool RemoveUser(Client user);
Setting IsTerminating = true
meant that the channel was closed before the service was processing the logoff method and so when it tried to callback it couldn't.
Setting IsTerminating = false
and closing the channel on the client side sorted the problem for me.
In my app the callback shouldn't of even be happening buts thats a seperate issue all together and not related. The main point is that if you have IsTerminating = True
on an operation then make sure you are not using a callback.
Upvotes: 0
Reputation: 18482
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.
Upvotes: 0
Reputation: 4051
Did you try to use OperationContext.Current directly instead of the instance variable Context?
Upvotes: 0
Reputation: 2747
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.
Upvotes: 2
Reputation: 45117
Configure Tracing and see what exception is faulting your channel.
Upvotes: 4