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.
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've looked at a bunch of threads like Detect if wcf service is activated but these solutions require the client to proactively detect if the WCF service is running. But what if I am in the middle of a transaction and the WCF service goes down or the connection is lost for some reason? In my testing there is no exception thrown; either nothing happens at all or that twirly circle thing just keeps going round and round. I want the client to detect if the service/connection is lost and gracefully tell the user it's down. I have timeouts set in my code:
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
binding.OpenTimeout = TimeSpan.FromSeconds(15);
binding.SendTimeout = TimeSpan.FromSeconds(3000);
binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
this._engineChannel = new DuplexChannelFactory<IEngineApi>(this, binding, new EndpointAddress("net.pipe://localhost/Engine"));
But if I am in the middle of a transaction nothing actually happens; these timeouts don't seem to affect anything.
You can use one of the two approaches:
1
The two things I do are a telnet check to make sure the WCF process
has the socket open.
telnet host 8080 The second thing I do is always add an IsAlive method
to my WCF contract so that there is a simple method to call to check
that the service host is operating correctly.
public bool IsAlive() {
return true; }
Source: Pinging WCF Services
2
Use the Discovery/Announcement feature introduced in WCF 4.0
Discovery depends on the User Datagram Protocol (UDP). UDP is a connectionless protocol, and there is no direct connection required between the client and server. The client usages UDP to broadcast finding requests for any endpoint supporting a specified contract type. The discovery endpoints that support this contract will receive the request. The implementation of the discovery endpoint responds back to the client with the address of the service endpoints. Once the client determines the services, it invokes the service to set up call.
Simple usage example: http://www.codeproject.com/Articles/469549/WCF-Discovery
In the project I'm working on, we have several services implemented using WCF. The situation I'm facing is that some of the services need to know when a session ends, so that it can appropriately update the status of that client. Notifying the service when a client gracefully terminates (e.g. the user closes the application) is easy, however, there are cases where the application might crash, or the client machine might restart, in which case the client won't be able to notify the service about its status.
Initially, I was thinking about having a timer on the server side, which is triggered once a client connects, and changes the status of that client to "terminated" after, let's say, 1 minute. Now the client sends its status every 30 seconds to the service, and the service basically restarts its timer on every request from the client, which means it (hopefully) never changes the status of the client as long as the client is alive.
Even though this method is pretty reliable (not fully reliable; what if it takes the client more than 1 minute to send its status?) it's still not the best approach to solving this problem. Note that due to the original design of the system, I cannot implement a duplex service, which would probably make things a lot simpler. So my question is: Is there a way for the sevice to know when the session ends (i.e. the connection times out or the client closes the proxy)? I came accross this question: WCF: How to find out when a session is ending but the link on the answer seems to be broken.
Another thing that I'm worried about is; they way I'm currently creating my channel proxies is implemented like this:
internal static TResult ExecuteAndReturn<TProxy, TResult>(Func<TProxy, TResult> delegateToExecute)
{
string endpointUri = ServiceEndpoints.GetServiceEndpoint(typeof(TProxy));
var binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
TResult valueToReturn;
using (ChannelFactory<TProxy> factory = new ChannelFactory<TProxy>(binding,
new EndpointAddress(new Uri(endpointUri),
EndpointIdentity.CreateDnsIdentity(ServiceEndpoints.CertificateName))))
{
TProxy proxy = factory.CreateChannel();
valueToReturn = delegateToExecute(proxy);
}
return valueToReturn;
}
So the channel is closed immediately after the service call is made (since it's in a using block), is that, from a service standpoint, an indication that the session is terminated? If so, should I keep only one instance of each service during application runtime, by using a singleton maybe? I apologize if the questions seem a little vague, I figured there would be plenty of questions like these but wasn't able to find something similar.
Yes, closing the channel terminates the session, but if there is an error of some kind then you are subject to the timeout settings of the service, like this:
<binding name="tcpBinding" receiveTimeout="00:00:10" />
This introduces a ten second timeout if an error occurs.
Check out Managing WCF Session Lifetime with IsInitiating and IsTerminating
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 client / server type of application and I'd like the server object to create his own host. It looks something like this:
public class Server : IServer {
private ServiceHost m_Host;
public Server() {
m_Host = new ServiceHost(this);
m_Host.Open();
}
}
It seems to work fine when there are few message transfers occurring. But when it starts to speed up (my application requires that data is transfered every 50 ms), the server hangs and and the transfers stop after a few seconds without throwing an exception.
So, is it possible for an object to create his own host? Or do I really have to create it in the main() or do something else?
EDIT: I think the problem in this case is that I want the object that implements the service itself to create his own ServiceHost.
There's nothing really stopping any object to create an instance of ServiceHost.
The big question then is - can you guarantee that your object containing the service host is "alive"? Or was it garbage collected by any chance?
We use Windows (NT) Services to host our own custom service host classes to provide around-the-clock availability for WCF services - works just fine.
Marc
To be a WCF service it simply needs to implement the service contract. There's nothing to stop you adding more methods to open and close an instance of itself as a service.
Check out the ServiceBehaviorAttribute which allows you to specify how your service ... behaves. ;) The ConcurrencyMode property defined the support for multithreading and defaults to single threaded mode, and the InstanceContextMode defines if the service object is per session, per call or singleton.
Quote from ConcurrencyMode:
Setting ConcurrencyMode to Single instructs the system to restrict instances of the service to one thread of execution at a time, which frees you from dealing with threading issues. A value of Multiple means that service objects can be executed by multiple threads at any one time. In this case, you must ensure thread safety.
Quote from InstanceContextMode:
If the InstanceContextMode value is set to Single the result is that your service can only process one message at a time unless you also set the ConcurrencyMode value to Multiple.
We could really use some code examples of your service to further debug the behavior you're describing. For example, is your service object expensive to construct (assuming non singleton implementation), or do the operation slow down? Do you know where the time is spent, is it code, or could it as well be some firewall that limits connection? What protocol do you use?