.NET Framework Bookmark and Share   
 index > Windows Communication Foundation > How to Send Binary Data or How to bypass XmlInfoSet?
 

How to Send Binary Data or How to bypass XmlInfoSet?

What is the most efficient way to transfer binary data?

In other words, I just want to transmit a blob of binary data. Creating XmlInfoSet seems like a waste of effort (or is it?).

Izor

The most efficient way to transfer binary data (in WCF) is to use an endpoint whose binding uses the BinaryMessageEncodingBindingElement, and a transport binding element. As long as you don't have security or other channels which add complexity to the message, the overhead of the infoset shouldn't be a problem.

Example:

public class Post2944384b

{

[ServiceContract]

public interface ITest

{

[OperationContract]

void Process(byte[] input);

}

public class Service : ITest

{

public void Process(byte[] input)

{

Console.WriteLine("Received {0} bytes from the client", input.Length);

}

}

static Binding CreateBinding()

{

NetTcpBinding binding = new NetTcpBinding();

binding.Security.Mode = SecurityMode.None;

binding.MaxReceivedMessageSize = int.MaxValue;

binding.ReaderQuotas.MaxArrayLength = int.MaxValue;

return binding;

}

public static void Test()

{

string baseAddress = "net.tcp://" + Environment.MachineName + ":8000/Service";

ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));

host.AddServiceEndpoint(typeof(ITest), CreateBinding(), "");

host.Open();

Console.WriteLine("Host opened");

ChannelFactory<ITest> factory = new ChannelFactory<ITest>(CreateBinding(), new EndpointAddress(baseAddress));

ITest proxy = factory.CreateChannel();

byte[] input = new byte[23456];

Random rndGen = new Random(1);

rndGen.NextBytes(input);

proxy.Process(input);

((IClientChannel)proxy).Close();

factory.Close();

Console.WriteLine("Press ENTER to close service");

Console.ReadLine();

host.Close();

}

}


Another option, if you're using .NetFX 3.5, is to use the web programming model's support for raw data - your operation would simply take (or return) a System.IO.Stream object, and it can receive (or return) any blob without any overhead at all. Notice that you could also use Stream in the first case.

Example:

public class Post2944384

{

[ServiceContract]

public interface ITest

{

[OperationContract, WebInvoke]

void Process(Stream input);

}

public class Service : ITest

{

public void Process(Stream input)

{

int bytesRead = 0, totalBytesRead = 0;

byte[] buffer = new byte[10000];

do

{

bytesRead = input.Read(buffer, 0, buffer.Length);

totalBytesRead += bytesRead;

} while (bytesRead > 0);

Console.WriteLine("Received {0} bytes from the client", totalBytesRead);

}

}

public class MyContentTypeMapper : WebContentTypeMapper

{

public override WebContentFormat GetMessageFormatForContentType(string contentType)

{

return WebContentFormat.Raw;

}

}

static Binding CreateBinding()

{

WebMessageEncodingBindingElement webBE = new WebMessageEncodingBindingElement();

webBE.ContentTypeMapper = new MyContentTypeMapper();

HttpTransportBindingElement httpBE = new HttpTransportBindingElement();

httpBE.MaxReceivedMessageSize = int.MaxValue;

httpBE.ManualAddressing = true;

CustomBinding result = new CustomBinding(webBE, httpBE);

return result;

}

public static void Test()

{

string baseAddress = "http://" + Environment.MachineName + ":8000/Service";

ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));

WebHttpBinding serverBinding = new WebHttpBinding();

ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(ITest), CreateBinding(), "");

endpoint.Behaviors.Add(new WebHttpBehavior());

host.Open();

Console.WriteLine("Host opened");

HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(baseAddress + "/Process");

req.Method = "POST";

req.ContentType = "application/octet-stream";

string reqBody = @"whatever you want to send to the service in a binary blob";

byte[] reqBodyBytes = Encoding.UTF8.GetBytes(reqBody);

Stream reqStream = req.GetRequestStream();

reqStream.Write(reqBodyBytes, 0, reqBodyBytes.Length);

reqStream.Close();

HttpWebResponse resp = (HttpWebResponse)req.GetResponse();

Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);

Console.WriteLine(new StreamReader(resp.GetResponseStream()).ReadToEnd());

resp.Close();

Console.WriteLine("Now using the programming model to send data to the service...");

ChannelFactory<ITest> factory = new ChannelFactory<ITest>(CreateBinding(), new EndpointAddress(baseAddress));

factory.Endpoint.Behaviors.Add(new WebHttpBehavior());

ITest proxy = factory.CreateChannel();

FileStream fs = new FileStream(Assembly.GetEntryAssembly().Location, FileMode.Open, FileAccess.Read, FileShare.Read);

proxy.Process(fs);

fs.Close();

((IClientChannel)proxy).Close();

factory.Close();

Console.WriteLine("Press ENTER to close service");

Console.ReadLine();

host.Close();

}

}

Carlos Figueira

The most efficient way to transfer binary data (in WCF) is to use an endpoint whose binding uses the BinaryMessageEncodingBindingElement, and a transport binding element. As long as you don't have security or other channels which add complexity to the message, the overhead of the infoset shouldn't be a problem.

Example:

public class Post2944384b

{

[ServiceContract]

public interface ITest

{

[OperationContract]

void Process(byte[] input);

}

public class Service : ITest

{

public void Process(byte[] input)

{

Console.WriteLine("Received {0} bytes from the client", input.Length);

}

}

static Binding CreateBinding()

{

NetTcpBinding binding = new NetTcpBinding();

binding.Security.Mode = SecurityMode.None;

binding.MaxReceivedMessageSize = int.MaxValue;

binding.ReaderQuotas.MaxArrayLength = int.MaxValue;

return binding;

}

public static void Test()

{

string baseAddress = "net.tcp://" + Environment.MachineName + ":8000/Service";

ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));

host.AddServiceEndpoint(typeof(ITest), CreateBinding(), "");

host.Open();

Console.WriteLine("Host opened");

ChannelFactory<ITest> factory = new ChannelFactory<ITest>(CreateBinding(), new EndpointAddress(baseAddress));

ITest proxy = factory.CreateChannel();

byte[] input = new byte[23456];

Random rndGen = new Random(1);

rndGen.NextBytes(input);

proxy.Process(input);

((IClientChannel)proxy).Close();

factory.Close();

Console.WriteLine("Press ENTER to close service");

Console.ReadLine();

host.Close();

}

}


Another option, if you're using .NetFX 3.5, is to use the web programming model's support for raw data - your operation would simply take (or return) a System.IO.Stream object, and it can receive (or return) any blob without any overhead at all. Notice that you could also use Stream in the first case.

Example:

public class Post2944384

{

[ServiceContract]

public interface ITest

{

[OperationContract, WebInvoke]

void Process(Stream input);

}

public class Service : ITest

{

public void Process(Stream input)

{

int bytesRead = 0, totalBytesRead = 0;

byte[] buffer = new byte[10000];

do

{

bytesRead = input.Read(buffer, 0, buffer.Length);

totalBytesRead += bytesRead;

} while (bytesRead > 0);

Console.WriteLine("Received {0} bytes from the client", totalBytesRead);

}

}

public class MyContentTypeMapper : WebContentTypeMapper

{

public override WebContentFormat GetMessageFormatForContentType(string contentType)

{

return WebContentFormat.Raw;

}

}

static Binding CreateBinding()

{

WebMessageEncodingBindingElement webBE = new WebMessageEncodingBindingElement();

webBE.ContentTypeMapper = new MyContentTypeMapper();

HttpTransportBindingElement httpBE = new HttpTransportBindingElement();

httpBE.MaxReceivedMessageSize = int.MaxValue;

httpBE.ManualAddressing = true;

CustomBinding result = new CustomBinding(webBE, httpBE);

return result;

}

public static void Test()

{

string baseAddress = "http://" + Environment.MachineName + ":8000/Service";

ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));

WebHttpBinding serverBinding = new WebHttpBinding();

ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(ITest), CreateBinding(), "");

endpoint.Behaviors.Add(new WebHttpBehavior());

host.Open();

Console.WriteLine("Host opened");

HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(baseAddress + "/Process");

req.Method = "POST";

req.ContentType = "application/octet-stream";

string reqBody = @"whatever you want to send to the service in a binary blob";

byte[] reqBodyBytes = Encoding.UTF8.GetBytes(reqBody);

Stream reqStream = req.GetRequestStream();

reqStream.Write(reqBodyBytes, 0, reqBodyBytes.Length);

reqStream.Close();

HttpWebResponse resp = (HttpWebResponse)req.GetResponse();

Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);

Console.WriteLine(new StreamReader(resp.GetResponseStream()).ReadToEnd());

resp.Close();

Console.WriteLine("Now using the programming model to send data to the service...");

ChannelFactory<ITest> factory = new ChannelFactory<ITest>(CreateBinding(), new EndpointAddress(baseAddress));

factory.Endpoint.Behaviors.Add(new WebHttpBehavior());

ITest proxy = factory.CreateChannel();

FileStream fs = new FileStream(Assembly.GetEntryAssembly().Location, FileMode.Open, FileAccess.Read, FileShare.Read);

proxy.Process(fs);

fs.Close();

((IClientChannel)proxy).Close();

factory.Close();

Console.WriteLine("Press ENTER to close service");

Console.ReadLine();

host.Close();

}

}

Carlos Figueira

Is there a wayto remove XmlInfoSet overhead?

I have found that NetDataContractSerializer for the same data represented with LINQ classes is at least2 to4 times slower compared to DataSet BinaryFormatter serializer for exactly the same data.

Izor

If you use the .NET 3.5 (web programming model way) there is no XML overhead at all - actually, there's no XML involved in that sample.

Carlos Figueira

You can use google to search for other answers

Custom Search

More Threads

• svcutil NetSuite wsdl import problem
• Error Creating The Web Proxy
• DataContractSerializer Exception on close of last node
• Service databse update time out
• Can I use System.Web.Caching.Cache in WCF?
• HOW TO consume WCF Service in ASP.Net using Visual Studio 2008 - Cannot find Endpoint.
• additional data with security credentials
• WCF Dynamic Endpoint Address Configuration on the Server Side
• Problem while passing dataset over wcf service (Urgent )
• XBAP with WCF