WCF is a popular technology for developing distributed applications. Over the past two releases, new features have been added that increased the flexibility of the framework. For example in WCF 3.5, REST was introduced and WCF 4.0 introduced features like Routing, Discovery, Help page with REST etc. With the latest release of WCF in .NET 4.5, several new features have been added. We will explore these new features in this article.
public void PostMessages(MessagePost message)
{
Conn.Open();
Cmd = new SqlCommand();
Cmd.Connection = Conn;
Cmd.CommandText = "Insert into MessagePost Values(@PostDetails)";
Cmd.Parameters.AddWithValue("@PostDetails",message.MessageDetails);
Cmd.ExecuteNonQuery();
Conn.Close();
}
}
}
Improved Intellisense Support in VS2012
Intellisense in Configuration
As we know, Intellisense support for code is a major productivity boost when developing in Visual Studio. However, while creating configuration files, Intellisense support has been ‘weak’ to say the least. Many a times, we make mistakes in writing Service name, Binding name, Contract name, Behavior name etc. resulting in runtime errors. With WCF 4.5, Visual Studio 2012 provides significantly improved Intellisense support in configuration files too. For example as we can see below we have auto completion of Service Names
This type of Intellisense supports easier creation of WCF configuration.
Improved Validations with Configuration
Validation of the configuration file is another important feature in VS 2012. This reduces possible validation mistakes. Any mistakes in configuration will be displayed as below:
Also the configuration errors come up in the Tasks window as warnings:
The validation message of the configuration file will be shown as above.
These subtle improvements in VS 2012 improves developer productivity and takes away some of the pains associated with WCF configuration.
New Https protocol mapping on IIS
Transport security is an important factor of WCF service. In WCF 4.0, we have been provided with default endpoint feature which defines protocol mapping for ‘basicHttpBinding’. In WCF 4.5, if IIS is enabled for SSL and if the service does not have any explicit endpoint defined for the specific binding, then WCF can be hosted on IIS with default HTTPs enabled i.e. ‘basicHttpsBinding’.
To experience the automatic Https protocol mapping on IIS, you need to create an Application Pool with Identity as ‘LocalSystem’. This must be targeted to .NET 4.0 framework as below:
The Identity property is set to the LocalSystem as shown below:
Now we need to create a Web Site under the application pool which will contain the WCF 4.5 service published in it:
The web site must be provided with the SSL certificate which you need to create. The port is set to 443.
Now Open Visual Studio 2012 and create a new WCF Service application and set a Service Name. When you browse the service.svc, you will get the ‘basicHttpBinding’ endpoint in WSDL as shown here:
Now publish the WCF service on IIS in the site created above and browse the service.svc, you will find endpoints as below:
This new feature reduces the amount of configuration required. Although we had SSL support in previous versions of WCF, but it was necessary to declare an explicit endpoint. Now in WCF 4.5, using the default endpoint we can have smaller configuration.
Multiple Authentication support for single endpoint hosted on IIS
Technically, when a WCF service is to be used by multiple client applications over a large network, then the recommended host is IIS. IIS 7.x with Windows Process Activation Service (WAS) enables multi-protocol support to WCF services and various client applications can make calls to WCF service over these protocols.
To setup authentication on the WCF service, the authentication values need to be applied in Web.config file of the Service application and also on IIS. If there are any authentication value mismatches between the Endpoint authentication and the IIS authentication, then authentication mismatch error will occur.
Consider a scenario where the WCF service is configured to use ‘basicHttpBinding’ endpoint with Security mode as ‘Transport’ and ClientCredentialType as ‘Windows’.
The WCF service is published on IIS with authentication set like as the following:
When we try to access the service, we will get the following error
This happens because, the WCF service endpoint is expecting Windows Authentication and the IIS is enabled for anonymous authentication only. To support multiple clients for making call to WCF service with different authentication, developer has to define multiple endpoints for the WCF service.
The solution here is that WCF needs be configured to have capability for inheriting the authentication types provided by IIS. This can be achieved using the ClientCredentialType value on the transport security set to ‘InheritedFromHost’. Now the configuration of the endpoint will be as below:
The ‘InheritedFromHost’ value for the ClientCredentialType is newly introduced in WCF 4.5. This configures, the single endpoint WCF service hosted on IIS to use the authentication types defined on IIS. Now the IIS authentication can be as below:
Now if you browse the service.svc, you will be able to get the WSDL. (Note: The endpoint uses Transport security, so for publishing on IIS 7.x, you need to have Web site enable for SSL.) The client application can have various ClientCredentialType values e.g.
Here the client applications need not pass of any credential information to WCF service, because IIS has authentication type set to Anonymous as enabled. The response from the WCF service, will be successfully delivered to client if the value of the ClientCredentialType is set to Windows as below:
In this case also, the response will be successfully delivered to client, because the Service on IIS has set the Windows Authentication as Enabled if the client application set the ClientCredentialType to ‘Basic’ as below:
This mandates that the client application should send the credentials to WCF service for successful communication otherwise the following exception will be displayed:
So to ensure successful communication between client and the WCF service the credentials are passed as below:
The advantage of this feature is that, for single endpoint WCF service hosted on IIS with multiple authentication type set, multiple client applications with different credentials can communicate with WCF service successfully and hence developer is free from providing several endpoints making WCF service less complex and more manageable.
Support for UDP Endpoint
One of the most attractive and beneficial features of WCF 4.5 is the out-of-box support for UDP protocol. We have been provided with ‘udpBinding’. In some cases the UDP is proven far better than TCP and HTTPS which are the most popular protocols. Typically TCP is used in the non-time critical (may be non-real-time) applications but UDP is very useful for real-time applications e.g. Games or the applications which requires fast data communication. Since TCP performs data-packets checking for the order of the message to be send, it is slower than UDP. In UDP, packet delivery is not guaranteed
and loss or out-of-arrival of packets is acceptable. Thus it is faster that TCP.
and loss or out-of-arrival of packets is acceptable. Thus it is faster that TCP.
Using TCP vs. UDP
Let us setup a simple comparison between the TCP and UDP binding for database communication.
For this example a SQL Server Database is used with following table design:
Task 1: Open VS2012 and create a blank solution, name it as ‘WCF45_UDP_Comparision’. In this solution, add a new WCF Service application; name it as ‘WCF45_UPD_Binding_Service’. Rename, IService1.cs to IService.cs and Service1.svc to Service.svc. Add the below methods in the IService interface:
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel;
namespace WCF45_UPD_Binding_Service
{
[ServiceContract]
public interface IService
{
[OperationContract(IsOneWay=true)]
void PostMessages(MessagePost message);
}
{
[ServiceContract]
public interface IService
{
[OperationContract(IsOneWay=true)]
void PostMessages(MessagePost message);
}
[DataContract]
public class MessagePost
{
[DataMember]
public string MessageDetails { get; set; }
}
}
public class MessagePost
{
[DataMember]
public string MessageDetails { get; set; }
}
}
Task 2: Implement the IService interface in the service class as below:
using System.Data.SqlClient;
namespace WCF45_UPD_Binding_Service
{
public class Service : IService
{
SqlConnection Conn;
SqlCommand Cmd;
public Service()
{
Conn = new SqlConnection("Data Source=.;Initial Catalog=Company;Integrated Security=SSPI");
}
{
public class Service : IService
{
SqlConnection Conn;
SqlCommand Cmd;
public Service()
{
Conn = new SqlConnection("Data Source=.;Initial Catalog=Company;Integrated Security=SSPI");
}
public void PostMessages(MessagePost message)
{
Conn.Open();
Cmd = new SqlCommand();
Cmd.Connection = Conn;
Cmd.CommandText = "Insert into MessagePost Values(@PostDetails)";
Cmd.Parameters.AddWithValue("@PostDetails",message.MessageDetails);
Cmd.ExecuteNonQuery();
Conn.Close();
}
}
}
The fact about the UDP binding is that it is not supported by IIS/WAS because there is no UDP shared listener available on this host, so we need to host via a managed Exe (.NET application). Also one important thing to note is the service contract defines one-way message i.e. Fire and forget which is the most suitable mechanism for UDP based Communication. Other important facts about the UDP Binding are:
- The binding is supported only for .NET client applications. SOAP-based service messaging is not supported.
- No support for transport or message security is available.
- Only text encoding is supported.
Task 3: In the solution created, add a new Console Application and add the App.Config file with the below configuration:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="WCF45_UPD_Binding_Service.Service">
<endpoint address="http://localhost:3401/MyServHttp"
binding="basicHttpBinding"
contract="WCF45_UPD_Binding_Service.IService">
</endpoint>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="WCF45_UPD_Binding_Service.Service">
<endpoint address="http://localhost:3401/MyServHttp"
binding="basicHttpBinding"
contract="WCF45_UPD_Binding_Service.IService">
</endpoint>
<endpoint address="net.tcp://127.0.0.1:3402/MyServTcp"
binding="netTcpBinding"
contract="WCF45_UPD_Binding_Service.IService">
</endpoint>
binding="netTcpBinding"
contract="WCF45_UPD_Binding_Service.IService">
</endpoint>
<endpoint address="soap.udp://localhost:3403/MyServUdp"
binding="udpBinding"
contract="WCF45_UPD_Binding_Service.IService">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:3400/MyServ"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
binding="udpBinding"
contract="WCF45_UPD_Binding_Service.IService">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:3400/MyServ"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Note that, in the above configuration, 3 endpoints HTTP, Tcp and UDP are defined for comparison. Note that, the address schema defined for the UDP endpoint is “soap.udp”.
Following is the code for hosting in Program class:
class Program
{
static void Main(string[] args)
{
ServiceHost Host = new ServiceHost(typeof(WCF45_UPD_Binding_Service.Service));
Host.Open();
Console.WriteLine("Service Started...");
Console.ReadLine();
Host.Close();
Console.ReadLine();
{
static void Main(string[] args)
{
ServiceHost Host = new ServiceHost(typeof(WCF45_UPD_Binding_Service.Service));
Host.Open();
Console.WriteLine("Service Started...");
Console.ReadLine();
Host.Close();
Console.ReadLine();
}
}
}
Task 4: Add the service reference of the above WCF service in Windows application by adding Windows application in the solution created above, name it as ‘WCF45_UDP_Comparision_Client’. The reference will be added using the following URI 'http://localhost:3400/MyServ'. In the App.Config file of the client application, you will get 3 endpoints, one each for Tcp, Udp and Http.
Task 5: Design the WinFrom as below:
Task 6: Write the following code in the Form Code behind:
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Diagnostics;
using System.Windows.Forms;
namespace WCF45_UDP_Comparision_Client
{
public partial class Form1 : Form
{
{
public partial class Form1 : Form
{
#region Class Level Declaration
string Protocol = string.Empty;
MyRef.ServiceClient Proxy;
#endregion
public Form1()
{
InitializeComponent();
}
string Protocol = string.Empty;
MyRef.ServiceClient Proxy;
#endregion
public Form1()
{
InitializeComponent();
}
#region Radio Button Events
private void rdTcp_CheckedChanged(object sender, EventArgs e)
{
Protocol = "Tcp";
}
private void rdTcp_CheckedChanged(object sender, EventArgs e)
{
Protocol = "Tcp";
}
private void rdHttp_CheckedChanged(object sender, EventArgs e)
{
Protocol = "Http";
}
{
Protocol = "Http";
}
private void rdUdp_CheckedChanged(object sender, EventArgs e)
{
Protocol = "Udp";
}
#endregion
{
Protocol = "Udp";
}
#endregion
/// <summary>
/// Method for Posting Messages to Database
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
try
{
if (Protocol == string.Empty)
{
MessageBox.Show("Please select the Protocol");
}
else
{
switch (Protocol)
{
case "Tcp":
Proxy = new MyRef.ServiceClient("NetTcpBinding_IService");
break;
case "Http":
Proxy = new MyRef.ServiceClient("BasicHttpBinding_IService");
break;
case "Udp":
Proxy = new MyRef.ServiceClient("UdpBinding_IService");
break;
}
}
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
for (int i = 0; i < 2000; i++)
{
MyRef.MessagePost msg = new MyRef.MessagePost()
{
MessageDetails = "My Message Post No" + i.ToString() + "with Protocol " + Protocol
};
Proxy.PostMessages(msg);
}
stopWatch.Stop();
if (Protocol == "Tcp")
{
lblTcpTime.Text += stopWatch.ElapsedMilliseconds;
}
if (Protocol == "Http")
{
lblHttpTime.Text += stopWatch.ElapsedMilliseconds;
}
if (Protocol == "Udp")
{
lblUdpTime.Text += stopWatch.ElapsedMilliseconds;
}
/// Method for Posting Messages to Database
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
try
{
if (Protocol == string.Empty)
{
MessageBox.Show("Please select the Protocol");
}
else
{
switch (Protocol)
{
case "Tcp":
Proxy = new MyRef.ServiceClient("NetTcpBinding_IService");
break;
case "Http":
Proxy = new MyRef.ServiceClient("BasicHttpBinding_IService");
break;
case "Udp":
Proxy = new MyRef.ServiceClient("UdpBinding_IService");
break;
}
}
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
for (int i = 0; i < 2000; i++)
{
MyRef.MessagePost msg = new MyRef.MessagePost()
{
MessageDetails = "My Message Post No" + i.ToString() + "with Protocol " + Protocol
};
Proxy.PostMessages(msg);
}
stopWatch.Stop();
if (Protocol == "Tcp")
{
lblTcpTime.Text += stopWatch.ElapsedMilliseconds;
}
if (Protocol == "Http")
{
lblHttpTime.Text += stopWatch.ElapsedMilliseconds;
}
if (Protocol == "Udp")
{
lblUdpTime.Text += stopWatch.ElapsedMilliseconds;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
The Button click event will make call to ‘PostMessage()’ method of the WCF service based upon the Protocol selected from the Radio Button on the UI.
Task 7: To test the comparison, run the Host Application and run the Client application in multiple instances:
Run the client application, and select various Protocols e.g. UDP, TCP and Http and click on the ‘Post Message’ button, the result will be shown as below:
It is clearly shown that for 2000 Database Insert transactions, UDP takes only 165 Milliseconds whereas TCP takes 669 and HTTP takes 1806 milliseconds. Hence it is proven that UDP is faster for performance as compare other protocols.
One more feature worth mentioning is support for WebSockets using NetHttpBinding.
NetHttpBinding and NetHttpsBinding
This is provided for WebSocket programming. WebSocket is the new protocol for bidirectional communication over port 80 and 443. This has provided enhanced performance like TCP protocol. Typically we can make use of this for Duplex communication with WCF 4.5.
Conclusion
WCF has been considered more verbose with respect to configuration and setup when compared to other Remote communication mechanism like the new WebAPI. However the latest WCF release makes significant improvements with respect to setup, configuration and protocol support making it easier to develop and manage WCF applications.
Download the entire source code (Github)
No comments:
Post a Comment