Maybe I'm missing something basic here, so please correct me if I am. I have a local service and a WinForms app that communicate via WCF, but I seem to end up with a lot of copies of this code in my application:
Public Shared Sub MyLocalMethod1()
Dim tcpBinding As New NetTcpBinding
tcpBinding.SendTimeout = New TimeSpan(0, 0, 5)
Dim tcpFactory As ChannelFactory(Of MyWCFClass.MyWCFInterface) = New _
ChannelFactory(Of MyWCFClass.MyWCFInterface)(tcpBinding, "net.tcp://localhost:4079")
Dim ServiceWCFConnection As MyWCFClass.MyWCFInterface = tcpFactory.CreateChannel
ServiceWCFConnection.MyWCFMethod1()
tcpFactory.Close()
End Sub
I should probably be doing this in some kind of a helper class that creates the connection, lets my service use it, and then closes the connection, so I don't have multiple copies of this connection code. However, should I be leaving this connection open, or does it make sense to close it every time? The WinForm generally calls the service every few seconds, so it may make more sense to try and have a common copy that all these different calls can each access, instead of opening a closing a new connection each time.
It depends on your needs because both approaches are correct. You can wrap your channel creation code into some helper. You will have same functionality as you use at the moment with single place to edit your channel creation code (DRY principle). Usage of the service is slower because each call will create new TCP connection. Use some disposable helper class to represent your created connection.
If you decide to use single channel (proxy) for whole application you have to think about some new complexity. You are using Net.Tcp binding which creates transport session - TCP connection will live for long time. Moreover WCF service instance will live for the same time as the connection because default instancing mode is PerSession. So single service instance will handle all requests from your client = your service will became stateful. Also when you use opened channel for several calls you have to test state of the channel - network problem, server problem, timeout or unhandled exception will switch channel to Faulted state - such channel and related service instance cannot be used any more. You have to abort such channel and open new one.
Related
I have an application that needs to stream data up to a server over a particular port. When the application starts it performs a number of checks, for network connectivity, a reachable host, among others. I'd like it to also check the port to ensure it's able to receive data.
I have this code:
Private Function CheckPort(ByVal Host As String) As Boolean
Dim IPs() As IPAddress = Dns.GetHostAddresses(Host)
Dim s As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
s.Connect(IPs(0), <port # removed>)
If s.Poll(-1, SelectMode.SelectWrite) Then
Return True
End If
Return False
End Function
The code works well, but I'm concerned that by performing the check I might be inadvertently preventing subsequent messages from the application from reaching the port. Will performing this check interfere with the actual data I want to send to the host? Should I close the socket with s.close() before returning the function?
I mainly agree with CodeCaster's response.
If you say the server is buggy, it is also probable that a few minutes after you check the port connection, the connection is broken or even closed by the server.
If you still want to do it as a means to reduce risk of making the user write some message that later cannot be sent, this would be a good approach to follow. An alternative is that you can save the data as draft locally or somewhere else for sending it later when the server is available.
Now, going to your code:
You are opening a connection inside function CheckPort so when the function finishes you will lose any reference to s, the open socket. In C, you would have a leak of resources; in Java, a garbage collector will take care of the Socket and close it. I don't know how it is in VB but I'd close that socket before leaving the function. In any case it's a healthy practice.
Additionally, when you have data ready to send you won't be able to do it on the same connection if you lose the reference (s) to the open socket or you close the socket (unless VB has any trick that I don't know). You will have to open a new connection to send data. Don't worry, you will be able to do it even if you made the check before. The server will see it as just a different connection, maybe from a different source port (or could be the same if you closed the connection before, that depends on the OS).
Checking a port before connecting to it is as useful as verifying file existence before opening it: not at all.
The file can be deleted in between checking and opening, and your socket can be closed for a variety of reasons.
Just connect and write to it, it'll throw an appropriate exception when it won't work.
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'm currently trying to set up something like this:
a server side windows wcf service hangs out and listens via tcp for connections from a client side windows service.
when a connection is received (the client calls the CheckIn method on the service) the service obtains a callback channel via OperationContext.Current.GetCallbackChannel<T>
this channel is stored in a collection along with a unique key (specifically, i store the callback interface, the channel, and the key in a List<ClientConnection> where each of those is a property)
calls should now be able to be passed to that client service based on said unique key
this works at first, but after a while stops -- i'm no longer able to pass calls to the client. i'm assuming it's because the connection has been dropped internally and i'm trying to work with a dead connection.
that in mind, i've got the following questions:
how do i tell wcf i want to keep those tcp connections indefinitely (or for as long as possible)?
how do i check, from the client side, whether or not my connection to the server is still valid so i can drop it and check in with the server again if my connection is fried?
i can think of gimpy solutions, but I'm hoping someone here will tell me the RIGHT way.
When you establish the connection from the client, you should set two timeout values in your tcp binding (the binding that you will pass to ClientBase<> or DuplexClientBase<>):
NetTcpBinding binding = new NetTcpBinding();
binding.ReceiveTimeout = TimeSpan.FromHours(20f);
binding.ReliableSession.InactivityTimeout = TimeSpan.FromHours(20f);
My sample uses 20 hours for timeout, you can use whatever value makes sense for you. Then WCF will attempt to keep your client and server connected for this period of time. The default is relatively brief (perhaps 5 minutes?) and could explain why your connection is dropped.
Whenever there is a communication problem between the client and server (including WCF itself dropping the channel), WCF will raise a Faulted event in the client, which you can handle to do whatever you feel appropriate. In my project, I cast my DuplexClientBase<> derived object to ICommunicationObject to get a hold of the Faulted event and forward it to an event called OnFaulted exposed in my class:
ICommunicationObject communicationObject = this as ICommunicationObject;
communicationObject.Faulted +=
new EventHandler((sender, e) => { OnFaulted(sender, e); });
In the above code snippet, this is an instance of my WCF client type, which in my case is derived from DuplexClientBase<>. What you do in this event is specific to your application. In my case, the application is a non-critical UI, so if there is a WCF fault I simply display a message box to the end-user and shut down the app - it'd be a nice world if it were always this easy!
In my current web project, we perform a ClientFactory.CreateChannel for every method call to a remote service.
Is this really necessary?
What is the best practice?
This depends to some extent what your requirements are. Opening a channel is expensive, relatively speaking. Best practice is to have the class that is doing the remote calls implement IDisposable, it should make a call to ClientFactory.CreateChannel once, use the channels in all the method calls, and close the channel when the Dispose method is called. That said, if the time between the calls to methods that call to a remote service is long (longer then the default idle timeout on the channel which is 10 minutes) then doing a ClientFactory.CreateChannel isn't particularly harmful, but I would say it would still be better to go the IDisposable route and encapsulate use of the class with the 'using' keyword
creating a new channel for each method call comes in bad practice "generally".
For Duplex WCF Service
creating a single channel and using it until there is no need to communicate with server anymore/ or that channel gets closed.
After creating the channel, before making any call to server, its recommended to check channel's state (Error, opening, closed).
Registering the channel closed/Error events is recommended to get to know immmediatley when it occurs. so you can take necessary actions or/and create the channel again with same object channel object reference.
For Normal WCF service
Create the proxy pattern, to create channel/ to re-use/ re create, error handling and disposing. set the appropiate inactivity timeout along with WCF client's proxy appropiate configuration which suits best with your solution.
Always Load test!!!!
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