I have an application that reuses the same WCF channel over and over again. I keep a static reference through a factory object. I wonder if this is good pratice or that I should open x channels and round robin all services calls over these channels instead of using the single channel?
Do these services calls get queued if using only 1 channel or does the same happen when I would use x channels?
You should use a single channel factory for all requests but different channels should be constructed for each request. Never reuse channels. They are not expensive to create and are not thread safe. What is expensive to create is the channel factory. It is thread safe and can be reused. Of course if the channel factory get into a faulted state you might need to reopen it.
#Darin Dimitrov
Reuse the same proxy
In many cases, you would want to reuse the same proxy. This has the best performance. It is especially true when you use security features since the initial security negotiation can have high cost.
proxy equals channel. if you look at this blog post, you can see the following code snippet:
ISimpleContract proxy = factory.CreateChannel();
((IClientChannel)proxy).Open();
Furthermore, if you plan to work with sessions, you don't want to establish a new session for each request (by creating a new channel/proxy each time).
Related
We're all being taught to use Dependency-Injection for coding in ASP.NET Core applications, but all of the examples I've seen so far that related to the retrieval of services via DI relate to situations where the method that has the service reference injected is strictly bound to a specific HTTP request (HttpContext) (e.g. MVC controllers, Routing delegates).
Service location is warned against as an anti-pattern, but I'm not sure on how to obtain a proper service (e.g. DbContext) reference via DI in code that is not bound a specific HTTP request, e.g. code that has to respond to messages arriving over a websocket.
Although the websocket itself is set-up initially with a specific HTTP request, messages will get responses over potentially a long lifetime of the websocket (as long as the user web session lasts). The server should not reserve/waste a DbContext/DB connection over this entire lifetime (this would result in exhaustion quickly), but rather obtain a DB connection temporarily when a message arrives and requires a response; discarding the DbContext/connection immediately afterwards - while the original HTTP request that set-up the websocket in the very beginning of the user-session technically is still there.
I haven't been able to find anything else but using:
httpContext.RequestServices.GetService(typeof(<MyNeededDbContext>)
This way I use the initial httpContext (obtained via DI when the websocket was set up), but at multiple times after that whenever a websocket message needs a response I can request a transient service object (a DbContext in this example), that may be recycled or pooled after the message response is complete, but while the original httpContext is very much still alive.
Anyone aware of a better approach?
You can create a new service scope to manage the lifetime of services yourself;
IServiceProvider provider = ...;
using (var scope = provider.CreateScope())
{
var context = scope.ServiceProvider.GetService<MyNeededDbContext>();
...
}
What should be the HttpClient lifetime of a WebAPI client?
Is it better to have one instance of the HttpClient for multiple calls?
What's the overhead of creating and disposing a HttpClient per request, like in example below (taken from http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client):
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:9000/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// New code:
HttpResponseMessage response = await client.GetAsync("api/products/1");
if (response.IsSuccessStatusCode)
{
Product product = await response.Content.ReadAsAsync<Product>();
Console.WriteLine("{0}\t${1}\t{2}", product.Name, product.Price, product.Category);
}
}
HttpClient has been designed to be re-used for multiple calls. Even across multiple threads.
The HttpClientHandler has Credentials and Cookies that are intended to be re-used across calls. Having a new HttpClient instance requires re-setting up all of that stuff.
Also, the DefaultRequestHeaders property contains properties that are intended for multiple calls. Having to reset those values on each request defeats the point.
Another major benefit of HttpClient is the ability to add HttpMessageHandlers into the request/response pipeline to apply cross cutting concerns. These could be for logging, auditing, throttling, redirect handling, offline handling, capturing metrics. All sorts of different things. If a new HttpClient is created on each request, then all of these message handlers need to be setup on each request and somehow any application level state that is shared between requests for these handlers also needs to be provided.
The more you use the features of HttpClient, the more you will see that reusing an existing instance makes sense.
However, the biggest issue, in my opinion is that when a HttpClient class is disposed, it disposes HttpClientHandler, which then forcibly closes the TCP/IP connection in the pool of connections that is managed by ServicePointManager. This means that each request with a new HttpClient requires re-establishing a new TCP/IP connection.
From my tests, using plain HTTP on a LAN, the performance hit is fairly negligible. I suspect this is because there is an underlying TCP keepalive that is holding the connection open even when HttpClientHandler tries to close it.
On requests that go over the internet, I have seen a different story. I have seen a 40% performance hit due to having to re-open the request every time.
I suspect the hit on a HTTPS connection would be even worse.
My advice is to keep an instance of HttpClient for the lifetime of your application for each distinct API that you connect to.
If you want your application to scale, the difference is HUGE! Depending on the load, you will see very different performance numbers. As Darrel Miller mentions, the HttpClient was designed to be re-used across requests. This was confirmed by folks on the BCL team who wrote it.
A recent project I had was to help a very large and well-known online computer retailer scale out for Black Friday/holiday traffic for some new systems. We ran into some performance issues around the usage of HttpClient. Since it implements IDisposable, the devs did what you would normally do by creating an instance and placing it inside of a using() statement. Once we started load testing the app brought the server to its knees - yes, the server not just the app. The reason is that every instance of HttpClient opens a port on the server. Because of non-deterministic finalization of GC and the fact that you are working with computer resources that span across multiple OSI layers, closing network ports can take a while. In fact Windows OS itself can take up to 20 secs to close a port (per Microsoft). We were opening ports faster than they could be closed - server port exhaustion which hammered the CPU to 100%. My fix was to change the HttpClient to a static instance which solved the problem. Yes, it is a disposable resource, but any overhead is vastly outweighed by the difference in performance. I encourage you to do some load testing to see how your app behaves.
You can also check out the WebAPI Guidance page for documentation and example at
https://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client
Pay special attention to this call-out:
HttpClient is intended to be instantiated once and re-used throughout the life of an application. Especially in server applications, creating a new HttpClient instance for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors.
If you find that you need to use a static HttpClient with different headers, base address, etc. what you will need to do is to create the HttpRequestMessage manually and set those values on the HttpRequestMessage. Then, use the HttpClient:SendAsync(HttpRequestMessage requestMessage, ...)
UPDATE for .NET Core:
You should use the IHttpClientFactory via Dependency Injection to create HttpClient instances. It will manage the lifetime for you and you do not need to explicitly dispose it. See Make HTTP requests using IHttpClientFactory in ASP.NET Core
As the other answers state, HttpClient is meant for reuse. However, reusing a single HttpClient instance across a multi-threaded application means you can't change the values of its stateful properties, like BaseAddress and DefaultRequestHeaders (so you can only use them if they are constant across your application).
One approach for getting around this limitation is wrapping HttpClient with a class that duplicates all the HttpClient methods you need (GetAsync, PostAsync etc) and delegates them to a singleton HttpClient. However that's pretty tedious (you will need to wrap the extension methods too), and fortunately there is another way - keep creating new HttpClient instances, but reuse the underlying HttpClientHandler. Just make sure you don't dispose the handler:
HttpClientHandler _sharedHandler = new HttpClientHandler(); //never dispose this
HttpClient GetClient(string token)
{
//client code can dispose these HttpClient instances
return new HttpClient(_sharedHandler, disposeHandler: false)
{
DefaultRequestHeaders =
{
Authorization = new AuthenticationHeaderValue("Bearer", token)
}
};
}
Related to high-volume web sites but not directly to HttpClient. We have the snippet of code below in all of our services.
// number of milliseconds after which an active System.Net.ServicePoint connection is closed.
const int DefaultConnectionLeaseTimeout = 60000;
ServicePoint sp =
ServicePointManager.FindServicePoint(new Uri("http://<yourServiceUrlHere>"));
sp.ConnectionLeaseTimeout = DefaultConnectionLeaseTimeout;
From https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Net.ServicePoint.ConnectionLeaseTimeout);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.2);k(DevLang-csharp)&rd=true
"You can use this property to ensure that a ServicePoint object's active connections do not remain open indefinitely. This property is intended for scenarios where connections should be dropped and reestablished periodically, such as load balancing scenarios.
By default, when KeepAlive is true for a request, the MaxIdleTime property sets the time-out for closing ServicePoint connections due to inactivity. If the ServicePoint has active connections, MaxIdleTime has no effect and the connections remain open indefinitely.
When the ConnectionLeaseTimeout property is set to a value other than -1, and after the specified time elapses, an active ServicePoint connection is closed after servicing a request by setting KeepAlive to false in that request.
Setting this value affects all connections managed by the ServicePoint object."
When you have services behind a CDN or other endpoint that you want to failover then this setting helps callers follow you to your new destination. In this example 60 seconds after a failover all callers should re-connect to the new endpoint. It does require that you know your dependent services (those services that YOU call) and their endpoints.
One thing to point out, that none of the "don't use using" blogs note is that it is not just the BaseAddress and DefaultHeader that you need to consider. Once you make HttpClient static, there are internal states that will be carried across requests. An example: You are authenticating to a 3rd party with HttpClient to get a FedAuth token (ignore why not using OAuth/OWIN/etc), that Response message has a Set-Cookie header for FedAuth, this is added to your HttpClient state. The next user to login to your API will be sending the last person's FedAuth cookie unless you are managing these cookies on each request.
You may also want to refer to this blog post by Simon Timms: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
But HttpClient is different. Although it implements the IDisposable interface it is actually a shared object. This means that under the covers it is reentrant) and thread safe. Instead of creating a new instance of HttpClient for each execution you should share a single instance of HttpClient for the entire lifetime of the application. Let’s look at why.
As a first issue, while this class is disposable, using it with the using statement is not the best choice because even when you dispose HttpClient object, the underlying socket is not immediately released and can cause a serious issue named ‘sockets exhaustion.
But there’s a second issue with HttpClient that you can have when you use it as singleton or static object. In this case, a singleton or static HttpClient doesn't respect DNS changes.
in .net core you can do the same with HttpClientFactory something like this:
public interface IBuyService
{
Task<Buy> GetBuyItems();
}
public class BuyService: IBuyService
{
private readonly HttpClient _httpClient;
public BuyService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<Buy> GetBuyItems()
{
var uri = "Uri";
var responseString = await _httpClient.GetStringAsync(uri);
var buy = JsonConvert.DeserializeObject<Buy>(responseString);
return buy;
}
}
ConfigureServices
services.AddHttpClient<IBuyService, BuyService>(client =>
{
client.BaseAddress = new Uri(Configuration["BaseUrl"]);
});
documentation and example at here
I have written a WCF service with some regular functionality (add user, remove, search, update...). The implementation of this functionality is in entity framework (with sql DB).
Now I want to use it in the client side.
And I have some basic questions:
I have many calls to the WCF methods in the client side - should I try catch every time each call?
Every time I want to call a method, for example AddUser(User user), I need to make an instance of my service, like that:
WcfService client = new WcfService();
client.AddUser(user);
And in another place I write:
WcfService client = new WcfService(); //Again making a new instance...
client.UpdateUser(user);
Should I make one instance for all the application for my wcf service?
Or every time to make a new instance before I call to a method? (as in my example above).
Thanks very much !
In many cases, you want to reuse the same client proxy, as this connection method yields the best performance. Reusing the same proxy can be particularly beneficial if you use security features, which have a high initial security negotiation cost. Note: you surely need to check the state of the client proxy before using.
In the event that reusing the same client proxy is not an option, then consider using a ChannelFactory proxy that uses caching.
The following link provides a good explanation along with best practice recommendations:
http://blogs.msdn.com/b/wenlong/archive/2007/10/27/performance-improvement-of-wcf-client-proxy-creation-and-best-practices.aspx
(i)You can make an instance one time for a service, and use the same client whenever you need to make a method call. if you are aborting or closing the connection then you need to create each time.
(ii)It is better if you use try catch methods in each methods, so it will be easy to close the connection and identify the exceptions.
I've been preparing for MS 70-513 exam and with the Self-paced training kit content cd there are some practice tests.
The following is one question of those tests which I kindly ask someone to explain. The correctly marked answer is A, however I don't understand why D isn't the correct one.
Question:
What is the default behavior for instancing service objects in WCF?
A - Each instance is associated with one user-defined service object.
B - Each instance handles all requests for the lifetime of the requesting application.
C - A new instance is created for each client request.
D - A new instance is created for each new client session.
Thakns in advance,
Bruno
I got an answer from msdn forums, I guess I'm convinced with it.
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/2e35729f-603a-4a52-a3b7-920c9f3a8100/
Quoting the answer:
This is a tricky one - I assume that the reason D is not true is that
not every client creates a session. For example basicHttpBinding does
not support sessions. So if you don't always have a session - D is not
always true. However, A is always true (unless you create your own
custom behavior) because every InstanceContext object wraps a single
user-defined service object (an object created according to your
service type)
It's PerSession
http://msdn.microsoft.com/en-us/library/ms733040.aspx
If you use the default instancing behavior in WCF, all calls between a WCF client object are handled by the same service instance. Therefore, at the application level, you can think of a session as enabling application behavior similar to local call behavior. For example, when you create a local object:
A constructor is called.
All subsequent calls made to the WCF client object reference are processed by the same object instance.
A destructor is called when the object reference is destroyed.
Sessions enable a similar behavior between clients and services as long as the default service instance behavior is used. If a service contract requires or supports sessions, one or more contract operations can be marked as initiating or terminating a session by setting the IsInitiating and IsTerminating properties.
I would think D is correct as well, since InstanceContextMode is set to PerSession by default (link).
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.