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)
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)."
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.
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).
Related
This a snippet of a code from a project I am working on, it goes multiple clients connect to WCF service(host), the host is to detect any changes made to the service Library database and to display to each client the changes that have been made by which, it show the value changed, the IP address of the client that made that change.
private void RaisedPropertyChanged(string prop)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
public string GetIP()
{
OperationContext context = OperationContext.Current;
MessageProperties prop = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpoint =
prop[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
string ip = endpoint.Address;
Console.WriteLine("Client Ip" + ip);
return ip;
}
One way is using a Duplex Contract
How to: Create a Duplex Contract
The duplex contract is one of three message patterns available to
Windows Communication Foundation (WCF) services. The other two message
patterns are one-way and request-reply. A duplex contract consists of
two one-way contracts between the client and the server and does not
require that the method calls be correlated. Use this kind of contract
when your service must query the client for more information or
explicitly raise events on the client
You could also use Signalr
Introduction to SignalR
ASP.NET SignalR is a library for ASP.NET developers that simplifies
the process of adding real-time web functionality to applications.
Real-time web functionality is the ability to have server code push
content to connected clients instantly as it becomes available, rather
than having the server wait for a client to request new data.
Lastly you could just poll the Wcf service for last change information
WFC and Duplex Contracts is very secure an reliable way to achieve your results. Signalr is a very lightweight approach and is'nt as robust or secure.
In this situation, if you don't need security and just a light weight approach, id be inclined go with Signalr
I have inherited a couple of large legacy C# code bases that make extensive use of SOAP/WCF to talk to each other and some third party software. I am somewhat new to WCF. I've run across a situation I can't quite explain. The URL pattern being used for the contracts in one of the service classes is definitely invalid (The top level domain it specifies does not exist).
[OperationContract(Name = "TestMethod", Action = "http://hard.coded.URL.that.is.definitely.invalid/TestMethod")]
[WebMethod(MessageName = "TestMethod")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults = true)]
string TestMethod(string x);
Is it possible that this could work, or is the explanation simply that it has never been used?
I don't know for sure that this service has actually been used for anything. The commit messages on all revisions of this file (and most other files) are useless. This is in one of the modules that talks to third party software that I don't currently have the ability to deploy in a test environment. There are a lot of other WCF endpoints in the project that use valid URL patterns.
Maybe they were doing something really weird with the DNS configuration(?) This service most likely would be run over a local network.
I am building a ServiceStack service that runs on several dozen embedded devices. I'd like to ensure that all communication to the device occurs over an encrypted channel. I've researched various SSL/TLS options, but managing several dozen different certs, or publishing a single cert to dozens of device, seems like a lot of overhead.
I've been looking at the Encrypted Messaging feature, but it appears that this only offers a transparent overlay, which would allow either a plain DTO or an encrypted DTO to be sent.
Is there any way to restrict my endpoints to ONLY accept EncryptedMessage DTOs, while preserving the ability to process them internally? Some sort of filter that can tell the original DTO came from an EncryptedMessage originally maybe?
I've considered the Service Gateway, but it seems like I'd have to have two separate AppHosts - one to receive the encrypted data and one (internal only) to process & respond. Seems like there should be a better way.
I've just marked Encrypted Messaging Requests as Secure in this commit which will allow you to use the Restricting Services Attribute to ensure only secure Requests are made with:
[Restrict(RequestAttributes.Secure)]
public class SecureOnlyServices { }
[Restrict(RequestAttributes.InSecure | RequestAttributes.InternalNetworkAccess,
RequestAttributes.Secure | RequestAttributes.External)]
public class InternalHttpAndExternalSecure { }
This change is available from v4.5.13 that's now available on MyGet.
Earlier versions of ServiceStack can check the IRequest.Items dictionary to determine if it's an Encrypted Messaging Request with:
var isEncryptedMessagingRequest = base.Request.Items.ContainsKey("_encryptCryptKey");
if (!isEncryptedMessagingRequest)
throw new HttpError.Forbidden("Only secure requests allowed");
I am building a WCF based service application in .Net. I am currently designing the contracts.
Should I use response codes, exceptions or textual messages for my service responses to report service result status?
They will be consumed by web applications and other systems.
You should take a look at FaultContracts. See http://msdn.microsoft.com/en-us/library/system.servicemodel.faultcontractattribute.aspx
Your Fault Contract can include a (string based) error code for client side processing, and / or a textual message for display to users.
If your service, or rather you as a service designer, don't know what a (future) client application will want to do with an error message (display or process), include both.
In my opinion best is to use response enum (code) that make sense to client. Apart from it returning message may increase the dataload on the WCF service.
E.g.
throw new FaultException<InvalidArgumentException>(new InvalidArgumentException(),Constants.MaxLengthFields.PhoneNumber)), Response.OrderIdMissing);
[DataContract, Serializable]
enum Response
{
[EnumMember]
OrderIdMissing,
[EnumMember]
ProductCodeInvalid,
}
There are several articles available on the web. Please go though them for more concrete information.
http://blogs.msdn.com/b/brajens/archive/2007/04/23/exception-handling-in-wcf-web-service.aspx
http://blogit.create.pt/blogs/marcosilva/archive/2008/05/18/Developing-a-WCF-Service-%5F2D00%5F-Fault-Exceptions-AND-FAULT-Contracts.aspx
http://blogs.msdn.com/b/brajens/archive/2007/04/23/exception-handling-in-wcf-web-service.aspx
I have a WSDL from which I generated the implementation of ClientBase namely MyService
function void updateData(Data data){
BasicHttpBinding binding = new BasicHttpBinding();
// see there is naked username and password.
EndpointAddress address = new EndpointAddress("http://qa.farwaha.com/eai_enu/start.swe?SWEExtSource=WebService&SWEExtCmd=Execute&UserName=john&Password=johspassword");
MyService service = new MyService(binding, address);
try{
service.update(data);
}finally{
service.close();
}
}
Unfortunately, to call this web service I have to pass User name and password as shown in the code. so, my question is around best practices.
Given that its a Winform Application.
How memory / CPU intensive is creating MyService object?
If you suggest cashing the service, it will hold on to the EndpointAddress; which intern has a string with Username and Password. Which is not a good idea .. any work arounds?
If I keep the code as such, service object will be garbage collected .. and there will be no trace of user name or password (as soon as GC runs)
This is a sample code, I have User Object which stores password in SecureString and every time I have to access the password; I get string from SecureString in an instance private method, use it quickly and let it be garbage collected. I believe if I use a method something like above, it will be safe OR safe enough rather than holding on to reference of Service, What do you suggest !!
To your specific questions:
In your client code, what you're constructing are instances of lightweight proxy classes that wrap the channel infrastructure that serialize messages to/from the service's endpoints. As such, these client proxy classes are cheap and fast to construct because they don't generally do a great deal until you actually send something to the service. One thing to watch out for is when you call services which employ a more complex security scheme - establishing connections to such services can be costly and so it's worth caching or re-using such connections if you can.
"Any workarounds"? Nope! Alas, the service you're consuming is poorly designed - not only do they require username and password to be supplied as part of the service method invocation, but they require that you pass them in the clear over HTTP. You might want to ask them to AT LEAST provide an SSL endpoint so that the username and password can be secured during transit. Better still, they could implement basic-auth to allow you to acquire an HTTP auth cookie that you can attach to subsequent calls against their services.
Yes, the GC will eventually clean-up your proxy instances. Better still, you could wrap your instances in using statements to invoke the Dispose pattern and clean-up deterministically. See my Magic8Ball WCF Service on Codeplex for examples.
Other observations:
Because your service requires your username and passoword, each time you call it, you need to pay some very careful thought to how you're going to obtain and store the username and password.
I would urge you to specify your binding information in the app.config rather than inline in your code. Again, see the Magic8Ball WCF Service: If you create bindings in code and the endpoint changes or if they open up a new endpoint, protocol, encoding and/or binding, you'll have to recompile and redist your entire app. If you specify your bindings in config, you might just be able to get away with shipping an updated app.config.
Hope this helps.