I am using the following code to investigate what happens when you fail to close the proxy:
class Program
{
static void Main()
{
for (int i = 1; i < 500; i++)
{
MakeTheCall(i);
}
Console.WriteLine("DONE");
Console.ReadKey();
}
private static void MakeTheCall(int i)
{
Console.Write("Call {0} - ", i);
var proxy = new ServiceReference1.TestServiceClient();
var result = proxy.LookUpCustomer("123456", new DateTime(1986, 1, 1));
Console.WriteLine(result.Email);
//proxy.Close();
}
}
The service is using net.Tcp binding, WAS hosted, all default values.
Running it, I get a timeout when i > 400. Why 400 - is this a setting somwhere? I expected it to be much less - equal to maxConnections.
By not closing the proxy, you are maintaining a session on the service. The maxConcurrentSessions throttling attribute controls how many sessions the service can accommodate. The default (in .NET 4.0) is 100 * Processor Count, so I am guessing that you have 4 processors (or cores) = 400 concurrent sessions?
The reason your test code is timing out is probably due to the default WCF service throttling and doesn't have anything to do with not disposing of the proxy object. To conserve client-side resource, you should always properly dispose the proxy instance.
I believe that a service host will only create up to 16 instances of a service by default which may be even less if the binding is set to use session of some sort. You're flooding it with around 400 requests within a few seconds. There are a set of WCF performance counters you can fire up and view the instancing of a WCF service. I knew all that prep for the WCF certification exam would come in really useful sometime :)
Related
I have below code to invoke a REST API method using Apache HTTP client. However only two parallel requests could be sent using above client.
Is there any parameter to set max-connections?
HttpPost post = new HttpPost(resourcePath);
addPayloadJsonString(payload, post);//set a String Entity
setAuthHeader(post);// set Authorization: Basic header
try {
return httpClient.execute(post);
} catch (IOException e) {
String errorMsg = "Error while executing POST statement";
log.error(errorMsg, e);
throw new RestClientException(errorMsg, e);
}
Jars I am using are below are,
org.apache.httpcomponents.httpclient_4.3.5.jar
org.apache.httpcomponents.httpcore_4.3.2.jar
You can configure the HttpClient with HttpClientConnectionManager
Take a look at Pooling connection manager.
ClientConnectionPoolManager maintains a pool of HttpClientConnections and is able to service connection requests from multiple execution threads. Connections are pooled on a per route basis. A request for a route which already the manager has persistent connections for available in the pool will be services by leasing a connection from the pool rather than creating a brand new connection.
PoolingHttpClientConnectionManager maintains a maximum limit of connections on a per route basis and in total. Per default this implementation will create no more than 2 concurrent connections per given route and no more 20 connections in total. For many real-world applications these limits may prove too constraining, especially if they use HTTP as a transport protocol for their services.
This example shows how the connection pool parameters can be adjusted:
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// Increase max total connection to 200
cm.setMaxTotal(200);
// Increase default max connection per route to 20
cm.setDefaultMaxPerRoute(20);
// Increase max connections for localhost:80 to 50
HttpHost localhost = new HttpHost("locahost", 80);
cm.setMaxPerRoute(new HttpRoute(localhost), 50);
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.build();
I'm having a lot of problems getting tyres on the ground with Windows 8 Programming.
One problem is, I cannot install IIS as Windows 8 is giving me problems because I am dual booting it with 7. Any OS updates fail, including configuration changes such as adding IIS.
But anyway, to get around this, I decided to host a WCF service in a Windows Service with a TCP endpoint, and consume that service in my Store app. For inserts, it works, not a problem.
But when I go to retrieve some data (a very small data set - 3 records), the following error displays: The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.
I've Googled that error and it seems to be a common one - meaning it could be anything. But I am a total noob with WCF.
My code in the ViewModel is simply:
private async void PopulatePeople()
{
var people = await licenceBucketService.GetAllPersonsAsync();
FirstName = people.First().FirstName;
LastName = people.First().LastName;
}
The GetAllPersons method is:
public ObservableCollection<Person> GetAllPersons()
{
ObservableCollection<Person> people = null;
using (var context = new LicenceBucketContext())
{
people = new ObservableCollection<Person>(context.People);
}
return people;
}
The async version in the Reference.cs file looks like:
public System.Threading.Tasks.Task<System.Collections.ObjectModel.ObservableCollection<Win8UI.LicenceBucketService.Person>> GetAllPersonsAsync() {
return base.Channel.GetAllPersonsAsync();
}
Do any WCF gurus see my issue?
I try to generate a lot of User in my DB using a WCF service using a loop.
The script and the web service are running locally (Cassini).
FormWCFClient formClient = new srForm.FormWCFClient();
User user;
int nbUser = 20000;
for (int i = 0; i < nbUser; ++i)
{
user = new User();
user.Email = String.Format("{0}#example.com", i.ToString());
formClient.AddUser(user); // Add the user in DB
}
formClient.Close();
The problem is that around 3300 calls an EndpointNotFoundException is launched with the following innerException : "Unable to connect to the remote server".
I need to wait around 20 seconds in order to be able to continue the process without error (until the next range of 3300 calls).
Is it a code problem or a server limitation ?
You could create a new operation in your service that takes a list of users as a parameter. Then you would call it once with the list instead of calling the existing operation 20000 times with one user. It would reduce the load on the network and ease the use of transactions.
If not possible, then activate WCF tracing and check what happens when the call fails.
Uhm, I’m utterly lost so any help would be much appreciated
The
OperationContext.Current.InstanceContext
is the context of the current service
instance that the incoming channel is
using.
In a Duplex system, the service can
callback to the client via a
CallbackContract. This
CallbackContract is much like a
service on the client side that is
listening for calls from the service
on the channel that the client has
opened. This “client callback
service” can only be accessed via the
same channel it used on the service
and therefore only that service has
access to it.
a) So in duplex systems the same channel instance with which client-side sends messages to the service, is also used by client to receive messages from the service?
b) If in request-reply system a client uses particular channel instance clientChannel to send a message to the service, then I assume this same instance ( thus clientChannel ) needs to stay opened until service sends back a reply to this instance, while in duplex system clientChannel needs to stay opened until the session is closed?
c) I’m assuming such behaviour since as far as I can tell each channel instance has a unique address ( or ID ) which helps to differentiate it from other channel instances ) running on the same client? And when service sends back a message, it also specifies an ID of this channel?
Thus when in Duplex system client calls a service, WCF creates ( on client side ) a channel instance clientChannel, which sends a message over the wire. On server’s side WCF creates channel instance serverChannel, which delivers the message to requested operation(method). When this method wants to callback to the client via CallbackContract, it uses InstanceContext.GetCallBackChannel<> to create a channel, which among other things contains the ID of the channel that called a service ( thus it contains an exact address or ID of clientChannel )?
d) Does in duplex systems client use the same channel instance to call any of endpoint’s operations?
Thank you
I am not sure but here is how I understand this for a Duplex mode communication.
I had a look at the InstanceContext class defined in the System.ServiceModel assembly using dotPeek decompiler.
Internally there is a call
this.channels = new ServiceChannelManager(this);
That means, it is creating channel using a ServiceChannelManager passing in the instance of the same InstanceContext.
This way it keeping a track of the Channel with the instance of InstanceContext.
Then is binds Incoming channel (Service to Client) requests in method that is implemented as :
internal void BindIncomingChannel(ServiceChannel channel)
{
this.ThrowIfDisposed();
channel.InstanceContext = this;
IChannel channel1 = (IChannel) channel.Proxy;
this.channels.AddIncomingChannel(channel1);
if (channel1 == null)
return;
switch (channel.State)
{
case CommunicationState.Closing:
case CommunicationState.Closed:
case CommunicationState.Faulted:
this.channels.RemoveChannel(channel1);
break;
}
}
So to answer your queries :
a. Yes, it internally maintains the Service and InstanceContext (which creates a channel) relations for
calls between Client and Service.
b. Yes, the channel needs to stay opened untill the Service replies back to the context, in which the InstanceContext
will take care of closing the channel.
c. Each client has a unique Session Id, but the InstanceContext type at the Service depends on the InstanceContextMode
used at the Service on the implementation of the Contract.
d. It uses the same channel. InstanceContext maintains a count of IncomingChannel and Outgoing channel.
Incoming channel are the one that are Service to Client directed and Outgoing are Client to Service directed.
You can see this count using debugger in VS.
For the sake of further clarification, as far as the other behavior for a Duplex service is concerned, here is how we can look at the behavior of InstanceContext and how channel instance is created :
I created a Duplex service demo :
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IServiceDuplexCallback))]
public interface IServiceClass
{
[OperationContract(IsOneWay = true)]
void Add(int num1);
}
This contract is implemented as :
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class ServiceClass : IServiceClass
{
int result = 0;
public void Add(int num1)
{
result += num1;
callBack.Calculate(result);
}
IServiceDuplexCallback callBack
{
get
{
return OperationContext.Current.GetCallbackChannel<IServiceDuplexCallback>();
}
}
}
In this implementation notice the first line where InstanceContextMode is set to PerCall. The default is PerSession.
This enumeration has three options:
PerCall - New instance of InstanceContext used for every call independent of Session
PerSession - New instance used for every session
Single - A single instance of InstanceContext used for all the clients.
I created a client which use NetTcpBinding to connect with Service :
InstanceContext ic = new InstanceContext(new TCPCallbackHandler(ref textBox1));
TCP.ServiceClassClient client = new TCP.ServiceClassClient(ic);
// First call to Add method of the Contract
client.Add(val1);
// Second call to Add method of the Contract
client.Add(val2);
TCPCallbackHandler is the class in the Client that implements the Callback contract as:
public class TCPCallbackHandler : TCP.IServiceClassCallback
{
TextBox t;
public TCPCallbackHandler(ref TextBox t1)
{
t = t1;
}
public void Calculate(int result)
{
t.Text += OperationContext.Current.SessionId + " " + result.ToString();
}
}
To see the behavior of the InstanceContext, I started the service and then started two clients with
each enumeration operation as discussed above. Here are the results :
1 - PerCall
Client 1 : urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 5 - urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 5
Client 2 : urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 5 - urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 5
Here - urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 is SessionId
Since for each client Add is called twice in the Client, and in PerCall -> new instance of InstanceContext is created every call, we create a new instance of ServiceClass for both the calls of every client. Point to note here is that new instance is created even for the same session
// First call to Add method of the Contract
client.Add(val1); -> New Instance of ServiceClass created and value will be incremented to 5
// Second call to Add method of the Contract
client.Add(val2); -> New Instance of ServiceClass created and value will be incremented to 5
2 - PerSession
Client 1 : urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 5 - urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 10
Client 2 : urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 5 - urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 10
Here the instance of ServiceClass is separate for both the client as they have different sessions running. So the increment in the calls is 0 -> 5 -> 10 (for both client separately)
3 - Single
Client 1 : urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 5 - urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 10
Client 2 : urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 15 - urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 20
Here the same instance of ServiceClass is shared by all clients so we have 0 -> 5 -> 10 in first client. The second client will increment in the same instance, so we get 10 -> 15 -> 20.
This will behave differently as per the call and may give result like when invoked at the same time from the clients.
Client 1 : urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 5 - urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 15
Client 2 : urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 10 - urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 20
Hope this helps!
I want to check the availability of the WCF web service i.c service is up or down through the C# code. How to achieve that?
When you call Client.Open if it is down that should throw an exception which you can trap.
What I prefer to do is implement a method which returns a boolean called Ping. The code basically just does return true; so it returns as quickly as possible. On the client side I call it and trap exceptions, if I get any then I know the web service is down.
You can extend the pattern to do things like PingCheckDB or PingCheckX which can do a fake/sample test run so you enable/disable functionality on the client based on what is available.
To elaborate on the previous answer: the only way to determine if a service is "available" is to first determine what you mean by "available". For instance, a service that depends on an external resource like a database may be perfectly available, but if the database cannot be accessed, then the service will be available but useless.
You should also ask what you are going to do with the information about availability. In particular, what would happen if you decided that the service was "available" yet, when you call it, you find that it is not really "available". An example would be if the above service was available and the database was available, but there was one particular stored procedure which would always fail. Is the service "available" in this case? How bad would it be if you indicated that it was available, but this one stored procedure failed?
In many cases, it's best to simply go ahead and make the calls to the web service, then handle any exceptions. If you've validated the parameters you're sending to the service, then, from the point of view of the end user, any failure of the service amounts to the service being unavailable.
It is not available to be successfully used, you see.
This is what I'm using and it works great. And ServiceController lives in namespace 'System.ServiceProcess' if you want to use a Using statement at the top to qualify it.
try
{
ServiceController sc = new ServiceController("Service Name", "Computer's IP Address");
Console.WriteLine("The service status is currently set to {0}",
sc.Status.ToString());
if ((sc.Status.Equals(ServiceControllerStatus.Stopped)) ||
(sc.Status.Equals(ServiceControllerStatus.StopPending)))
{
Console.WriteLine("Service is Stopped, Ending the application...");
Console.Read();
EndApplication();
}
else
{
Console.WriteLine("Service is Started...");
}
}
catch (Exception)
{
Console.WriteLine("Error Occurred trying to access the Server service...");
Console.Read();
EndApplication();
}
I use the following code. It's simple and works...
public bool IsServiceRunning()
{
try
{
System.Net.WebClient wc = new System.Net.WebClient();
string s = wc.DownloadString(new Uri("http://localhost:27777/whatever/services/GatherDataService?wsdl"));
}
catch (Exception ex)
{
return false;
}
return true;
}
just take your endpoint uri and add the ?wsdl