Carrying on from an excellent MSDN blog post by Rick Rainey comparing the performance of various WCF bindings here is an example including NetNamePipes and ProtoBuf-Net:
Original blog post: http://blogs.msdn.com/b/rickrain/archive/2012/05/20/which-wcf-binding-is-best.aspx
protobuf-net
Is available via Nuget or its Google project hosting: http://code.google.com/p/protobuf-net/
AddressAccessDeniedException
If you come across the following exception:
HTTP could not register URL http://+:9001/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details).
Either run Visual Studio using “Run as Administrator” or visit the following link for a more complete resolution:
Source
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using ProtoBuf;
using ProtoBuf.ServiceModel;
namespace BindingTest
{
[ServiceContract]
public interface ITestService
{
[OperationContract]
void Execute(TestData data);
}
[DataContract]
[ProtoContract]
public class TestData
{
[DataMember]
[ProtoMember(1)]
public List<string> Data { get; set; }
}
public class TestService : ITestService
{
public void Execute(TestData data)
{
// empty service implementation
}
}
class Program
{
static void Main(string[] args)
{
var bindingElements = new BindingElement[] {
new BinaryMessageEncodingBindingElement(),
new ReliableSessionBindingElement(true),
new HttpTransportBindingElement()
};
var bindings = new Binding[]
{
new WSHttpBinding() { MaxReceivedMessageSize = Int32.MaxValue },
new NetTcpBinding
{
Name = "NetTcpBinding (SecurityMode.Message)",
Security = { Mode = SecurityMode.Message },
MaxReceivedMessageSize = Int32.MaxValue
},
new CustomBinding(bindingElements)
{
Name = "CustomBinding (HTTP/Binary/ReliableSession(ordered)/NoSecurity"
},
new NetTcpBinding(),
new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport),
new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
};
var payloadSize = 15000;
var iterations = 5;
OutputTitle(payloadSize, iterations);
// Compare all the bindings in the bindings array.
CompareBindings(bindings, payloadSize, iterations, false);
// Compare all the bindings using protobuf-net
CompareBindings(bindings, payloadSize, iterations, true);
OutputNote();
}
public static void OutputTitle(int payloadSize, int iterations)
{
Console.WriteLine("Test parameters: {0} byte payload, {1} iterations",
payloadSize.ToString("N0"),
iterations);
Console.WriteLine();
}
private static void OutputNote()
{
Console.WriteLine();
Console.WriteLine("NOTE: NetNamedPipe is only used for same machine inter process communication");
Console.WriteLine();
}
public static string GenerateRandomStringData(int stringSize)
{
var r = new Random();
var sb = new StringBuilder(stringSize);
while (sb.Length < stringSize)
sb.Append((char)(r.Next(0, 256)));
return sb.ToString();
}
public static TestData GenerateTestData(int payloadSize)
{
const int itemDataSize = 4096;
var data = new TestData {Data = new List<string>()};
int numDataItems = payloadSize / itemDataSize;
for (int item = 0; item < numDataItems; item++)
data.Data.Add(GenerateRandomStringData(itemDataSize));
data.Data.Add(GenerateRandomStringData(payloadSize - (numDataItems * itemDataSize)));
return data;
}
public static void CompareBindings(Binding[] bindings, int payloadSize, int iterations, bool useProtoBuf)
{
Console.WriteLine("Using {0} serialisation", useProtoBuf ? "protobuf" : "normal");
var data = GenerateTestData(payloadSize);
foreach (var b in bindings)
{
try
{
// Run the test on this binding.
Stopwatch result = TestBinding(b, data, iterations, useProtoBuf);
// Output the results.
Console.Write(b.Name);
//Console.WriteLine(string.Format("Payload Size: {0}, Iterations: {1}", payloadSize, iterations));
//Console.WriteLine(" Binding Elements:");
//foreach (BindingElement be in b.CreateBindingElements())
// Console.WriteLine(" {0}", be.GetType());
Console.WriteLine(", time: {0} ms", result.ElapsedMilliseconds);
}
catch (Exception e)
{
Console.WriteLine("EXCEPTION: {0}", e.Message);
}
}
Console.WriteLine();
}
public static Stopwatch TestBinding(Binding binding, TestData data, int iterations, bool useProtoBuf)
{
var address = GetAddress(binding);
// Start the host using the binding provided
var host = new ServiceHost(typeof(TestService), new Uri(address));
var endpoint = host.AddServiceEndpoint(typeof(ITestService), binding, "");
if (useProtoBuf)
endpoint.Behaviors.Add(new ProtoEndpointBehavior());
host.Open();
var sw = new Stopwatch();
sw.Restart();
// Create a client proxy using the binding provided
var cf = new ChannelFactory<ITestService>(binding, address);
ITestService proxy = cf.CreateChannel();
// Call the service
for (int count = 0; count < iterations; count++)
proxy.Execute(data);
// Close the client proxy and host.
cf.Close();
sw.Stop();
host.Close();
return sw;
}
private static string GetAddress(Binding binding)
{
var machine = "localhost";
var port = (binding.Scheme == "net.pipe")
? ""
: ":9001";
return string.Concat(binding.Scheme, "://", machine, port, "/", Guid.NewGuid().ToString());
}
}
}
Download: http://stevenhollidge.com/blog-source-code/BindingTestSolution.zip
No comments:
Post a Comment