In my client program, there is a WCF connection that is opened at startup and supposedly stays connected til shutdown. However, there is a chance that the server closes due to unforeseeable circumstances (imagine someone pulling the cable).
Since the client uses a lot of contract methods in a lot of places, I don't want to add a try/catch on every method call.
I've got 2 ideas for handling this issue:
Create a method that takes a delegate and executes the delegate inside a try/catch and returns an Exception in case of a known exception, or null else. The caller has to deal with nun-null results.
Listen to the Faulted event of the underlying CommunicationObject. But I don't see how I could handle the event except for displaying some error message and shutting down.
Are there some best practices for faulted WCF connection that exist for app lifetime?
If you do have both ends of the wire under your control - both the server and the client are .NET apps - you could think about this approach instead:
put all your service and data contracts into a shared assembly, that both the server and the client will use
create the ChannelFactory<IYourService> at startup time and cache it; since it needs to have access to the service contract, this only works if you can share the actual service contract between server and client. This operation is the expensive part of building the WCF client
ChannelFactory<IYourService> factory = new ChannelFactory<IYourService>();
create the actual communications channel between client and server each time you make a call, based on the ChannelFactory. This is pretty cheap and doesn't cost much time - and you can totally skip any thoughts about having to detect or deal with faulted channels.....
IYourService client = factory.CreateChannel();
client.CallYourServiceMethod();
Otherwise, what you basically need to do is wrap all service calls into a method, which will first check for a channel's faulted state, and if the client proxy is faulted, aborts the current one and re-creates a new one.
I wrote a blog post on exceptions in WCF that deals with how to handle this: http://jamescbender.com/bendersblog/Default.aspx
Related
I have a WPF client that makes calls to 2 WCF services.
One service is for querying only and one service is for commands (CQS pattern).
How should I make the calls to the commands service ?
I read somewhere that all the operations in the command service must be 'One-Way',
because they should not return any values. And that if something went wrong - the operation should throw a 'FaultException' to the client.
But if the commands are all One-Way - what do I do in the client ?
Say I have an 'AddProduct' window in the WPF client, and I enter information and press 'Save'.
I now call 'AddProduct(Product)' in the service, but :
Should it close the window ?
Should it wait for 10 seconds to see if there wasn't any FaultException ?
Should the operation not be 'One-Way' ? If so - should all operations in the command service return some type of generic 'Result' object with 'succeeded' or 'failed' ?
If section 3 is 'Yes' - should I call the service in a seperate thread and 'disable' all the controls on the window until I get a response back from the service ?
Thanks.
I would say option 3 is the way to go, but you probably do not need the generic Result object to communicate errors to the client. As you might know, exceptions are not serialized in the SOAP message so you won't get any of the usual .NET exceptions on the client side. On the other hand, you can still take advantage of SOAP Faults by catching FaultException on the client. Accordingly, if no exceptions were caught on the client, then everything went well.
For more information about fault exceptions and how you can use them to your benefit, take a look at:
Specifying and Handling Faults in Contracts and Services
I think using On-Way is fine but you have to be aware of some one-way call characteristic. If you care and can handle service exceptions then #4 is fine option.
One Way message - Once the client issues the call, WCF generates the request message but no correlated message will be ever returned to the client. Any exceptions thrown on the service side will not make it to the client.
One thing that you should have on is the reliability on your service so side so that you can insure that request has been delivered to the service.
When there is no transport session (basic or wsHttp binding) if exception occurs during the call of one-way operation client will be unaffected and it can continue sending calls on the same proxy instance.
If there is a presence of transport session - service side exception will fault the channel hence client will not be able to re-use proxy for sending more calls. This can give you an option to discover if something went wrong on the server side (but not what went wrong). Although, if service is using a FaultContracts you can still get into situation where client is unaware that something went wrong.
When service throws an exception listed in service side fault contract this will not fault the communication channel hence the client using one-way contract cannot detect communication failure.
In my client/server applications, I want a single duplex WCF channel to be available for communication with its server - sort of a background connection that isn't strictly necessary for the client application to run, but is desirable for reporting status to the server. I have a Ping() call and Echo() callback in the IServerContract and IClientContract respectively.
I implement class ServerProxy : System.ServiceModel.DuplexClientBase<IServerContract> with the pass-thru methods to base.InnerChannel.
If I create var proxy = new ServerProxy(...) in my client, I can just begin calling proxy.Ping() and WCF will automatically open the connection for the first call and perform the operation call immediately after. However, the first call always takes ~10 seconds because of channel initialization and authentication. (I'm using windows authentication, Message-based security, EncryptAndSign.) Subsequent calls are quicker.
I believe this 10 seconds is unavoidable, but there is usually time prior to the first call by the client to the server during which this initialization could happen. So rather than wait for the auto-open feature of DuplexClientBase, I open the channel early with a call to proxy.InnerDuplexChannel.Open(). (proxy.Open() throws an exception and this indirection seems to avoid it.)
Unfortunately, authenticating the client-to-server channel does not also authenticate the server-to-client callback channel. Instead, the first call by the server to the client ALSO requires ~10 seconds. Since I'm using netTcp binding I'm surprised by this, but I'll assume it is to be expected for now.
How can I open the callback channel preemptively as well?
I could require the client to call some Login() method instead, but I don't believe that WCF should strictly require an operation before user-code can be aware of a connected client!
Hint(?): I imagine that this code would have to go in a place in the WCF pipeline/lifecycle where the server has the opportunity to perform custom actions upon a client-connected event (and BEFORE any operation message is transmitted). This integration point has so far eluded me.
I have a service that uses callback operations to call back its client. Is there a away to notify the client when Service goes down? An exception is raised when client goes down during callback, but with service goes down the subscription is lost but client is not notified.
Does WCF support some heartbeat operation to check the state of the service?
Thanks
No, there's no such thing as a "check if this service call will succeed" method.
You need to call the service and be prepared to handle any exceptions that occur during the service call.
There's really no reliable or useful way to check for service availability. All that a heartbeat could check for is that you can call your service method right now - but a fraction of a second later, that connection might be gone (cable has been unplugged or severed, server has crashed - the possibilities of things going wrong are endless......), too. It cannot check if all the necessary background services and databases etc. are available.
So in reality, such a heartbeat check is quite pointless. Just call the service, hope for the best, and be prepared for the worst! Wrap your service calls in good exception handling, and get on with it.
Just trying to get my head around what can happen when things go wrong with WCF. I have an implementation of my service contract declared with an InstanceContextMode of PerSession...
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
The calls happen as follows:
My client calls the server and calls GetServerUTC() to return the current UTC time of the server. This is a one way call and the server will call the client back when its ready (trivial in this instance to simply return the current time!)
The server calls back to the client and for test purposes in the callback implementation on the client I throw an exception.
This goes unhandled in the client (for test purposes) and the client crashes and closes down.
On the server I handle the faulted event handler on the ICommunicationObject...
obj.Faulted += new EventHandler(EventService_Faulted);
Questions...
Will this kill off the session for the current connection on the server.
I presume I am free to do what I want in this method e.g. logging or something, but should I do anything specific here to terminate the session or will WCF handle this?
From a best practise view point what should I do when the callback is faulted? Does it mean "something has happened in your client" and thats the end of that or is there something I a missing here?
Additionally, are there any other faulted handlers I should be handling.
Ive done a lot of reading on WCF and it seems sort of vague on what to do when something goes wrong. At present I am implementing a State Machine on my client which will manage the connection and determine if a user action can happen dependant on if a connection exists to the server - or is this overkill.
Any tips would be really appreciated ;)
I found out that the session will time out as per the settings for your sessions. Strangely I noticed that once faulted the client is still able to call other methods on the same session.
Using techniques as hinted at in:
http://msdn.microsoft.com/en-us/library/system.servicemodel.servicecontractattribute.callbackcontract.aspx
I am implementing a ServerPush setup for my API to get realtime notifications from a server of events (no polling). Basically, the Server has a RegisterMe() and UnregisterMe() method and the client has a callback method called Announcement(string message) that, through the CallbackContract mechanisms in WCF, the server can call. This seems to work well.
Unfortunately, in this setup, if the Server were to crash or is otherwise unavailable, the Client won't know since it is only listening for messages. Silence on the line could mean no Announcements or it could mean that the server is not available.
Since my goal is to reduce polling rather than immediacy, I don't mind adding a void Ping() method on the Server alongside RegisterMe() and UnregisterMe() that merely exists to test connectivity of to the server. Periodically testing this method would, I believe, ensure that we're still connected (and also that no Announcements have been dropped by the transport, since this is TCP)
But is the Ping() method necessary or is this connectivity test otherwise available as part of WCF by default - like serverProxy.IsStillConnected() or something. As I understand it, the channel's State would only return Faulted or Closed AFTER a failed Ping(), but not instead of it.
2) From a broader perspective, is this callback approach solid? This is not for http or ajax - the number of connected clients will be few (tens of clients, max). Are there serious problems with this approach? As this seems to be a mild risk, how can I limit a slow/malicious client from blocking the server by not processing it's callback queue fast enough? Is there a kind of timeout specific to the callback that I can set without affecting other operations?
Your approach sounds reasonable, here are some links that may or may not help (they are not quite exactly related):
Detecting Client Death in WCF Duplex Contracts
http://tomasz.janczuk.org/2009/08/performance-of-http-polling-duplex.html
Having some health check built into your application protocol makes sense.
If you are worried about malicious clients, then add authorization.
The second link I shared above has a sample pub/sub server, you might be able to use this code. A couple things to watch out for -- consider pushing notifications via async calls or on a separate thread. And set the sendTimeout on the tcp binding.
HTH
I wrote a WCF application and encountered a similar problem. My server checked clients had not 'plug pulled' by periodically sending a ping to them. The actual send method (it was asynchronous being a server) had a timeout of 30 seconds. The client simply checked it received the data every 30 seconds, while the server would catch an exception if the timeout was reached.
Authorisation was required to connect to the server (by using the built-in feature of WCF that force the connecting person to call a particular method first) so from a malicious client perspective you could easily add code to check and ban their account if they do something suspicious, while disconnecting users who do not authenticate.
As the server I wrote was asynchronous, there wasn't any way to really block it. I guess that addresses your last point, as the asynchronous send method fires off the ping (and any other sending of data) and returns immediately. In the SendEnd method it would catch the timeout exception (sometimes multiple for the client) and disconnect them, without any blocking or freezing of the server.
Hope that helps.
You could use a publisher / subscriber service similar to the one suggested by Juval:
http://msdn.microsoft.com/en-us/magazine/cc163537.aspx
This would allow you to persist the subscribers if losing the server is a typical scenario. The publish method in this example also calls each subscribers on a separate thread, so a few dead subscribers will not block others...