1

I am trying to figure out what I can do (logging, things to check) before having to read server logs as I don't want to miss something stupid before requesting that.

Here is my code:

const string URL = "https://SomeURL/api/security/";
string urlParameters = string.Format("grant_type=password&username={0}&password={1}", username, password);
StringContent content = new StringContent(urlParameters, Encoding.UTF8, "application/x-www-form-urlencoded");

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11;

HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
StringContent content = new StringContent(urlParameters, Encoding.UTF8, "application/x-www-form-urlencoded");

var tokenResponse = client.PostAsync("token", content).Result;

I am a little newer to this so I'm not sure what to check next but have tried the same request using postman and get a response with my token so it looks like I am missing something or maybe formatting something incorrectly?

Pittfall
  • 2,751
  • 6
  • 32
  • 61
  • A 500 error is the fault of the server, not the client. If the client does something wrong, the server should return a 4xx error. So there might be a problem in your request, but since the server doesn't handle it properly, you can't know what it is. So you *have* to look at the server logs. – Thomas Levesque Apr 10 '17 at 14:45
  • @ThomasLevesque, I got a successful response using postman which is why I thought I'd post the question, to see if there;s something obvious I am missing. But yeah, if nothing stands out to anyone, I will have to request them like you said. – Pittfall Apr 10 '17 at 14:48
  • 1
    Try using `FormUrlEncodedContent` rather than `StringContent`: https://gist.github.com/thomaslevesque/8f9f21c7153122a1f509f27ee1fabf80. – Thomas Levesque Apr 10 '17 at 15:13
  • 2
    Also, keep in mind that Postman implicitly sends other headers, such as `User-Agent`, `Cookie`, `Accept-Language`, etc. Maybe the server is expecting those headers. – Thomas Levesque Apr 10 '17 at 15:14
  • @ThomasLevesque, thanks for your reply's. I was actually looking for ideas on what I can try and that is exactly how you answered so that is much appreciated. You helped me realise that I did not URL encode my parameters and the server was expecting it. Thanks! – Pittfall Apr 11 '17 at 16:29

2 Answers2

2

I was following an online course, and the code for setting the URL parameters were set like this:

public async Task<AuthenticatedUser> Authenticate(string userName, string password)
    {
        var data = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("grant_type", "password"),
            new KeyValuePair<string, string>("username ", "userName"),
            new KeyValuePair<string, string>("password", "password")
        });

        using (HttpResponseMessage response = await apiClient.PostAsync("/Token", data))
        {
            if (response.IsSuccessStatusCode)
            {
                var result = await response.Content.ReadAsAsync<AuthenticatedUser>();
                return result;
            }
            else
            {
                throw new Exception(response.ReasonPhrase);
            }
        }
    }

When testing, found that 500 error was being returned for the PostAsync call. I checked my URL address and parameters and they all looked correct. If I tested in Swagger, then I received a 200 status and token was shown.

Following the link by Thomas Levesque I changed how the data variables were set to :

var data = new FormUrlEncodedContent(new Dictionary<string, string>
        {
            ["grant_type"] = "password",
            ["username"] = username,
            ["password"] = password
        });

Now the response status is 200 and the AuthenticatedUser model is populated correctly. However I couldn't understand why Dictionary seem to work and KeyValuePair didn't. So I created the list and then encoded it:

       var dataList = new[]
        {
            new KeyValuePair<string, string>("grant_type", "password"),
            new KeyValuePair<string, string>("username", username),
            new KeyValuePair<string, string>("password", password)
        };

        var content = new FormUrlEncodedContent(dataList);

        using (HttpResponseMessage response = await apiClient.PostAsync(requestUrl, content))

This also worked. I freely admit that I do not fully understand why.....yet.

0

I did not URL encode my parameters, here's the fix (probably a better way of doing it).

string urlParameters = string.Format("grant_type=password&username={0}&password={1}", Uri.EscapeDataString(username), Uri.EscapeDataString(password));
Pittfall
  • 2,751
  • 6
  • 32
  • 61
  • Using `FormUrlEncodedContent` as I suggested in my comment takes care of encoding the values. – Thomas Levesque Apr 11 '17 at 16:32
  • @ThomasLevesque I did comment that your comment was what helped me get here. I did not use FormURLEncodedContent because the object is a little bit more bulky. Still a good solution. – Pittfall Apr 20 '17 at 11:52