简体   繁体   中英

C# consume a web api with multiple http POST requests

So I have 2 http Post requests consuming a web api as follow:-

using (var client = new HttpClient())
{
   client.BaseAddress = new Uri("https://your_url.com:8443/");
   client.DefaultRequestHeaders.Accept.Clear();
   client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

   // 1st request //
   var datatobeSent = new ApiSendData()
    {
        UserID = "xxx",
        UserPsw = "yyy",
        ApiFunc = "zzz",
        clearData = "x1y1z1"
    };

    HttpResponseMessage response = await client.PostAsJsonAsync("WebApi", datatobeSent);
    var resultData = await response.Content.ReadAsStringAsync();


   #region Extract Secured Data response from WebApi

   JObject JsonObject = JObject.Parse(resultData);
   datatobeSent.SecureData = (string)JsonObject["SecureResult"];

   #endregion


   // 2nd request //
   var datatobeSent2 = new ApiSendData()
   {
     UserID = "xxx",
     UserPsw = "yyy",
     ApiFunc = "zzz",
     SecureData = datatobeSent.SecureData
   };

   HttpResponseMessage response2 = await client.PostAsJsonAsync("WebApi", datatobeSent2);
   var resultData2 = await response2.Content.ReadAsStringAsync();

}

So now I need some clarifications...

1) Are both my http POST requests sent over the same SSL session ?

2) If they are not, then how can I combine the two and send the 2 requests over a single connections/session ?

3) How may I improve performance of this code? currently 100 requests take 11secs to process and respond. ( i just used a for loop that counts 100 http post requests for the above 2 samples)

They are over the same SSL session and connection. The same HttpClient instance shares some configurations and underlying TCP connections. Therefore, you should reuse the same instance, which you are already doing with the using statement.

I would try to improve the performance of your code by asynchronously making the post requests and processing the results. Here's an option:

Create a new class to handle these async requests

public class WebHelper
{
   public async Task<string> MakePostRequest(HttpClient client, string route, object dataToBeSent)
   {
      try{
            HttpResponseMessage response = await client.PostAsJsonAsync(route, datatobeSent);
            string resultData = await response.Content.ReadAsStringAsync();
            return resultData;
      }
      catch (Exception ex){
         return ex.Message;
    }
  }
}

Notice that the same httpClient instance is being used. In the main code, you could test your performance like this (to simplify our test, I'm just making the post request with the same parameters 101 times):

//Start time measurement
List<Task> TaskList = new List<Task>();
for (int i = 0; i < 100; i++)
{
  Task postTask = Task.Run(async () =>
  {
     WebHelper webRequest = new WebHelper();
     string response = await webRequest.MakePostRequest(client, "WebApi", dataToBeSent);
     Console.WriteLine(response);
  });
  TaskList.Add(postTask);
}
Task.WaitAll(TaskList.ToArray());
//end time measurement

And just an improvement for your code: use try/catches to make the requests!

While HttpClient will aim to use the same Ssl session and connection, this cannot be guaranteed as it depends on the server also maintaining the session and connection. If the server drops them, HttpClient will renegotiate new connections and sessions transparently.

That said, while there is some overhead from connection and ssl session establishment, it's unlikely to be the root cause of any performance issues.

Given the simplicity of your code above, I strongly suspect that the performance issue is not in your client code, but in the service you are connecting to.

To determine that, you need to isolate the performance of that service. A few options for how to do that, depending on the level of control you have over that service:

  1. If you are the owner of that service, carry out over the wire performance testing directly against the service, using a tool like https://www.blitz.io/ . If 100 sequential requests from blitz.io takes 11 seconds, then the code you have posted is not the culprit, as the service itself just has an average response time of 110ms.
  2. If you are not the owner of that service, use a tool like Mountebank to create an over the wire test double of that service, and use your existing test loop. If the test loop using Mountebank executes quickly, then again, the code you have posted is not the culprit. (Mountebank supports https, but you will need to either have the keypair, or use their self-signed cert and disable certificate verification in your client.)

It's worth noting that it's not unusual for complex web services to take 110ms to respond. Your test appears to be doing a sequential series of requests - one request at a time - most web services are optimised around handling many requests from independent users in parallel. The scalability challenge is in terms of how many concurrent users can I service while still ensuring that the average response time is 110ms. But if only a single user is using the service at a time, it will still take ~110ms.

So - an even earlier validation step you could take is to work out if your test of 100 sequential requests in a loop is a valid representation of your actual performance requirements, or if you should call your method 100 times in parallel to see if you can have 100 concurrent users access your service.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM