1

I am trying to send a POST request when using HttpClient. When I run the code I am getting an unauthorized response. But I am able to get it to work in PostMan. Below is my current code snippet and pictures of what I am trying to perform. I'd like to add I am trying to send a json string in my body.

using (HttpClient client = new HttpClient())
        {
            var connectionUrl = "https://api.accusoft.com/prizmdoc/ViewingSession";
            var content = new Dictionary<string, string> { { "type", "upload" }, { "displayName", "testdoc" } };
            // Serialize our concrete class into a JSON String
            var stringPayload = JsonConvert.SerializeObject(content);

            // Wrap our JSON inside a StringContent which then can be used by the HttpClient class
            var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");

            using (var httpClient = new HttpClient())
            {
                //client.DefaultRequestHeaders.Add("Acs-Api-Key", "aPsmKCmvkZHf9VakCmfHB8COmzRxXY5FDhj8F1FU1IGmQlOkfjiKESKxfm38lhey");
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Acs-Api-Key", "aPsmKCmvkZHf9VakCmfHB8COmzRxXY5FDhj8F1FU1IGmQlOkfjiKESKxfm38lhey");

                // Do the actual request and await the response
                var httpResponse =  httpClient.PostAsync(connectionUrl, httpContent).Result;

                if (httpResponse.StatusCode == HttpStatusCode.OK)
                {
                    // Do something with response. Example get content:
                    var connectionContent = httpResponse.Content.ReadAsStringAsync().Result;

                }
                else
                {
                    // Handle a bad response
                    return;
                }
            }
        }

PostMan Header Segment

PostMan Body Segment

Matthew Czajka
  • 159
  • 1
  • 2
  • 17
  • Use a sniffer like wireshark or fiddler and compare the 1st request headers between the Postman results and the c# results. One or more of the headers are different. Then make c# application headers look exactly like the postman headers. – jdweng Jan 27 '20 at 15:44
  • Could it be because your api-key's value is too short lived? i.e it expires very quickly – Moutabreath Jan 27 '20 at 15:49
  • No, the api key is not randomly generated. It is used for all api calls – Matthew Czajka Jan 27 '20 at 15:56

2 Answers2

2

You're using two HttpClients when you only need to use one.

using (HttpClient client = new HttpClient())

and

using (var httpClient = new HttpClient())

The second one (httpClient) is doing the post but the authentication header has been added to client. Just remove the second one (httpClient) and make sure you use client.PostAsync(...) to send the request.


I'd also consider using await, rather than .Result (see why here) when sending the request:

var httpResponse = await client.PostAsync(connectionUrl, httpContent);
haldo
  • 14,512
  • 5
  • 46
  • 52
  • I fixed the double httpclient(s) and still having a problem. I think it may be the source I am trying to send it. but thank you for pointing out the obvious double usage – Matthew Czajka Jan 27 '20 at 16:13
1

In addition to haldo's answer,

In your code, you are adding your Acs-Api-Key header as and Authorization header, meaning it ends up looking like Authorization: Acs-Api-Key (key) rather than Acs-Api-Key: (key) which is what you have in PostMan.

Instead of adding it as an Authorization header, just add it as a regular header.

client.DefaultRequestHeaders.Add("Acs-Api-Key","(key)");

Also something else that may cause issues is that you aren't wrapping your content in the "source" object like you are in PostMan. There are a couple ways of doing this

The first would be to simply wrap it in it's string format:

stringPayload = $"\"source\":{{{stringPayload}}}"

Or you can do it before you serialize by making your own object instead of having a Dictionary

var content = new PayloadObject(new Source("upload", "testdoc"));
var stringPayload = JsonConvert.SerializeObject(content);

// Send the request

class PayloadObject{
    Source source {get; set;}
    PayloadObject(Source source){
        this.source = source;
    }
}
class Source{
    string type {get; set;}
    string displayName {get; set;}
    Source(string type, string displayName){
        this.type = type;
        this.displayName = displayName;
    }
}
Jesse
  • 1,386
  • 3
  • 9
  • 23
  • I wasn't totally sure which header to use in the code, as you can see I commented out what you suggested. – Matthew Czajka Jan 27 '20 at 16:08
  • Yes I did notice that. I just wanted to clarify. The other problem is mentioned in @haldo's answer. *You're using two `HttpClient`s* where one has your header, and the other one doesn't. You are using the one without the header to send the request. – Jesse Jan 27 '20 at 16:11
  • I fixed that as well. I think it may be about the source object. I am working on getting that right now to see if it works – Matthew Czajka Jan 27 '20 at 16:12
  • After making all the changes, I now get a error "server committed a protocol violation. Section=ResponseStatusLine" after doing research into the error, I added a segment in web.config to useUnsafeHeaderParsing to true and it still doesn't work. Any idea what the problem here could be? – Matthew Czajka Jan 27 '20 at 19:25