Tuesday, December 15, 2009

WCF, Duplex Channels, firewalls and NATs


Introduction

WCF supports duplex channels; this means you can have a server fire an event back to the client. This works with Silverlight and also with full .NET apps. This blog does not go into details on how to create a duplex channel but it does show the results of testing it behind a firewall and on a NATed connection.

Creating a Duplex Channel

To create a duplex channel you need to define a contract that says what you need the client to implement. On your main contract you need to include a reference to this interface . This interface is known as the callback contract. Your service interface will look like

[ServiceContract(SessionMode = SessionMode.Required,CallbackContract = typeof(ICallBackChannel))]
public interface IService1
{
[OperationContract(IsOneWay = true)] // IsOneWay means the caller will not expect a reply, this allows us to use call back channel without causing a deadlock.
void PingServer();
}
ICallBackChannel is the interface that defines the contract that the client will implement. Eg
public interface ICallBackChannel
{
[OperationContract(IsOneWay = true)]
void Ping();
}

Other ways to get events

You don't need to use duplex channels, you can manually implement the interface in the client and manage this yourself. You will find that this approach won't work when you are NATed or firewalled.

Testing it from a NATed connection (and firewalled)

If you use netTcpBinding then the client will keep the socket open and receive call-back messages. To test I used a Virtual PC and configured the connection to use a NAT. I turned the firewall on and tested it. It worked fine. If you were to use a wsDualHttpBinding behind a NAT it would not work. Let's examine the traffic that goes on with the http binding.
When I open the Client up, you see the following traffic on the server. (This has been captured using fiddler)





The client has managed to connect to the server but the server cannot talk back to the client. This is due to the address virtualxp-28481 not existing on our network as the client is NATed. So, Duplex Channels will not work if your client is NATed. A firewall may also block the port.
If we change the binding to use netTcpBinding then it works fine. We can see the open sockets on the client.




If we kill the connection the client channel goes into a faulted state.

Some other tricks

When the connection goes into a faulted state WCF raises an event. The client and the server can hook into this event: for example, the client could try to re-open the connection.
When I create the callback channel, we can attach to the Faulted event .
wisdomCallbackServer.InnerChannel.Faulted += new EventHandler(InnerChannel_Faulted);
The code that gets fired just reconnects.
Also, as a default your server will only allow 10 connections, this can be increased by changing the settings in the config file :



If I get time, I may post the test project on codeplex. I will re-blog if I do this.

Tuesday, December 1, 2009

Don't use .RenderBeginTag("pre")

Even in our modern XHTML/DHTML/AJAX world we still sometimes need to use a good old fashioned <pre>
tag. In our Records Management application, Wisdom, we needed to use one to display the contents of a plain text email that had been stored in Wisdom.  So I used the following code fragment:

writer.RenderBeginTag("pre");
writer.Write(HttpUtility.HtmlEncode(textContent));
writer.RenderEndTag();


but this didn't work very well! The first line of the email was indented as shown below:

         This is a
multi line
plain text email.

The reason is that RenderBeginTag uses some (normally helpful) logic internally to indent HTML tags and content so that it is more readable when you view the source. BUT you don't want this inside a <pre> tag because it preserves the whitespace! So you need to use WriteFullBeginTag and WriteEndTag methods on HtmlTextWriter instead:

writer.WriteFullBeginTag("pre");
writer.Write(HttpUtility.HtmlEncode(textContent));
writer.WriteEndTag("pre");