Closing WCF connection - wcf

We are using WCF service
on the client side we are planning to explicitly close the connection
It seems there are more then one way of closing
Sample1:
In the finally block of the WCF service consumption use
if (client.State == CommunicationState.Faulted)
{
client.Abort();
}
client.Close();
Since if the service is in fault state we will not be able to call close()
Sample2:
using(ClientProxy proxy = new ClientProxy())
{
//call your service methods
}
in sample2 i am not sure what will happen if the service is in fault state, will it throw error closing the connection?

You have all the necessary information at hand - the resulting Best Practice to use and properly close/abort all your WCF client proxies would be:
YourClientProxy clientProxy = new YourClientProxy();
try
{
.. use your service
clientProxy.Close();
}
catch(FaultException)
{
clientProxy.Abort();
}
catch(CommunicationException)
{
clientProxy.Abort();
}
catch (TimeoutException)
{
clientProxy.Abort();
}
Catching the FaultException handles all cases when the service responsded with an error condition (and thus your channel is in a faulted state), and CommunicationException will handle all other communication-related exceptions that can occur, like network connectivity dropping etc.
The approach with the using() block won't work, since if an exception happens at the end of the block, when the Dispose() method calls the Close() method on the client proxy, you have no way to catching and handling that.

The 2nd sample using the "using" block is incorrect. The using block ensures that the Dispose method is called on the proxy object. The Dispose method in turn calls the Close method which will (try to) connect to the service which will throw an exception when the communication state is faulted. So your feelings/hunch are absolutely right. It would be nice if the proxy Dispose method used the code from your first sample but it doesn't so don't use the using block :)

In Juval Lowy's Excellent Programming WCF book he recommends:
try
{
ClientProxy clientProxy = new ClientProxy();
clientProxy.SomeMethod();
clientProxy.Close();
}
catch
{
proxy.Abort();
}

Use sample 1
Here is a good article on why you should not use using:
http://msdn.microsoft.com/en-us/library/aa355056.aspx

Related

Close and Abort in custom service channel

My client is using one WCF service which is throwing an exception
(EXCEPTION: The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state).
All subsequent calls throwing an same exception.
I read on internet that client need to close()/Abort() channel, this will solve the problem. is it completely right?
Also I am using customer serviceChannel factory provided by service developers. When I create channel it does not show the close and abort methods. So how do I get these close and abort methods when I create custom service channel instance on client side?
Assuming that you have a proxy instance that implements the IClientChannel interface, here is a way (hopefully the right way) to use it.
IClientChannel clientChannel = (IClientChannel)proxy;
bool success = false;
try
{
// do something with the proxy
clientChannel.Close();
success = true;
}
finally
{
if (!success)
{
clientChannel.Abort();
}
}
You may also want to check this. You can wrap your operations using a shared class or function.

Do I need to Close and/or Dispose callback channels acquired through OperationContext.Current.GetCallbackChannel?

I'm using OperationContext.Current.GetCallbackChannel to get a channel to the client that called a WCF service operation.
Do I need to worry about closing / disposing these callback channels or is this taken care of by the framework?
Well, I just tried it myself and it turns out that if you Close & Dispose the callback channel (after casting to IClientChannel) the entire Service channel becomes useless and when called throws a ProtocolException saying:
"This channel can no longer be used to send messages as the output session was auto-closed due to a server-initiated shutdown. Either disable auto-close by setting the DispatchRuntime.AutomaticInputSessionShutdown to false, or consider modifying the shutdown protocol with the remote server."
I assume that this is an unwelcome consequence or side effect of attempting to close & dispose the callback channel, meaning that this should not be done.
In my opinion you should.
The callback mechanism supplies nothing like a higher-level protocol for managing the
connection between the service and the callback endpoint. It is up to the developer to
come up with some application-level protocol or a consistent pattern for managing the
lifecycle of the connection. The service can only call back to the client if the client-side channel is still open, which is typically achieved by not closing the proxy. Keeping the proxy open will also prevent the callback object from being garbage-collected. If the service maintains a reference on a callback endpoint and the client-side proxy is closed or the client application itself is gone, when the service invokes the callback it will get an ObjectDisposedException from the service channel. It is therefore preferable for the client to inform the service when it no longer wishes to receive callbacks or when the client application is shutting down. To that end, you can add an explicit Disconnect() method to the service contract. Since every method call carries the callback reference with it, in the Disconnect() method the service can remove the callback reference from its internal store.
here is an exemple :
class MyService : IServiceContract
{
static List<IServiceContractCallback> m_Callbacks = new List<IServiceContractCallback>();
public void Connect()
{
IServiceContractCallbackcallback = OperationContext.Current.GetCallbackChannel<IServiceContractCallback>();
if(m_Callbacks.Contains(callback) == false)
{
m_Callbacks.Add(callback);
}
}
public void Disconnect()
{
IServiceContractCallback callback = OperationContext.Current.GetCallbackChannel<IServiceContractCallback>();
if(m_Callbacks.Contains(callback))
{
m_Callbacks.Remove(callback);
}
else
{
throw new InvalidOperationException("Cannot find callback");
}
}
In such a way a client can inform the service that the callback is no longer needed. Does it answer your question ?

What WCF Exceptions should I retry on failure for? (such as the bogus 'xxx host did not receive a reply within 00:01:00')

I have a WCF client that has thrown this common error, just to be resolved with retrying the HTTP call to the server. For what it's worth this exception was not generated within 1 minute. It was generated in 3 seconds.
The request operation sent to xxxxxx
did not receive a reply within the
configured timeout (00:01:00). The
time allotted to this operation may
have been a portion of a longer
timeout. This may be because the
service is still processing the
operation or because the service was
unable to send a reply message. Please
consider increasing the operation
timeout (by casting the channel/proxy
to IContextChannel and setting the
OperationTimeout property) and ensure
that the service is able to connect to
the client
How are professionals handling these common WCF errors? What other bogus errors should I handle.
For example, I'm considering timing the WCF call and if that above (bogus) error is thrown in under 55 seconds, I retry the entire operation (using a while() loop). I believe I have to reset the entire channel, but I'm hoping you guys will tell me what's right to do.
What other
I make all of my WCF calls from a custom "using" statement which handles exceptions and potential retires. My code optionally allows me to pass a policy object to the statement so I can easily change the behavior, like if I don't want to retry on error.
The gist of the code is as follows:
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ProxyUsing<T>(ClientBase<T> proxy, Action action)
where T : class
{
try
{
proxy.Open();
using(OperationContextScope context = new OperationContextScope(proxy.InnerChannel))
{
//Add some headers here, or whatever you want
action();
}
}
catch(FaultException fe)
{
//Handle stuff here
}
finally
{
try
{
if(proxy != null
&& proxy.State != CommunicationState.Faulted)
{
proxy.Close();
}
else
{
proxy.Abort();
}
}
catch
{
if(proxy != null)
{
proxy.Abort();
}
}
}
}
You can then use the call like follows:
ProxyUsing<IMyService>(myService = GetServiceInstance(), () =>
{
myService.SomeMethod(...);
});
The NoInlining call probably isn't important for you. I need it because I have some custom logging code that logs the call stack after an exception, so it's important to preserve that method hierarchy in that case.

WCF FaultException - crashes App Pool when "re-throwing" from internal WCF call

I have a WCF service that's hosted in IIS, and uses a WS HTTP binding (the external service). This service ends up calling a second WCF service that's hosted in a Windows service, over Net TCP (the internal service). When the internal service throws a FaultException, the external service crashes rather than throwing it to the client. All the client sees is the connection being forcibly closed.
The internal service uses the Enterprise Library Validation Application Block to validate the incoming messages. When validation errors occur, the service throws a FaultException<ValidationFault>.
Both the internal and external service have a [FaultContract(typeof(ValidationFault)] attribute in the service contract. If I change the external service to just immediately throw a new FaultException<ValidaitonFault>, this gets back to the client fine. I can catch the exception from the internal service in the external service, but if I try to re-throw it, or even wrap it in a new exception and throw that, the whole Application Pool in IIS crashses. I can't see anything useful in the event log, so I'm not sure exactly what the problem is.
The client object the external service uses to communicate with the internal service is definitely being closed and disposed of correctly. How can I get the internal service's faults to propagate out to the client?
updated:
Below is a simplified version of the external service code. I can catch the validation fault from the internal service call. If I throw a brand new FaultException<ValidationFault>, everything is fine. If I use the caught exception, the connection to the external client is broken. The only difference I can see is when debugging the service - trying to use the caught exception results in a message box appearing when exiting the method, which says
An unhandled exception of type
'System.ServiceModel.FaultException`1'
occurred in mscorlib.dll
This doesn't appear if I throw a brand new exception. Maybe the answer is to manually copy the details of the validation fault into a new object, but this seems crazy.
public class ExternalService : IExternalService
{
public ExternalResponse DoSomething(ExternalRequest)
{
try
{
var response = new ExternalResponse();
using (var internalClient = new InternalClient())
{
response.Data = internalClient.DoSomething().Data;
}
return response;
}
catch (FaultException<ValidationFault> fEx)
{
// throw fEx; <- crashes
// throw new FaultException<ValidationFault>(
// fEx.Detail as ValidationFault); <- crashses
throw new FaultException<ValidationFault>(
new ValidationFault(new List<ValidationDetail> {
new ValidationDetail("message", "key", "tag") }),
"fault message", new FaultCode("faultCode"))); // works fine!
}
}
}
I have almost the exact design as you and hit a similar issue (not sure about a crash, though!).
If I remember correctly, even though the ValidationFault is a common class when the Fault travels over the wire the type is specific to the WCF interface. I think this is because of the namespace qualifiers on the web services (but this was a while back so I could be mistaken).
It's not terribly elegant, but what I did was to manually re-throw the exceptions:
try
{
DoStuff();
}
catch (FaultException<ValidationFault> fe)
{
HandleFault(fe);
throw;
}
...
private void HandleFault(FaultException<ValidationFault> fe)
{
throw new FaultException<ValidationFault>(fe.Detail as ValidationFault);
}
Well, it works if I do this, but there must be a better way...
This only seems to be a problem for FaultException<ValidationFault>. I can re-throw FaultException and FaultException<SomethingElse> objects with no problems.
try
{
DoStuff();
}
catch (FaultException<ValidationFault> fe)
{
throw this.HandleFault(fe);
}
...
private FaultException<ValidationFault> HandleFault(
FaultException<ValidationFault> fex)
{
var validationDetails = new List<ValidationDetail>();
foreach (ValidationDetail detail in fex.Detail.Details)
{
validationDetails.Add(detail);
}
return new FaultException<ValidationFault>(
new ValidationFault(validationDetails));
}

WCF nested Callback

The backgound: I am trying to forward the server-side ApplyChangeFailed event that is fired by a Sync Services for ADO 1.0 DBServerSyncProvider to the client. All the code examples for Sync Services conflict resolution do not use WCF, and when the client connects to the server database directly, this problem does not exist. My DBServerSyncProvider is wrapped by a head-less WCF service, however, and I cannot show the user a dialog with the offending data for review.
So, the obvious solution seemed to be to convert the HTTP WCF service that Sync Services generated to TCP, make it a duplex connection, and define a callback handler on the client that receives the SyncConflict object and sets the Action property of the event.
When I did that, I got a runtime error (before the callback was attempted):
System.InvalidOperationException: This operation would deadlock because the
reply cannot be received until the current Message completes processing. If
you want to allow out-of-order message processing, specify ConcurrencyMode of
Reentrant or Multiple on CallbackBehaviorAttribute.
So I did what the message suggested and decorated both the service and the callback behavior with the Multiple attribute. Then the runtime error went away, but the call results in a "deadlock" and never returns. What do I do to get around this? Is it not possible to have a WCF service that calls back the client before the original service call returns?
Edit: I think this could be the explanation of the issue, but I am still not sure what the correct solution should be.
After updating the ConcurrencyMode have you tried firing the callback in a seperate thread?
This answer to another question has some example code that starts another thread and passes through the callback, you might be able to modify that design for your purpose?
By starting the sync agent in a separate thread on the client, the callback works just fine:
private int kickOffSyncInSeparateThread()
{
SyncRunner syncRunner = new SyncRunner();
Thread syncThread = new Thread(
new ThreadStart(syncRunner.RunSyncInThread));
try
{
syncThread.Start();
}
catch (ThreadStateException ex)
{
Console.WriteLine(ex);
return 1;
}
catch (ThreadInterruptedException ex)
{
Console.WriteLine(ex);
return 2;
}
return 0;
}
And this is my SyncRunner:
class SyncRunner
{
public void RunSyncInThread()
{
MysyncAgent = new MySyncAgent();
syncAgent.addUserIdParameter("56623239-d855-de11-8e97-0016cfe25fa3");
Microsoft.Synchronization.Data.SyncStatistics syncStats =
syncAgent.Synchronize();
}
}