1

I have this small Python application that I wrote last year that I need to remake in C#. I don't really know C#, but need to make a connection between Dynamics 365 and QuickBooks Desktop which uses C# (or C++, Java, VB... none of which I know).

As I said, the Python app works fine, and I get what I need from D365 via Postman, put having a hell of time getting it working for C#. There is a sample project here, but trying to interpret what is going on is making my head spin (it doesn't run either otherwise I'd just use it).

This is what I currently do:

class Program
{
    static void Main(string[] args)
    {
        ConnectToCRM();
    }

    static void ConnectToCRM()
    {
        string crmOrg = "https://company.api.crm.dynamics.com";
        string clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
        string clientSecret = "super_secret_stuff";
        string username = "me@company.biz";
        string userPassword = "password";
        string authorizationEndPoint =
            "https://login.windows.net/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/oauth2/authorize";
        string crmWebApi = "https://company.api.crm.dynamics.com/api/data/v8.2";

        var values = new Dictionary<string, string>
            {
                {"client_id", clientId},
                {"client_secret", clientSecret},
                {"resource", crmOrg},
                {"oauthUrl", authorizationEndPoint},
                {"username", username},
                {"password", userPassword},
                {"grant_type", "password"}
            };

        HttpRequestToCrm(values);
    }

    public class ServerResponse
    {
        public string token_type { get; set; }
        public string scope { get; set; }
        public string expires_in { get; set; }
        public string ext_expires_in { get; set; }
        public string expires_on { get; set; }
        public string not_before { get; set; }
        public string resource { get; set; }
        public string access_token { get; set; }
        public string refresh_token { get; set; }
    }

    static async void HttpRequestToCrm(Dictionary<string, string> values)
    {
        string tokenEndPoint = "https://login.windows.net/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/oauth2/token";

        var client = new HttpClient();

        var content = new FormUrlEncodedContent(values);

        try
        {
            HttpResponseMessage response = await client.PostAsync(tokenEndPoint, content);
            var responseContent = await response.Content.ReadAsStringAsync();

            Console.WriteLine(response);
            Console.WriteLine(responseContent);

            ServerResponse rb = JsonConvert.DeserializeObject<ServerResponse>(responseContent);

            Console.WriteLine(rb.token_type);
        }
        catch (WebException e)
        {
            Console.WriteLine("catch");

            Console.WriteLine(e);
            throw;
        }
    }
}

As I understand it I need to be using FormUrlEncodedContent for x-www-form-urlencoded, as x-www-form-urlencoded is what I have to do in Postman for it to work. Python just seems to be doing it.

Console.WriteLine(content); just says System.Net.Http.FormUrlEncodedContent. The Console.WriteLine(response); actually has something in it now, where it didn't before: System.Threading.Tasks.Task1[System.Net.Http.HttpResponseMessage]. I need to get the response body, so that I can get theaccess_token` and then finally actually query the D365 web API.

How do I get the response body and the access_token? How do I even see that that is what it is responding with? Is my approach entirely wrong?

EDIT:

Whether or not I do:

HttpResponseMessage response = await client.PostAsync(tokenEndPoint, content);

Or:

var response = await client.PostAsync(tokenEndPoint, content);

Visual Studio Community 2017 quits running at that line and doesn't trigger any kind of error. I'll sent a break point there, then F10 or F11, and it exits the program.

Found this regarding it:

Code Execution stops with no error

Turned on all the options, but still can't see why it is just ending.

This is a screenshot of what I'm trying to do working in Postman. I'm obviously just doing something wrong in C#.

enter image description here

cjones
  • 8,384
  • 17
  • 81
  • 175

2 Answers2

1

Couple things right off the bat, you aren't awaiting your PostAsync call so you don't really have the response stored.

Second, C# doesn't automatically serialize objects like that when you tell it to write to the console so it is just telling ou what kind of object it is, aka a task that is wrapping an HttpResponseMessage.

The following should get you the response body (assuming it is just the token this will work fine for you). You'll need to modify it some to work perfectly for you, but this should get you started.

try
{
    var response = await client.PostAsync(tokenEndPoint, content);
    //read the response body as a string here
    string token = await response.Content.ReadAsStringAsync();
    Console.WriteLine(response);

}
catch (WebException e)
{
    Console.WriteLine("catch");

    Console.WriteLine(e);
    throw;
}
Matti Price
  • 3,351
  • 15
  • 28
1

Try this to get the Content of the Response:

HttpResponseMessage response = await client.PostAsync(tokenEndPoint, content);

if(!response.IsSuccessStatusCode) return; // optional

string responseContent = await response.Content.ReadAsStringAsync();

First of all you need to await the PostAsync() call. Since this only leaves you with a HttpResponseMessage then and not the actual content of the response, you'd have to get it in a second step by reading the response's Content Property as a string.

If your Response returned an OK (HTTP 200 Status Code) this code should leave you with responseContent holding the desired response as a string.

I assume that your access_token is a JSON Property in this received string, so you would have to then deserialize it or use a extracting mechanism to get the actual access_token from said string. There are already plenty of posts on StackOverflow regarding this, so i won't elaborate on it any further.

Tobias Tengler
  • 6,848
  • 4
  • 20
  • 34
  • Hi, thanks. I have updated my question based on testing your suggestion. – cjones Dec 11 '18 at 22:16
  • 1
    @sockpuppet Just a quick heads up, you're doing this in a console right? The Console will close/the process end once the code block in the `Main` method is finished. SInce `ConnectToCRM` calls the async method `HttpRequestToCrm` the code in `Main` finishes before the async method finishes. So your process shuts down before your async method is completed. Adding a `Console.ReadLine();` after the `ConnectToCRM();` call should keep the console open/the process running. Let me know if this was the issue! – Tobias Tengler Dec 11 '18 at 22:51
  • Hey, there it is! Everything I was trying to get. Thanks for the help! – cjones Dec 11 '18 at 23:02
  • @sockpuppet no problem :) Most of the times the issue lies in places we least expect it! – Tobias Tengler Dec 11 '18 at 23:03