I've following service, defined as OneWay, because it's long running (a few minutes) and I can't wait when it finishes (it's used in ASP.NET application).
The problem is that if I call client.Dispose() after the service call, it blocks and after 60s timeout expires with exception.
How should I dispose the client in such scenario? Increasing the timeout of the service isn't solution, because I can't wait so long time with the HTTP request of the web page, where it's used.
[ServiceContract]
public interface IMyService
{
[OperationContract(IsOneWay = true)]
void BeginRun();
}
var client = new MyServiceClient();
client.BeginRun();
client.Close(); //This leads to time-out, how and when to call it?
Thanks for tips.
I would switch your binding to netMsmqBinding. Then from your client your one-way calls will be instantaneous.
Long duration sends over http are problematic at best and complex to manage. Sticking a queue in between will greatly simplify this operation.
From your signiture, it seems like you don't need any sort of response. In that case, on the service, when you recieve the BeginRun() call, execute the work on a non-WCF thread. This will free the channel & should allow you to immediately dispose the client.
Even though you've marked the OperationContract as IsOneWay, that doesn't mean WCF immediately releases the channel. A WCF service will not actually return from a one-way call until all of the data has been read from the wire. Depending on your service configuration, this could involve waiting for previous calls to complete (particularly w/ Single concurrency mode sessionful service configurations).
So, for several reasons it's often a good idea to actually execute service work on a separate thread from the WCF thread, which should improve throughput. Take a look at this article on MSDN for additional details.
You can try the IChannel approach. Or maybe try this, not sure this will work : http://msdn.microsoft.com/en-us/library/ms731177.aspx
You need to add try catch block inside your code and if there is an timeout exception it should abort the client.
try
{
work(client);
client.Close();
}
catch (Exception e)
{
client.Abort();
throw;
}
Related
I have a console app that I want to do a "fire-and-forget" call to a WCF service, and then close down without waiting for a response. It is just supposed to initiate a cleanup job. The job can take several hours to finish, so I don't want the console app to stay open and wait for it.
I have added "IsOneWay=true" to the methods in the contract, but the console app still waits for the task to finish before doing client.close() and exiting.
If I remove the client.Close() then the console app works the way I want, but I am not sure if the channel will remain open even though the console app is not running anymore?
Here is my console app code:
static void Main(string[] args)
{
Console.WriteLine("Starting Cleanup");
var client = new IntegrationWcfServiceClient(EndPointConfigurationName);
try
{
client.ExecuteCleanup();
//client.Close();
}
catch (Exception ex)
{
client.Abort();
WriteLineRed($"Couldn't start cleanup: {ex.Message}");
return;
}
WriteLineGreen("Cleanup started successfully");
}
And here is the operation contract code:
[OperationContract(IsOneWay = true)]
void ExecuteCleanup();
There are few things you need to consider while making oneway call.
From the book programming WCF services.
Ideally, when the client calls a one-way method, it should be blocked only for the
briefest moment required to dispatch the call. However, in reality, one-way calls do not equate to asynchronous calls. When one-way calls reach the service, they may not be
dispatched all at once but may instead be buffered on the service side to be dispatched
one at a time, according to the service’s configured concurrency mode behavior
Although one-way operations do not return values or exceptions from the service itself,
it’s wrong to perceive them as a one-way street or a “black hole” from which nothing
can come out. The client should still expect exceptions from a one-way call, and can
even deduce that the call failed on the service. When dispatching a one-way operation,
any error because of communication problems (such as a wrong address or the host
being unavailable) will throw an exception on the side of the client trying to invoke the
operation.
If I remove the client.Close() then the console app works the way I want, but I am not sure if the channel will remain open even though the console app is not running anymore?
A one-way call is not fire-and-forget in nature, since the client can discover
that something went wrong on the service during a one-way invocation.
Here you are tring to invoke invoke a one-way operation asynchronously and hence you are not able to close the connection or proxy.
[OperationContract(IsOneWay = true,AsyncPattern = true)]
IAsyncResult ExecuteCleanup(AsyncCallback callback,object asyncState);
client.ExecuteCleanup(,null,null);
Note:If you dont want to complicate things ,then make sure ExecuteCleanup is the last call in your service and later you can close which will not affect later operations.
Possible implementation How to properly close a client proxy (An existing connection was forcibly closed by the remote host)?
I have a WCF service set to PerCall
I would like to know how I can send a Start call from the client to start a long running process, and send a Cancel command to cancel it
My WCF service looks something like this
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1 : IService1
{
CancellationTokenSource cancelToken = new CancellationTokenSource();
public void Start()
{
var compute = Task.Factory.StartNew(StartLongRunningTask, cancelToken.Token);
}
public void Stop()
{
cancelToken.Cancel();
}
private void StartLongRunningTask()
{
//process here
}
}
I guess the problem here is that, each time a call comes to the server, it's treated as a new request.
So how should starting and cancelling a long running task in WCF be done?
EDIT: I'm hosting it as a windows service
I have a WCF service set to PerCall
... the problem here is that, each time a call comes to the server, it's treated as a new request.
Yup, that's exactly what you're telling it to do. If you can, just change to InstanceContextMode.PerSession; then you can do what you're trying to do (assuming you're self-hosting).
If you can't do this, then you'll have to develop a more complex solution like #PeterRitchie commented. First, your host: IIS is not designed to have long-running operations independent of requests, so I'll assume you're self-hosting. Next, you'll need a form of token (like a GUID) that will act as an identifier for a long-running operation. Your Start method will allocate a GUID and CancellationTokenSource and start the operation, and your Stop method will take a GUID and use that to look up the CancellationTokenSource and cancel the operation. You'll need a shared (static, threadsafe) dictionary to act as lookup.
If your host is IIS, then your solution gets more complex... :)
First, you'll need a backend that's not hosted in IIS. Common choices are an Azure worker role or a Win32 service. Next, you'll need a reliable communications mechanism: an Azure queue, MSMQ, WebSphere, etc. Then you can build your WCF-over-IIS service to have the Start method generate a GUID identifier and drop a message on the queue to start processing. The Stop method takes the GUID and drops a message on the queue to cancel processing. All other logic gets moved to the backend service.
From how you've asked, the client seems to be aware of the async nature of the request.
#StephenCleary and #PeterRitchie's points are excellent, but your first step is to re-do your service/contract to properly implement an async service and add the means of communicating back (to client) some information/handle to the long running operation.
The Framework contains several paradigms for asynchronous programming (already :-) )but when it comes to WCF, you kinda fall back to How to: Implement an Asynchronous Service Operation
That will provide some infrastructure, but not necessarily the ability to automatically cancel an operation.
Speaking strictly about the cancellation (as this is your question): you will have to extend whatever your solution ends up being for cancellation. At the minimum you need to add necessary logic to your service “worker” to monitor and honor the cancellation token.
Other considerations that you may expect to encounter: return result from cancellation; cancelling a task that has managed to complete (what of you updated the 1,000,000 records by the time the cancellation request came); exception handling (with task-based programming exceptions are not thrown, but bundled in the Task, or whatever other “vehicle” you use to describe the ongoing operation).
I need such scenario: client sends message to server, not waiting for response, and don't care, if message was send properly.
using(host.RemoteService client = new host.RemoteService())
{
client.Open();
cliend.SendMessage("msg");
}
in scenario when firewall is on, or there is no connection to the internet, client dies at "SendMessage". I mean program stops to respond. I wish program don't care about the result. I mean if there is no connection, i wish program to go further, omitting "SendMessage" or sth like that.
What should I do, is there any solution for non blocking method?
Try something like this in your service contract:
[OperationContract(IsOneWay=true)]
void Send(string message);
See the following link:
One Way Operation in WCF
Edit: OP was already using my suggested solution.
Suggested approaches to solve the issue - taken from MSDN (One-Way Services):
Clients Blocking with One-Way Operations
It is important to realize that while some one-way applications return
as soon as the outbound data is written to the network connection, in
several scenarios the implementation of a binding or of a service can
cause a WCF client to block using one-way operations. In WCF client
applications, the WCF client object does not return until the outbound
data has been written to the network connection. This is true for
all message exchange patterns, including one-way operations; this
means that any problem writing the data to the transport prevents the
client from returning. Depending upon the problem, the result could
be an exception or a delay in sending messages to the service.
You can mitigate some of this problem by inserting a buffer between
the client object and the client transport's send operation. For
example, using asynchronous calls or using an in-memory message
queue can enable the client object to return quickly. Both
approaches may increase functionality, but the size of the thread pool
and the message queue still enforce limits.
It is recommended, instead, that you examine the various controls on
the service as well as on the client, and then test your application
scenarios to determine the best configuration on either side. For
example, if the use of sessions is blocking the processing of messages
on your service, you can set the
System.ServiceModel.ServiceBehaviorAttribute.InstanceContextMode
property to PerCall so that each message can be processed by a
different service instance, and set the ConcurrencyMode to
Multiple in order to allow more than one thread to dispatch messages
at a time. Another approach is to increase the read quotas of the
service and client bindings.
Modify your attribute
[OperationContract(IsOneWay=true)]
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.
Do CommunicationExceptions and/or TimeoutExceptions need to be handled in the Service Implementation? (in addition to the client?). What happens when a client times out ? Does the service continue processing the message, or does an exception get thrown?
Thanks
-Vic
For example do, I need to do the following ??
public MyServiceImpl:IMyService
{
void DoSomething()
{
try{
//Do something
}
catch (Communication exception){}
catch (Timeout exception){}
}
}
}
Since you're not in a callback scenario, your service method won't even be called if there's a timeout (since it will be catched by the various dispatchers that get the message before your method does). So no need to catch these exceptions here.
If you're using a Stream as one of the parameters of your operation, things are a little different though, since you're likely to run into an exception while reading the stream if your client throws a hissy fit. But in that case you'd have to guard for exceptions anyway.
As per usual: it depends :-)
If you have per-call instancing, or one-way messages, then even if a bad thing (an exception) happens on the server, they'll be propagated to the client (or in one-way scenarios: just dropped), and you don't have to worry about them all that much.
HOWEVER: if you have a session scenario, where either your transport protocol (TCP/IP in the case of netTtcp binding) uses a transport session, or where your e.g. wsHttpBinding establishes an application session with the server, then you need to make absolutely sure on the server to catch all exceptions and handle them and return them only as SOAP faults.
If you don't, then the channel (the communication pipe between your client's proxy instance and the server instance) will be "faulted", e.g. unusable and the client proxy instance will need to be recreated.
Also, keep in mind that .NET exceptions are just that - a .NET specific thing. If your service will need to be interoperable and be called from e.g. Java, Ruby, PHP or other clients, you absolutely MUST catch all .NET exceptions on the server side and turn them into SOAP faults (which are the interoperable equivalent). You can do this by implementing the IErrorHandler interface on your server side.
Marc