9

A have a web-accessible (via basicHttpBinding) WCF service which I also want to access from other .NET services on the same machine with as higher performance as possible. I understand that the netNamedPipeBinding is ideal for this, but wonder what the best configuration would be given that I'm only even going to be communicating with other .NET processes.

For example, I needn't necessarily use an encoding such as SOAP as this is perhaps too bulky and I don't need the compatibility with any other clients other than a .NET client. I also don't think I need any security.

What would be the best binding configuration for this purpose (or any other configurations for that matter)

Barguast
  • 5,926
  • 9
  • 43
  • 73

3 Answers3

9

As you have noted, the NetNamedPipeBinding binding is optimised for same-machine communication:

Provides a secure and reliable binding that is optimized for on-machine communication.

Ref. : System-Provided Bindings

In chapter one of Juval Lowy's book, "Programming WCF Services", he provides a useful decision-activity diagram for choosing the right binding:

"The first question you should ask yourself is whether your service needs to interact with non-WCF clients. If the answer is yes, and if the client is a legacy MSMQ client, choose the MsmqIntegrationBinding that enables your service to interoperate over MSMQ with such a client. If you need to interoperate with a non-WCF client and that client expects basic web service protocol (ASMX web services), choose the BasicHttpBinding, which exposes your WCF service to the outside world as if it were an ASMX web service (that is, a WSI-basic profile). The downside is that you cannot take advantage of most of the modern WS-* protocols. However, if the non-WCF client can understand these standards, choose one of the WS bindings, such as WSHttpBinding, WSFederationHttpBinding, or WSDualHttpBinding. If you can assume that the client is a WCF client, yet it requires offline or disconnected interaction, choose the NetMsmqBinding that uses MSMQ for transporting the messages. If the client requires connected communication, but could be calling across machine boundaries, choose the NetTcpBinding that communicates over TCP. If the client is on the same machine as the service, choose the NetNamedPipeBinding that uses named pipes to maximize performance. You may fine-tune binding selections based on additional criteria such as the need for callbacks (WSDualHttpBinding) or federated security (WSFederationHttpBinding)."

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
  • Thanks for your reply, but I'm looking to 'fine tune' the binding if there are any improvements that can be made. For example, I think security is enabled by default - I can disable that and save a bit of overhead. I assume SOAP encoding is used, but perhaps binary will speed things up. Perhaps even a faster custom encoding could be used? Any advice in regards to optimising the binding would be appreciated. – Barguast Dec 20 '10 at 00:12
  • 1
    You seem to be saying that you want to " 'fine tune' the binding" before you have established that you need to. Could you explain why you need this performance and what you have done to determine this requirement? – Mitch Wheat Dec 20 '10 at 00:17
  • 2
    I had tested the performance, found that 1,000 iterations of an operation using HTTP, Named Pipes, and performed on the same application took: Service (HTTP) : 5192ms, Service (Named Pipe) : 4646ms, Application : 2971ms. I can accept that it'll be slower, but I expected the NamedPipe binding to be closer to the application speed (the same operation running locally) than the HTTP speed. – Barguast Dec 20 '10 at 09:47
  • 3
    Ah - why? it still needs serialiaztion .Want to tune it - use PROTOBUF as serialiaztion pr otocol. A lot faster than XML / Binary from MS. Downloadable soruces avaialble via google. – TomTom Dec 20 '10 at 15:00
4

Certainly the Named Pipe transport is the best choice.

Transport security with EncryptAndSign is enabled by default on the standard NetNamedPipeBinding. You certainly want to remove this, as doing so will speed things up without any real impact on security, for the reasons I discuss here.

I also suspect, but have not yet confirmed, that changing the message encoding binding element may help. This is because the default is the WCF proprietary 'binary encoding with in-band dictionary', which is an encoding of an XML infoset which aims to reduce redundant bytes e.g. in opening and closing element tags: a worthy aim when network IO is involved, but maybe wasted CPU effort when message transfer is entirely in-memory (provided the messages are not too big). Thus changing to a plain text encoding might also provide a speed improvement.

Chris Dickson
  • 11,964
  • 1
  • 39
  • 60
  • 1
    Link is dead. Are you able to update or post relevant information? Your answer was very helpful and I'd love to see the rest. – VoteCoffee May 05 '14 at 12:42
1

I Understand this is a pretty old question, but it still worth answering. As already mentioned named pipes are fastest and you need to disable security, but the most dramatic effect you'll get if you get rid of data contract serialization and switch to stream-based transfer mode.

Use something like this as binding configuration:

                new NetNamedPipeBinding
                {
                    MaxReceivedMessageSize     = 524288000,
                    ReceiveTimeout             = TimeSpan.MaxValue, // never timeout
                    SendTimeout                = TimeSpan.MaxValue, // never timeout
                    ReaderQuotas               =
                    {
                        MaxStringContentLength = 655360000
                    },
                    TransferMode               = TransferMode.Streamed,
                    Security = new NetNamedPipeSecurity
                    {
                        Mode = NetNamedPipeSecurityMode.None,
                        Transport = new NamedPipeTransportSecurity
                        {
                            ProtectionLevel = ProtectionLevel.None
                        }
                    }
                }

Define your service messages like this:

[MessageContract]
public class CallRequestMessage
{
    [MessageHeader]
    public string Arg1;
    [MessageHeader]
    public int ParametersLen;
    [MessageBodyMember]
    public Stream Parameters;
}

[MessageContract]
public class CallResponceMessage
{
    [MessageHeader]
    public int ResultCode;
    [MessageHeader]
    public int ResultsLen;
    [MessageBodyMember]
    public Stream Results;
}

[ServiceContract]
public interface ILocalServiceAPI
{
    [OperationContract]
    CallResponceMessage Call(CallRequestMessage message);
}

The downside of this method is that now you have to serialize your data yourself. I prefer using protobuf serialization directly to MemoryStream. Place this stream to your CallRequestMessage.Parameters.

Don't forget to transfer ParametersLen/ResultsLen in the message header as Stream is endless (while reading you'll may receive 0 bytes, but unlike normal streams you should continue reading).

unclshura
  • 11
  • 2