What is the proper life-cycle of a WCF service client proxy in Silverlight 3? - wcf

I'm finding mixed answers to my question out in the web. To elaborate on the question:
Should I instantiate a service client proxy once per asynchronous invocation, or once per Silverlight app?
Should I close the service client proxy explicitly (as I do in my ASP.NET MVC application calling WCF services synchronously)?
I've found plenty of bloggers and forum posters out contradicting each other. Can anyone point to any definitive sources or evidence to answer this once and for all?

I've been using Silverlight with WCF since V2 (working with V4 now), and here's what I've found. In general, it works very well to open one client and just use that one client for all communications. And if you're not using the DuplexHttBinding, it also works fine to do just the opposite, to open a new connection each time and then close it when you're done. And because of how Microsoft has architected the WCF client in Silverlight, you're not going to see much performance difference between keeping one client open all the time vs. creating a new client with each request. (But if you're creating a new client with each request, make darned sure you're closing it as well.)
Now, if you're using the DuplexHttBinding, i.e., if you want to call methods on the client from the server, it's of course important that you don't close the client with each request. That's just common sense. However, what none of the documentation tells you, but which I've found to be absolutely critical, is that if you're using the DuplexHttBinding, you should only ever have one instance of the client open at once. Otherwise, you're going to run into all sorts of nasty timeout problems that are going to be really, really hard to troubleshoot. Your life will be dramatically easier if you just have one connection.
The way that I've enforced this in my own code is to run all my connections through a single static DataConnectionManager class that throws an Assert if I try to open a second connection before closing the first. A few snippets from that class:
private static int clientsOpen;
public static int ClientsOpen
{
get
{
return clientsOpen;
}
set
{
clientsOpen = value;
Debug.Assert(clientsOpen <= 1, "Bad things seem to happen when there's more than one open client.");
}
}
public static RoomServiceClient GetRoomServiceClient()
{
ClientsCreated++;
ClientsOpen++;
Logger.LogDebugMessage("Clients created: {0}; Clients open: {1}", ClientsCreated, ClientsOpen);
return new RoomServiceClient(GetDuplexHttpBinding(), GetDuplexHttpEndpoint());
}
public static void TryClientClose(RoomServiceClient client, bool waitForPendingCalls, Action<Exception> callback)
{
if (client != null && client.State != CommunicationState.Closed)
{
client.CloseCompleted += (sender, e) =>
{
ClientsClosed++;
ClientsOpen--;
Logger.LogDebugMessage("Clients closed: {0}; Clients open: {1}", ClientsClosed, ClientsOpen);
if (e.Error != null)
{
Logger.LogDebugMessage(e.Error.Message);
client.Abort();
}
closingIntentionally = false;
if (callback != null)
{
callback(e.Error);
}
};
closingIntentionally = true;
if (waitForPendingCalls)
{
WaitForPendingCalls(() => client.CloseAsync());
}
else
{
client.CloseAsync();
}
}
else
{
if (callback != null)
{
callback(null);
}
}
}
The annoying part, of course, is if you only have one connection, you need to trap for when that connection closes unintentionally and try to reopen it. And then you need to reinitialize all the callbacks that your different classes were registered to handle. It's not really all that difficult, but it's annoying to make sure it's done right. And of course, automated testing of that part is difficult if not impossible . . .

You should open your client per call and close it immediately after. If you in doubt browse using IE to a SVC file and look at the example they have there.

WCF have configuration settings that tells it how long it should wait for a call to return, my thinking is that when it does not complete in the allowed time the AsyncClose will close it. Therefore call client.AsyncClose().

Related

WCF Service proxy - Both Close() and Abort functions getting called

I have the below code to call a WCF proxy:-
var client = new ServiceClientProxy();
try
{
var documents = client.GetDocuments();
client.Close();
if(documents.Length > 50)
{
throw new Exception("Too many Documents");
}
else if(documents.Length <10)
{
throw new Exception("Too many Documents");
}
else
{
return documents;
}
}
catch(exception ex)
{
client.Abort();
}
Here If the documents count that we get from service is more than 50 or less than 10, in that case we will be calling both Close() as well as the Abort functions on client.Is this expected way of calling WCF service proxy?
Anyone please suggest if there is some better way handling this.
Also is it a better approach to close the client connection immediately after the call or do we need to wait till we have completely used the response properties and close the connection at end?
Also is it a better approach to close the client connection
immediately after the call or do we need to wait till we have
completely used the response properties and close the connection at
end?
Depends on if you need to make subsequent calls to the service. If not then by all means close the connection.
Is this expected way of calling WCF service proxy? Anyone please
suggest if there is some better way handling this.
No. To handle a problem that is baked into WCF you could should actually be structured like this:
Documents documnts = null;
try
{
var client = new ServiceClientProxy();
documents = client.GetDocuments();
}
finally
{
try
{
if (client.State != CommunicationState.Closed)
client.Close();
}
catch
{
client.Abort();
};
};
if (documents.Length > 50)
{
throw new Exception("Too many Documents");
}
else if (documents.Length < 10)
{
throw new Exception("Too many Documents");
}
else
{
return documents;
}
If you want to truly understand the 'why' I would highly recommend reading this series of articles. They will clear up the Close / Abort portion of your problem.
http://blogs.msmvps.com/p3net/2014/02/02/a-smarter-wcf-service-client-part-1/
http://blogs.msmvps.com/p3net/2014/02/09/a-smarter-wcf-service-client-part-2/
http://blogs.msmvps.com/p3net/2014/02/23/a-smarter-wcf-service-client-part-3/
http://blogs.msmvps.com/p3net/2014/03/15/a-smarter-wcf-service-client-part-4/
Another other things I should point out with the code you've provided is exceptions should be exceptional.
Using exceptions for what I would considered to be business logic is usually not the right thing to do. Consider the approach where you return a structured result instead. Perhaps in your case it make sense though.
HTH

Memory leak using WCF GetCallbackChannel over named pipe

We have a simple wpf application that connects to a service running on the local machine. We use a named pipe for the connection and then register a callback so that later the service can send updates to the client.
The problem is that with each call of the callback we get a build up of memory in the client application.
This is how the client connects to the service.
const string url = "net.pipe://localhost/radal";
_channelFactory = new DuplexChannelFactory<IRadalService>(this, new NetNamedPipeBinding(),url);
and then in a threadpool thread we loop doing the following until we are connected
var service = _channelFactory.CreateChannel();
service.Register();
service.Register looks like this on the server side
public void Register()
{
_callback = OperationContext.Current.GetCallbackChannel<IRadalCallback>();
OperationContext.Current.Channel.Faulted += (sender, args) => Dispose();
OperationContext.Current.Channel.Closed += (sender, args) => Dispose();
}
This callback is stored and when new data arrives we invoke the following on the server side.
void Sensors_OnSensorReading(object sender, SensorReadingEventArgs e)
{
_callback.OnReadingReceived(e.SensorId, e.Count);
}
Where the parameters are an int and a double. On the client this is handled as follows.
public void OnReadingReceived(int sensorId, double count)
{
_events.Publish(new SensorReadingEvent(sensorId, count));
}
But we have found that commenting out _event.Publish... makes no difference to the memory usage. Does anyone see any logical reason why this might be leaking memory. We have used a profiler to track the problem to this point but cannot find what type of object is building up.
Well I can partially answer this now. The problem is partially caused by us trying to be clever and getting the connection to be opened on another thread and then passing it back to the main gui thread. The solution was to not use a thread but instead use a dispatch timer. It does have the downside that the initial data load is now on the GUI thread but we are not loading all that much anyway.
However this was not the entire solution (actually we don't have an entire solution). Once we moved over to a better profiler we found out that the objects building up were timeout handlers so we disabled that feature. That's OK for us as we are running against the localhost always but I can imagine for people working with remote services it would be an issue.

WCF Proxy Client taking time to create, any cache or singleton solution for it

we have more than dozon of wcf services and being called using TCP binding. There are a lots of calls to same wcf service at various places in code.
AdminServiceClient client = FactoryS.AdminServiceClient();// it takes significant time. and
client.GetSomeThing(param1);
client.Close();
i want to cache the client or produce it from singleton. so that i can save some time, Is it possible?
Thx
Yes, this is possible. You can make the proxy object visible to the entire application, or wrap it in a singleton class for neatness (my preferred option). However, if you are going to reuse a proxy for a service, you will have to handle channel faults.
First create your singleton class / cache / global variable that holds an instance of the proxy (or proxies) that you want to reuse.
When you create the proxy, you need to subscribe to the Faulted event on the inner channel
proxyInstance.InnerChannel.Faulted += new EventHandler(ProxyFaulted);
and then put some reconnect code inside the ProxyFaulted event handler. The Faulted event will fire if the service drops, or the connection times out because it was idle. The faulted event will only fire if you have reliableSession enabled on your binding in the config file (if unspecified this defaults to enabled on the netTcpBinding).
Edit: If you don't want to keep your proxy channel open all the time, you will have to test the state of the channel before every time you use it, and recreate the proxy if it is faulted. Once the channel has faulted there is no option but to create a new one.
Edit2: The only real difference in load between keeping the channel open and closing it every time is a keep-alive packet being sent to the service and acknowledged every so often (which is what is behind your channel fault event). With 100 users I don't think this will be a problem.
The other option is to put your proxy creation inside a using block where it will be closed / disposed at the end of the block (which is considered bad practice). Closing the channel after a call may result in your application hanging because the service is not yet finished processing. In fact, even if your call to the service was async or the service contract for the method was one-way, the channel close code will block until the service is finished.
Here is a simple singleton class that should have the bare bones of what you need:
public static class SingletonProxy
{
private CupidClientServiceClient proxyInstance = null;
public CupidClientServiceClient ProxyInstance
{
get
{
if (proxyInstance == null)
{
AttemptToConnect();
}
return this.proxyInstance;
}
}
private void ProxyChannelFaulted(object sender, EventArgs e)
{
bool connected = false;
while (!connected)
{
// you may want to put timer code around this, or
// other code to limit the number of retrys if
// the connection keeps failing
AttemptToConnect();
}
}
public bool AttemptToConnect()
{
// this whole process needs to be thread safe
lock (proxyInstance)
{
try
{
if (proxyInstance != null)
{
// deregister the event handler from the old instance
proxyInstance.InnerChannel.Faulted -= new EventHandler(ProxyChannelFaulted);
}
//(re)create the instance
proxyInstance = new CupidClientServiceClient();
// always open the connection
proxyInstance.Open();
// add the event handler for the new instance
// the client faulted is needed to be inserted here (after the open)
// because we don't want the service instance to keep faulting (throwing faulted event)
// as soon as the open function call.
proxyInstance.InnerChannel.Faulted += new EventHandler(ProxyChannelFaulted);
return true;
}
catch (EndpointNotFoundException)
{
// do something here (log, show user message etc.)
return false;
}
catch (TimeoutException)
{
// do something here (log, show user message etc.)
return false;
}
}
}
}
I hope that helps :)
In my experience, creating/closing the channel on a per call basis adds very little overhead. Take a look at this Stackoverflow question. It's not a Singleton question per se, but related to your issue. Typically you don't want to leave the channel open once you're finished with it.
I would encourage you to use a reusable ChannelFactory implementation if you're not already and see if you still are having performance problems.

WCF Service method synchronous/async

I have a problem with calling WCF Service methods with Silverlight 3.
private bool usr_OK = false;
clientService.CheckUserMailAsync(this.mailTF.Text);
if (usr_OK == true)
{ isValidationOK = true; }
else { isValidationOK = false; MessageBox.Show("User already exists.", "User registered succes!", MessageBoxButton.OK); }
CheckUserMail should change usr_OK parameter. However it runs in other thread and it does not change the usr_OK param before IF block begins. I've tried thread.join byt the application freezed and i do not know what to do else. Please help me...how can i wait for WCF method to return param usr_OK.
The most direct answer to your question: Don't block on WCF calls. They make it hard for a reason. There, quite likely, is no way to block if you even tried... but don't.
Elaboration: The mode of operation for Silverlight is Asyncronicity. This is something you have to get used to when you are developing in Silverlight. They make it really hard for you to block on anything.
This is a good thing, in my opinion. When you block on the result of something like a WCF service call, you are ultimately blocking the user thread. It does require some getting used to on the developer's part, but again... get used to it.
Lets say you have code that you want to go like this (Synchronous) :
var theResult = clientService.DoSomething(foo);
Process(theResult);
The way to re-write it would be like this (Asynchronous) :
clientService.DoSomethingCompleted += (sender, args) => Process(args.Result);
clientService.DoSomethingAsync(foo);
Taking it a step further, I like to abstract my services out as interfaces (so I can replace them when testing, or running in stand-alone mode while developing). I take that as an opportunity to create an interface that looks like this:
public interface IMyService
{
void DoSomething(string input, Action<string> whenComplete);
}
I implement the service like the async code above, and then when I call it, it is very clean and simple:
myService.DoSomething(foo, Process);
You will find that much of your system will morph into an asynchronous code base, but it might require you to re-adjust your expectations.
Bind the code that checks the usr_OK variable in the event handler for CheckUserMailCompletedEvent
clientService.CheckUserMailCompleted += new EventHandler<CheckUserMailCompletedEventArgs> (clientService_CheckUserMailCompleted);
clientService.CheckUserMailAsync(this.mailTF.Text);
void clientService_CheckUserMailCompleted(object sender, CheckUserMailCompletedEventArgs e) {
if (usr_OK == true) {
isValidationOK = true;
}
else {
isValidationOK = false;
MessageBox.Show("User already exists.", "User registered success!", MessageBoxButton.OK);
}
}

Should I check if already closed before calling Close() on a WCF Service?

Before I call Close() on my WCF service, should I check to see if it is not already closed?
i.e.
myWCFService.State != System.ServiceModel.CommunicationState.Closed
My code looks like:
MyServiceClient myWCFClient = null;
try
{
myWCFClient = new .....();
}
catch
{
}
finally
{
myWCFClient.Close();
}
A WCF client is disposable, so except for a few caveats you can use using:
using(MyClient client = new MyClient()) {
client.DoStuff();
// etc
}
But there is a big problem with this; the Dispose on the WCF client actually throws if it is faulted (losing the original exception). There is a good workaround, here, or I've blogged on this here.
Take a look at this question: What is the best workaround for the WCF client using block issue? Although it isn't word for word what you are looking for, I think his examples will help you out.