I have a wrapper around a WCF service APIs
Class APIWrapper
{
private WCFClient _client;
//constructor opens a client connection
public APIWrapper()
{
_client = new WCFClient();
_client.open();
}
public API1()
{
_client.doSomething1();
}
public API2()
{
_client.doSomething2();
}
}
I want to ask:
Q1 will timeout exception occur? if this wrapper class instance exists for too long? (does the WCF connection by default keepalive? without setting that attribute in config)
for example, after a wrapper class is constructed, its API1 or API2 is called after 10mins, which is longer than the timeout value of this WCF connection.
Q2 Do I need explicitly close the connection, if so, should I do it in the destructor of the wrapper class like below?
~APIWrapper
{
if(_client !=null)
try{
_client.close(); }
catch(Exception e){
_client.Abort(); }
}
I am not sure why you wanna do that, but if the WCF is hosted in a IIS7, the WCF will start with or without connections, there is no point keeping a connection alive.
In my experience, those kind of services works best when are stateless (unless you have a really good reason). I strongly suggest opening and closing the connection each time. If you are doing this for performance, there are another ways to avoid closing and opening each time.
Q1: According to MSDN the openTimeout is 1 minute
http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.binding.opentimeout.aspx
Q2: you do not need to close the connection explicitly, but it's a good practice and I strongly recommend to do it. Non closing the connections could lead in a overhead on the WCF.
As I know, WCF do no keep the connection alive. After a predefined time passes (inactivityTimeout="00:10:00"), the connection will throw an exception when you try to call _client.doSomething1() or any other method on the service.
WCF inactivity timeout
To keep connection alive you should call a simple method at predefined intervals, lets say every 1 minute.
However, I agree with Jordi about that you should use wcf services stateless until it is realy necessary.
Related
I have a WCF service and I have the following (simplified) class:
public class PerOperationSingleton : IDisposable
{
private static bool _hasInstance = false;
public PerOperationSingleton()
{
if(_hasInstance)
throw new InvalidOperationException("Cannot have multiple instances during a single WCF operation");
_hasInstance = true;
}
public void Dispose()
{
_hasInstance = false;
}
}
I guess, it's pretty self explanatory piece of code. I don't need a singleton for entire WCF service but only during a single operation call. If one instance of the PerOperationSingleton is disposed, it should be safe to create a new instance during the same WCF operation.
The problem is that I don't know how to make the _hasInstance variable to be effective only for one WCF operation. I know about [ThreadStatic], but I've heard that ASP.NET and WCF do not guarantee that an operation will be executed on a single thread - it might be transferred to another thread.
I definitely don't want my _hasInstance = true to move to thread pool and get incorrectly detected if some other operation picks that thread from the pool.
If WCF operation moves to another thread, I would like the _hasInstance variable to keep the "true" value if it was set.
And I don't want to change some global settings for my WCF service to avoid affecting the performance or get into some problems which will be hard to debug and solve later (I don't feel proficient enough in advanced ASP.NET and WCF topics).
I cannot store _hasInstance in session either because my client requested to disable .NET sessions for various reasons.
I would like the class PerOperationSingleton actually to be environment agnostic. It shouldn't really know anything about WCF or ASP.NET.
How do I make _hasInstance variable static during entire call of my WCF operation and don't affect other WCF operations?
I would consider using OperationContext to make you data "static" during the operation call.
Here is a similar discussion Where to store data for current WCF call? Is ThreadStatic safe?
When a FaultException is returned from my WCF service, I need to Abort the channel instead of Closing it. Both my client and service work fine with this approach but after implementing IErrorHandler on the service and logging any exception, I can see that calling Abort on the client causes the service to log:
System.ServiceModel.CommunicationException: The socket connection was aborted...
I do not want to pollute my service logs with this information and only want to log service related errors. I know I can obviously stop logging any CommunicationExceptions but my service is also a WCF client for other services and CommunicationExceptions raised by these services should be logged.
How can I stop it doing this?
As nobody else has answered the question (Tomas's answer was not relevant), I asked a few experts in the field. Unfortunately, there is no nice way of stopping this and the best that they could come up with was to add logic in IErrorHandler to not log CommunicationExcepions with a message starting with 'The socket connection was aborted'. Not very elegant, but it does work.
The problem is that you get an exception that covers your underlying exception if you get an exception when calling dispose wich is possible. I wrote a wrapper to deal with scenarios like this, you can read about it on my blog: http://blog.tomasjansson.com/2010/12/disposible-wcf-client-wrapper/
The idea is that you have a wrapper around your channel that deals with the scenario if the dispose method throws an exception.
A small example of how you should use my wrapper:
public class ClientWrapperUsage : IYourInternalInterface
{
public IList<SomeEntity> GetEntitiesForUser(int userId)
{
using(var clientWrapper = new ServiceClientWrapper<ServiceType>())
{
var response = clientWrapper.Channel.GetEntitiesForUser();
var entities = response.YourListOfEntities.TranslateToInternal();
return entities;
}
}
}
Here I have assumed that it existing an extension method for a list that contains the entity that is returned by the service, then you use that method to translate it to internal entities. This is 100 % testable, at least I think :). Just moch the interface IYourInternalInterface everywhere you wan't to fake the service.
Hi
Maybe this look like ridiculous but this is problem at least for me
I wrote duplex WCF service, in my service I need to get active client service and save them, and when with occurred special event I call specific client and send some values for it. So I define dictionary and save client in that. (With this method client calls)
public static Dictionary<int, IServiceCallbak> ActiveClients;
public void IConnect(int SenderId)
{
if (ActiveClients == null)
ActiveClients = new Dictionary<int, IServiceCallbak>();
Client = OperationContext.Current.GetCallbackChannel<IServiceCallbak>();
if (ActiveClients.Count(ac => ac.Key == SenderId) > 0)
ActiveClients.Remove(SenderId);
ActiveClients.Add(SenderId, Client);
}
So then when I need find client from that dictionary and call specific method : Client.DoSomthing().
Also when Client wants to exit, it calls IDisconnect method which will remove client from dictionary.
so I manage Active-client in service!!!
But there is problem in client for managing themselves
After a period time which define in app.config service connection will be closed and you should renew that and then open the service.
So in this case:
1)Is there any solution for recreate and open the service object automatically in client.
2)Or when in server side when service want call clients, check state of client-service-object from that dictionary, and reopen connection from server-side (Ridiculous-solution)
Edit
I think better solution is to handle Suggestion 1, I don't know how!!!.
So for now the question is: Is way exist to do Suggestion 1 Or not? Previously I describe Suggestion 1 in Comment:
"And automatically refer to event for this case(like closing or aborting), but I don't find anything for doing this in Service-Client"
In order to prevent the server side from closing the connection you could set up a Heartbeat() method in the contract that the client could call periodically. This is not ideal however, for one thing because the underlying socket could drop and this does nothing to remedy that.
As far as your suggestion 1) if on the client side you are inheriting from ClientBase you are somewhat stuck in that no indication of a problem may be given until you call a method to route to the service. You would have to wrap the call in a try / catch and then employ some reconnect logic:
public class MyClass : ClientBase<IContract>, IContract
{
public void ServiceMethod(String data) {
try {
base.Channel.ServiceMethod(data);
}
catch (CommunicationException ce) {
// Perform some reconnect logic here
base.Channel.ServiceMethod(data);
}
}
}
Your comment for suggestion 2) is correct, if there are any firewalls between the server side and client they would most likely not allow the connection
Edit:
To expand on my suggestion for 1), you would need to create a new connection when the call to the service fails with a CommunicationException. The simplest approach would be to create the service channel in the constructor and then create another when the call fails:
class ServiceClient {
Service1Client mService; // Class generated by VS tool
public ServiceClient()
: base() {
mService = new Service1Client();
}
#region IService1 Members
public string GetData(int value) {
CommunicationState state = mService.State;
if (state == CommunicationState.Closed || state == CommunicationState.Faulted) {
mService = new Service1Client();
}
try {
// Note: The state checked above may not be accurate,
// hence the try...catch
return mService.GetData(value);
}
catch (CommunicationException) {
mService = new Service1Client(); // Reconnect logic
return mService.GetData(value); // If it fails again we are out of luck...
}
}
#endregion
}
Edit2:
In WCF the session is handled by the client, if the session between the client and the service is lost, I know of no way to restore that session, either from the client or the service. You are, unfortunately, stuck here.
If the service wants to send via the callback with a broken session, simply put, it can't. Because of the way networks work the service may not know the actual client address. This and various other issues (like firewalls) mean that trying to reestablish a connection to the client from the service just isn't practical. The only approach for the service is to store what data it wanted to send to the client and send it when the service detects that the client has reconnected.
There is no guarantee that the client will know of the underlying socket dropping, until the client tries to send something over the socket, hence the try...catch. Recreating the channel from the client once it becomes aware of a broken connection is the only way I know of to handle the issue; which is what the code example does.
The heartbeat idea is a way to proactively deal with broken connection. Its efficiency depends on your requirements as to how fast you need to detect a broken connection and how many clients are present. The more clients connected the longer the heartbeat would have to be so that you don't put a load on the network at the service.
Edit3:
After some additional digging there may be a way to do what you want automatically. You can create what is known as a Reliable Session. Activating this involves creating additional entries in the config:
<netTcpBinding>
<binding>
<reliableSession ordered="Boolean"
inactivityTimeout="TimeSpan"
enabled="Boolean" />
</binding>
</netTcpBinding>
It is also available for Http related bindings, check out the link to the Microsoft documentation on the feature.
I'm putting together a WCF service using net.tcp and netTcpBinding to get duplex comms with my Silverlight client. I call into the service from the Silverlight app and the service calls out to another server, passing it a callback method in the WCF service class. The remote server calls back several times and each time it does, the WCF service uses the callbackchannel to send the data to the Silverlight client. It all works nicely most of the time.
If the user puts in a big request, I get a TimeoutException after a large number of callbacks have already worked. (Clearly, there's some work to do elsewhere to prevent this but I'd like to robustify the service, first.)
I was expecting to do some kind of 'if (client.ConnectionState == faulted)' check before trying to call back to the Silverlight client but I can't seem to find the object that holds the state of the connection. Is there one? Am I approaching this from the wrong side?
This is my first venture into a service net.tcp and duplex. I just moved house and my WCF bible is still in a box. Somewhere. :-) So, I can't do my usual background reading.
Any pointers would be gratefully received. Here's some bare code in case my description is too soupy:
private IActiveDirectoryClient client;
private AsyncSearchRunner runner;
public void Search(Request request)
{
this.client = OperationContext.Current.GetCallbackChannel<IActiveDirectoryClient>();
runner = new AsyncSearchRunner();
runner.Run(request.SearchRoot, request.SearchFilter, request.PageSize,
System.DirectoryServices.Protocols.SearchScope.Subtree, SendObjects);
}
private void SendObjects(List<DirectoryObject> items)
{
Response response = new Response();
response.DirectoryObjects = items.ToArray();
client.SendResponse(response);
}
Yes, there is a State property that is defined in the ClientBase<> class (all the proxy classes are derived from ClientBase<>).
There are some proxy wrappers out there that handle fault states of the connection and re-establish connections as needed. Google for "wcf proxy wrapper".
You can also home-brew something if you use some kind of ServiceLocator pattern.
I've been working on a WPF application that uses WCF to access the server side logic & database.
I started with a single WCF client proxy object that I was using repeatedly to call methods on the server. After using the proxy for a while, the server would eventually throw an exception:
System.ServiceModel.EndpointNotFoundException: There was no endpoint listening at http://.../Service/BillingService.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details. ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
I think this is because every service call was opening a new socket from the proxy to the server and never closing them. Eventually the server was flooded and began refusing requests.
After a brief bit of searching, I determined that I need to Close() the proxy periodically. The samples I found are degenerately small. This one provided some helpful hints, but doesn't really answer the question. I've also seen recommendations to avoid the using() pattern (and apply try/catch/finally instead) because the proxy's Dispose method may throw an exception (yuck).
It seems like the recommended pattern is shaping up like this:
[TestClass]
public class WCFClientUnitTest
{
BillingServiceClient _service;
[TestMethod]
public void TestGetAddressModel()
{
List<CustomerModel> customers = null;
try
{
_service = new BillingServiceClient();
customers = _service.GetCustomers().ToList();
}
catch
{
_service.Abort();
_service = null;
throw;
}
finally
{
if ((_service != null) &&
(_service.State == System.ServiceModel.CommunicationState.Opened))
_service.Close();
_service = null;
}
if (customers != null)
foreach (CustomerModel customer in customers)
{
try
{
_service = new BillingServiceClient();
AddressModel address = (AddressModel)_service.GetAddressModel(customer.CustomerID);
Assert.IsNotNull(address, "GetAddressModel returned null");
}
catch
{
_service.Abort();
_service = null;
throw;
}
finally
{
if ((_service != null) &&
(_service.State == System.ServiceModel.CommunicationState.Opened))
_service.Close();
_service = null;
}
}
}
So my question still revolves around how long should I keep a client proxy alive? Should I open/close it for every service request? That seems excessive to me. Won't I incur a significant performance hit?
What I really want to do is create & open a channel and make brief burst of repeated, short, sequential service calls across the channel. Then nicely close the channel.
As a side note, while I haven't implemented it yet, I will soon be adding a security model to the service (both SSL & ACL) to restrict who can call the service methods. One of the answers to this post mentions that renegotiating the authentication & security context makes reopening the channel for every service call wasteful, but simply recommends to avoid constructing a security context.
EDIT 11/3/2010: This seems important, so I am adding it to the question...
In response to Andrew Shepherd's comment/suggestion, I re-ran my unit test with my TrendMicro AntiVirus shutdown while monitoring the output of netstat -b. Netstat was able to record a significant growth of open ports that were owned by WebDev.WebServer40.exe. The vast majority of the ports were in TIME_WAIT state. Microsoft says that ports may linger in NET_WAIT after the client closes the connection...
NOTE: It is normal to have a socket in
the TIME_WAIT state for a long period
of time. The time is specified in
RFC793 as twice the Maximum Segment
Lifetime (MSL). MSL is specified to be
2 minutes. So, a socket could be in a
TIME_WAIT state for as long as 4
minutes. Some systems implement
different values (less than 2 minutes)
for the MSL.
This leads me to believe that if every service call opens a new socket on the server, and because I am calling the service in a tight loop, I could easily flood the server, causing it to run out of available sockets and in turn generate the exception I noted above.
Therefore, I need to pursue one of two paths:
1) attempt to batch service calls so that they reuse the server side socket
2) change my service contract so that I can return larger chunks of data with fewer calls.
The first choice seems better to me, and I am going to continue to pursue it. I'll post back what I discover and welcome further comments, questions and answers.
(Posting a completely different second answer)
If we are talking about "best practice", the real best practice with WCF is to have "coarse-grained methods". If a client is calling a method numerous times in a loop, then the entire business logic should be moved to the service itself.
For example.
[DataContract]
class CustomerAndAddress
{
[DataMember]
CustomerModel Customer;
[DataMember]
AddressModel Address;
}
[ServiceContract]
class BillingService
{
[OperationContract]
CustomerAndAddress[] GetAllCustomersAndAddresses();
}
or, more likely in the real world:
[ServiceContract]
class BillingService
{
[OperationContract]
CustomerReportData FetchCustomerReportInfo(CustomerReportParameters parameterSet);
}
Having said that, I'm still interested to see if you can pull off what you are trying.
It seems like there are several things at play here.
First the unit test I ran and monitored with netstat –b pointed out that Cassini (WebDev.WebServer40.exe) was the owner of the ports that were accumulating in the TIME_WAIT state. As the referenced MSFT kb article notes, it is normal for ports to linger after the FIN handshake while the application waits for any slow packets on the network to be delivered and the message queue to drain. The default configuration of 2 minutes explains why I saw the ports malingering after my unit test completed. While it is possible to change the MSL via registry setting, it isn’t recommended.
But, the important point that I almost overlooked is that the service was running under Cassini. When I switch my server endpoint to run under IIS7, I don’t experience any port growth at all! I can’t explain whether that means the client is reusing the ports or whether IIS7 is just better than Cassini at cleaning up the ports after they are finished.
Now, that doesn’t totally answer my question regarding how often should I close the WCF proxy. It just means I don’t have to close the proxy frequently.
I can see there still being a resource tradeoff to keeping the proxy open for long periods of time.
If you have many (i.e. thousands) of clients accessing your WCF service, it may make sense to release the server resources in between calls, or small batches of calls. In which case, be sure to use the try/catch/finally mechanism and not using() because even though the service proxy implements IDisposable, the close() method can throw an exception if the service is in a faulted state.
On the other hand (as in my particular case), if you only expect to have a few clients accessing your WCF service, you don’t need the added complexity of frequently and explicitly opening and closing the service proxy. Therefore, I intend to open the proxy once when my application launches, and leave it open until the application completes. I intend to implement a service invoke helper method (similar to: Renewing a WCF client when SCT has expired? ) that will recycle the connection, just in case it ever goes into a faulted state. Then, I don’t have to worry about managing the proxy lifetime.
Please let me know if think I am misreading my test results, or if you have a better solution.
I wrote (well, found and modified) a wrapper to help with properly disposing the service. Sorry about the VB. It has some extra things in it, like a MessageViewerInspector so I can intercept the XML that flies in and out of the service. Just ignore it for now.
EDIT: I know this doesn't really answer your question of how to maintain bursts of requests, but it would certainly make using the service a little cleaner, code-wise.
Imports System.ServiceModel
Namespace WCF
''' <summary>
''' This helper fixes an issue with WCF services where an exception gets thrown
''' during the Dispose() call of the client, so it doesn't actually get disposed.
''' </summary>
''' <typeparam name="TProxy"></typeparam>
''' <typeparam name="TChannel"></typeparam>
''' <remarks></remarks>
Public Class ServiceProxyHelper(Of TProxy As {ClientBase(Of TChannel), New}, TChannel As Class)
Implements IDisposable
Private _proxy As TProxy
Private _inspector As MessageViewerInspector
Public ReadOnly Property ServiceProxy() As TProxy
Get
If Not _proxy Is Nothing Then
Return _proxy
Else
Throw New ObjectDisposedException("ServiceProxyHelper")
End If
End Get
End Property
Public ReadOnly Property Inspector() As MessageViewerInspector
Get
If _inspector Is Nothing Then
_inspector = New MessageViewerInspector()
End If
Return _inspector
End Get
End Property
Public Sub New()
_proxy = New TProxy()
_proxy.Endpoint.Behaviors.Add(Me.Inspector)
End Sub
Public Sub New(ByVal endpointAddress As String)
Me.New()
If Not Me._proxy Is Nothing AndAlso Not String.IsNullOrEmpty(endpointAddress) Then
Me._proxy.Endpoint.Address = New EndpointAddress(endpointAddress)
End If
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Try
If Not _proxy Is Nothing Then
If _proxy.State <> CommunicationState.Faulted Then
_proxy.Close()
Else
_proxy.Abort()
End If
End If
Catch ex As CommunicationException
_proxy.Abort()
Catch ex As TimeoutException
_proxy.Abort()
Catch ex As Exception
_proxy.Abort()
Throw
Finally
_proxy = Nothing
End Try
End Sub
End Class
End Namespace
Then you can use it like this:
Using myService As New ServiceProxyHelper(Of MyService.MyServiceClient, MyService.IMyService)
Try
' Do work
myService.ServiceProxy.DoWork()
Catch ex As FaultException(Of MyService.MyServiceException)
' Log exception
End Try
End Using
You have put your own answer in the question.
"What I really want to do is create & open a channel and make brief burst of repeated, short, sequential service calls across the channel. Then nicely close the channel"
That's correct.
Applying this to the example you have given, you can simplify it as:
try
{
_service = new BillingServiceClient();
customers = _service.GetCustomers().ToList();
if (customers != null)
foreach (CustomerModel customer in customers)
{
AddressModel address = (AddressModel)_service.GetAddressModel(customer.CustomerID);
Assert.IsNotNull(address, "GetAddressModel returned null");
}
}
catch
{
_service.Abort();
_service = null;
throw;
}
finally
{
if ((_service != null) &&
(_service.State == System.ServiceModel.CommunicationState.Opened))
_service.Close();
_service = null;
}
Later Edit: Oh, hang on, I just reread your question. You've said that it would fail after multiple repeated calls. I guess the above code actually causes the failure?