I'm trying to program a client server based on the callback infrastructure provided by WCF but it isn't working asynchronously.
My client connects to the server calling a login method, where I save the clients callback channel by doing
MyCallback callback =
OperationContext.Current.GetCallbackChannel<MyNamespace.MyCallback>()
After that the server does some processing and uses the callback object to communicate with the client.
All this works, the problem resides on the fact that even though I've set the method in the OperationContract as IsOneWay=true, the server still hangs when doing the call to the client.
I've tested this by launching the server for debug in the Visual Studio, detaching it, launching the client, calling the above mentioned login method, putting a break point in the implemented callback method of the client, and making the server send a response to the client. The server stops doing what it's supposed to do, waiting for the response of the client.
Any help is appreciated.
The trick is, to call the callback asynchronously from the server. Look at this:
[OperationContract(IsOneWay = true, AsyncPattern = true)]
IAsyncResult BeginOnMessageReceived(LiveDataMessage message, AsyncCallback acb, object state);
void EndOnMessageReceived(IAsyncResult iar);
I think the sollution to your problem is to properly set the 'ConcurecyMode' and 'Instance ContextMode' attributes for your service. To do that you must decorate your service declaration with those attributes as shown in the exemple below:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class SubscriberService: ISubscriberServiceContract
{...}
InstanceContextMode.Single builds your service as a Singleton object so there is only one instance of your service running for all clients;
ConcurencyMode.Reentrant or ConcurencyMode.Multiple enables multithreaded work for the service instance. For 'Multiple' you must take care of thread syncronization in your service.
Did you try to set
[CallbackBehavior(UseSynchronizationContext = false)]
on the client side object implementing the callback interface ?
Related
I am currently developing a REST Service where one of the methods is a long running task (named CalculatePrimeOneWay). Its definition is
[OperationContract(IsOneWay = true)]
[WebInvoke(Method = "POST", UriTemplate = "primeoneway/{jobnumber}")]
void CalculatePrimeOneWay(string jobnumber, Prime prime);
As there is no callback capability with a REST Service, I thought about implementing a kind of polling method to obtain status information. This polling method is defined as
[OperationContract]
[WebGet(UriTemplate = "poll/{jobnumber}")]
Job GetJobStatus(string jobnumber);
I write status information into a MS SQL table.
I start my client and invoke the CalculatePrimeOneWay Method. Subsequent calls to GetJobStatus return a WebException with Protocol Error, Status Code 400 and Status Description Bad Request.
However, if CalculatePrimeOneWay is finished and I then invoke GetJobStatus, all works perfectly fine.
Why am I unable to call GetJobStatus while CalculatePrimeOneWay is still running?
What other solutions would be possible for my scenario of a long runnning task and a polling mechanism?
Thanks
The behaviour you're getting may be a result of one or both of two things:
You are running the service with per-session or singleton instancing
You are re-using the same client channel to make the polling call as you did to make the one-way call.
You should have the service configured to per-call instancing and make the polling call on a new client channel instance.
I have now explicitly defined the service PerCall. For each call from
the client I get a new HttpWebRequest object and after the call, I
close the web response object. The behaviour is still the same
OK try replacing
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
with
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
ConcurrencyMode = ConcurrencyMode.Multiple,
UseSynchronizationContext = false)]
I am using IIS Express out of my VisualStudio
OK - the reason you are getting this behaviour is because you're hosting using the Visual Studio which uses the cassini web server. This does not support concurrency when processing requests. See posts here and here.
Try hosting the service temporarily in a console app and this problem will be resolved.
i am implementing a wcf callback service following this tutorial.
The thing is that my callback method on the client side is never called.
public void NotifyClient(object sender, EventArgs args)
{
INotificationCallback callback = OperationContext.Current.GetCallbackChannel<INotificationCallback >();
callback.OnStepReached(((ModuleEventArgs)args).Step);
}
The callback is called on the server side but never reaches the client side. I don't know what went wrong, the only I've got is a TimeOutException after a while.
My callback on the server side is a System.Runtime.Remoting.Proxies._TransparentProxy.
I'd like to know if there is an easy way to debug this behavior.
If you have not already, you may want to consider enabling WCF tracing to ensure the server is really calling the client callback method (callbackInstance.OnCallback(); ).
For reference, the following link provides an overview of WCF Tracing:
http://msdn.microsoft.com/en-us/library/ms733025.aspx
The servicecontract and the callback contract should be one-way. The linked tutorial is missing that.
So, Update the operation contract to [OperationContract(IsOneWay = true)]
I develop WCF-service with duplex mode and use nettcpbinding. I use .NET 4.5. I have only one client and only one server and there is a lot of logic between its. The client always the first begins communication with the server. I want that server can call client functions outside WCF-service class. I try to use duplex mode for this purpose.
This is my WCF-service:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single)]
public class Service : IService
{
...
public IServiceCallback Callback
{
get
{
return OperationContext.Current.GetCallbackChannel<IServiceCallback>();
}
}
}
I have no problem when I call my callback within OperationContract functions of my service:
Callback.foo();
But when I try to call it outside class Service for example:
service = new Service();
service.Callback.foo();
I got NullReferenceException of OperationContext.Current. I found a lot of information about the similar problems on the SO and other resources but it can't help to decide my problem.
Are there any solutions of my issue or may be workarounds for calling of callback? At the moment I plan to create one more WCF-service for my purpose but I feel that this is bad solution. Thanks for attention.
OperationContext.Current has a meaning only when it runs from the same thread that handles the current client request. You did not specify where exactly you calls this from.
I am using two-ways WCF model.
WCF server can send a data (broadcast) to WCF clients using callback method. However server must wait clients to finish the this method. With a lot of clients, server must wait a lot time. Please help me how to fix this problem at server side so that server mustn't wait clients. Thanks.
Mark the callback method as oneway:
[ServiceContract]
interface IMyContract
{
[OperationContract(IsOneWay = true)]
void MyMethod()
}
I have a WCF service running inside a windows service on a remote machine.
In the WCF service's contract, I have a method that takes a long time to run set up as
[OperationContract(IsOneWay = true)]
void Update(myClass[] stuff);
Everything works fine, the method gets called, I can see what it needs to do start getting done.
The problem is when I go to close the instance of the WCF service in my code, it times out and I get:
The socket connection was aborted.
This could be caused by an error
processing your message or a receive
timeout being exceeded by the remote
host, or an underlying network
resource issue. Local socket timeout
was '00:02:00'.
I thought the one way contract allowed me to fire and move on. Is there something I am missing? If not are there workarounds for this?
The ServiceContract attribute on your service's interface definition defaults the SessionMode property to SessionMode.Allowed, i.e.,
[ServiceContract(SessionMode = SessionMode.Allowed)]
public interface IMyContract
{
[OperationContract(IsOneWay = true)]
void Update(myClass[] stuff);
}
According to Juval Lowy's Programming WCF Services,
...when the SessionMode property is
configured with SessionMode.Allowed,
it merely allows transport sessions,
but does not enforce it. The exact
resulting behavior is a product of the
service configuration and the binding
used.
Thus, if you are using the WSHttpBinding with security or reliable messaging, the NetTcpBinding, or the NetNamedPipeBinding, then the service will behave as a per-session service. This simply means that as long as the client proxy has not been closed, a session will still be in place between the service and the client. By closing the client proxy as suggested by Shiraz should fix this.
Juval's book also says this with regard to one-way operations:
If the number queued messages has
exceeded the queue's capacity, then
the client will block, even when
issuing a one-way call. However, one
the call is queued, the client is
unblocked and can continue executing,
while the service processes the
operation in the background.
So while one-way operations do allow for fire-and-forget operation, you can still run into cases where your client may block.
Your "Update" is a method on the service.
When you open the wcf client, a connection to the service remains open until you call Close (or Abort).
You are probably not calling close, and it is therefore remaining open until it timesout.