There are times though when performance is critical and you may want to tweek the relevant WCF security settings.
I thought that I would have a look and see what the effect is of the ProtectionLevel security setting which can be set imperatively or declaratively... so I wrote the following performance test to evaluate the three different possible settings.
using System;
using System.Linq;
using System.ServiceModel;
using System.Net.Security;
using System.Diagnostics;
namespace ProtectionLevel1
{
//This is the minimum protection level that the binding must comply with.
[ServiceContract(ProtectionLevel = ProtectionLevel.None)]
public interface IConvertString
{
[OperationContract]
string ConvertString(string input);
}
// Simple service which reverses a string and returns the result
public class ConvertStringService : IConvertString
{
#region IConvertString Members
public string ConvertString(string input)
{
char[] chars = input.ToCharArray();
chars.Reverse<char>();
return chars.ToString();
}
#endregion
}
class Program
{
// Setup the Service host
private static ServiceHost StartServer<T>(string Uri, NetTcpBinding binding)
{
Uri uri = new Uri(Uri);
ServiceHost host = new ServiceHost(typeof(ConvertStringService));
host.AddServiceEndpoint(typeof(T), binding, uri);
host.Open();
Console.WriteLine("Service opened using NetTcpBinding with {0} protection level.", Enum.GetName(typeof(ProtectionLevel), binding.Security.Transport.ProtectionLevel));
return host;
}
// Create channel using NetTcp binding with Uri and execute performance test.
private static double RunPerformanceTestOnNetTcpBinding(NetTcpBinding binding, string endpointUri)
{
const int iterations = 300;
const string stringToConvert = "12";
binding.Security.Mode = SecurityMode.Transport;
Stopwatch watch = new Stopwatch();
watch.Start();
for (Int32 i = 0; i < iterations; i++)
{
ChannelFactory<IConvertString>.CreateChannel(binding,
new EndpointAddress(endpointUri))
.ConvertString(stringToConvert);
}
watch.Stop();
Console.WriteLine("ConvertString with ProtectionLevel {2} : {0} times; Time taken : {1} ",
iterations.ToString(),
watch.Elapsed.TotalSeconds.ToString(),
Enum.GetName(typeof(ProtectionLevel), binding.Security.Transport.ProtectionLevel));
return watch.Elapsed.TotalSeconds;
}
static void Main(string[] args)
{
string uri = "net.tcp://localhost:7000/IConvertString";
NetTcpBinding bindingNoEncryption = new NetTcpBinding();
bindingNoEncryption.Security.Transport.ProtectionLevel = ProtectionLevel.None;
NetTcpBinding bindingWithSign = new NetTcpBinding();
bindingWithSign.Security.Transport.ProtectionLevel = ProtectionLevel.Sign;
NetTcpBinding bindingWithEncryption = new NetTcpBinding();
bindingWithEncryption.Security.Transport.ProtectionLevel = ProtectionLevel.EncryptAndSign;
Console.WriteLine("Run performance test or press q to Quit...");
while (Console.ReadLine() != "q")
{
double noEncryptionTime;
double signTime;
double encryptionTime;
using (ServiceHost host = StartServer<IConvertString>(uri, bindingNoEncryption))
{
noEncryptionTime = RunPerformanceTestOnNetTcpBinding(bindingNoEncryption, uri);
host.Close();
}
using (ServiceHost host = StartServer<IConvertString>(uri, bindingWithSign))
{
signTime = RunPerformanceTestOnNetTcpBinding(bindingWithSign, uri);
host.Close();
}
using (ServiceHost host = StartServer<IConvertString>(uri, bindingWithEncryption))
{
encryptionTime = RunPerformanceTestOnNetTcpBinding(bindingWithEncryption, uri);
host.Close();
}
Console.WriteLine("Run performance test again or press 'q' to Quit...");
}
}
}
}
As you can see from the above tests the when using Transport security with the NetTcpBinding ProtectionLevel Sign performance is not much different to EncryptAndSign, although there is a definite performance improvement when using Protection Level None.
Additional resources:
Understanding Protection Level