1

The following is the code from where I would return a tuple of response status code and response output.

private Tuple<int, string> API_Check(string URL, string reqtype, string reqbody, string split_username, string split_pwd)
    {
        string responsetxt="";
        HttpResponseMessage httpresult = new HttpResponseMessage();
        int statuscode = 0;
        ServicePointManager.Expect100Continue = true;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
        ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
        HttpClient _httpClient = new HttpClient();
        var authString = Convert.ToBase64String(Encoding.UTF8.GetBytes(split_username+":" + split_pwd));
        _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authString);
        try
        {
            using (var content = new StringContent(JsonConvert.SerializeObject(reqbody)))
            {
                if (reqtype == "GET")
                {
                    httpresult = _httpClient.GetAsync(URL).Result;
                }
                if (reqtype == "PUT")
                {
                    httpresult = _httpClient.PutAsync(URL, content).Result;
                    //httpresult = _httpClient.PutAsync()
                }
                if (reqtype == "POST")
                {
                    httpresult = _httpClient.PostAsync(URL, content).Result;
                }

                statuscode = (int)httpresult.StatusCode;
                responsetxt = httpresult.Content.ReadAsStringAsync().Result;
                return Tuple.Create(statuscode, responsetxt);
            }
        }
        catch (System.Net.WebException Excptn)
        {
            statuscode = 401;
            responsetxt = Excptn.Status.ToString();
            using (var stream = Excptn.Response.GetResponseStream())
            using (var reader = new StreamReader(stream))
            {
                MessageBox.Show(reader.ReadToEnd());
            }
        }
        return Tuple.Create(statuscode, responsetxt);
    }

For some reason, the request body is not getting filled correctly during the call. I'm getting 401 Unauthorized as for this Post call, which is definitely not a authorization error as the response message that I receive is equivalent to empty body or invalid input json format.

When I tried to hit the same reqbody for the endpoint with Postman, I'm getting 200 with valid response. Also, the GetAsync works for a similar API which doesn't require a body.

I verified there is no issues with the username, password or the Endpoint URL.

Is there a way, I could avoid using httpcontent and use the string as it is for hitting the API through C#?

Now, I could not use HttpWebRequest due to my current .Net framework limitations.

9
  • 2
    ReadAsStringAsync().Result; <-- Why aren't you using await? Commented Sep 22, 2022 at 20:14
  • Are you maybe missing some of the required extra headers? Commented Sep 22, 2022 at 20:22
  • @JHBonarius, Not much use. I replaced content with this and still getting the same error...... using (var content = new StringContent(JsonConvert.SerializeObject(reqbody), null, "application/json")) Commented Sep 22, 2022 at 20:33
  • Your status code is overwritten when it gets to catch block. Try to comment out this block and see the actual response status code. Commented Sep 22, 2022 at 20:37
  • Did you catch any exceptions? Commented Sep 22, 2022 at 20:39

1 Answer 1

0

There are many issues with your code:

  • Primarily, you are serializing reqbody which is already a string. It sounds like you have a JSON string already, in which case you don't need to serialize it.
  • Don't use .Result, it can cause a deadlock. use await instead.
  • Use Valuetuples instead of Tuple, which can be inefficient.
  • Do not set ServicePointManager.SecurityProtocol = ..., instead let the operating system choose the best security protocol.
  • Do not use ServicePointManager in general, as it affects all HTTP request from your app. Instead set the relevant HtppClient property, or better: use HttpRequestMessage and set it directly on the message.
  • You can simplify the code a bit if you use HttpRequestMessage, giving it the type of HTTP method
  • You are catching the wrong exception type. You should be catching HttpRequestException, from which you can get the actual StatusCode.
  • HttpClient by default does not throw on non-success codes. You need to handle them explicitly.
  • Cache the HttpClient, or you could get socket exhaustion.
  • Creating a new HttpResponseMessage doesn't make a huge amount of sense.
HttpClient _httpClient = new HttpClient {
    DefaultRequestHeaders = {
        ExpectContinue = false,
    },
};

private async Task<(int, string)> API_Check(string URL, HttpMethod reqtype, string reqbody, string split_username, string split_pwd)
{
    var authString = Convert.ToBase64String(Encoding.UTF8.GetBytes(split_username + ":" + split_pwd));
    try
    {
        using (var content = new StringContent(reqbody))
        using (var request = new HttpRequestMessage(URL, reqtype))
        {
            message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authString);
            if (reqtype != "GET")
                message.Content = content;

            using var httpresult = await _httpClient.SendAsync(URL, content);
            var statuscode = (int)httpresult.StatusCode;
            var responsetxt = await httpresult.Content.ReadAsStringAsync();
            if (!httpresult.IsSuccessStatusCode)
                MessageBox.Show(responsetxt);

            return (statuscode, responsetxt);
        }
    }
    catch (HttpRequestException ex)
    {
        var statuscode = ex.StatusCode ?? 0;
        var responsetxt = ex.Message;
        MessageBox.Show(responsetxt);
        return (statuscode, responsetxt);
    }
}

If you actually have an object to serialize then change the method to

private async Task<(int, string)> API_Check(string URL, HttpMethod reqtype, object reqbody, string split_username, string split_pwd)
{
....
....
        using (var content = new StringContent(JsonConvert.SerializeObject(reqbody)))
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.