WCF Client in ASP.NET Application
What are the best practices for accessing a WCF web service from an ASP.NET application? Currently, in each page I need to access the service I have a field
private readonly _serviceClient = new WCFServiceClient();
and access it's methods repeatedly, closing it on each call and creating a new instance everytime it's state is Fau开发者_运维知识库lted
. However, I don't know whether I should do it like this or, instead, create a new instance per method call. What are the best practices regarding this?
Check out Wenlong's blog. As of .NET 3.5 Service Pack 1, client proxies extending ClientBase share a static ChannelFactory instance cached application-domain-wide.
From what I've tested and experiment, creation of ChannelFactory and Channel are most resource consuming parts of a wcf call initialization. By using "generated proxies" and if you are using some runtime >= .NET 3.5 Service Pack 1, you have already done with the ChannelFactory part. I've seen that creation of the Channel is even harder and longer when your service contracts get larger (more methods, more types, more parameters etc..). Therefore i suggest you keep your service contracts somehow compact.
So basically if you are using generated proxies, i don't think that caching/sharing will give you a performance improvement.
For the successive calls in a single block of code to the same service, you better use the same service proxy instance. Creating one per call is not the best idea.
I've done something similar to the article RubbleFord linked to in his comment, but since I was dealing with multiple services I used ChannelFactory and cached the returned object upon initial creation. I then would create new channels as needed, use them, then close/abort as needed. The helper methods are in a separate DLL (I'll use Common for the example):
// bindingName refers to the Web.config binding section's name
public static T GetFactoryChannel<T>(string address, string bindingName)
{
string key = typeof(T).Name;
// OpenChannels is a property that refers to a Dictionary<string, object> holding the key and the channel factory
if (!OpenChannels.ContainsKey(key))
{
ChannelFactory<T> factory = new ChannelFactory<T>();
factory.Endpoint.Address = new EndpointAddress(new System.Uri(address));
factory.Endpoint.Binding = new NetTcpBinding(bindingName);
OpenChannels.Add(key, factory);
}
T channel = ((ChannelFactory<T>)OpenChannels[key]).CreateChannel();
((IClientChannel(channel)).Open();
return channel;
}
In my client code, I'd do something like this (with the helper methods in Common):
IMyContract myContract = Common.GetChannelFactory<IMyContract>("net.tcp://someaddress/service", "MyNetTcpBinding");
myContract.SomeMethod();
Common.CloseChannel(myContract); // handles the necessary work to close or abort the channel.
I developed this based on some articles posted on the web around a year ago, when I first started working with WCF, and it's served me well. The OpenChannels dictionary object is stored (in my case, with the AppDomain as most of my WCF services are WCF libraries) so I only need to create each channel factory once during a given app's lifetime.
You can add any necessary logic (for example, credentials, or different types of bindings) to the GetFactoryChannel method as desired. I should also note that I don't add service references to the projects, but use the generated proxy files from svcutil. This is in 3.5, btw.
You could use a single isntance of the service cleint across the application. If you are using dependency injection then any of the IoC framework like Unity or Spring.Net will allow you to configure the client as a Singleton instance within the container. You need not have to write separate code to create the Singleton instance.
精彩评论