Call Dynamics Web API in C# Plugin - c#

I have a Business Process Flow in Microsoft Dynamics to handle creation of a new client. When the process finishes, I am attaching a workflow that kicks of an action which calls a plugin to do some custom processing. I am following this article to set up this process.
In my plugin, I have a call to the Dynamics Web API (see code below). When I hit the responseMessage = client.GetAsync(url).Result; line, my plugin exits without returning an error. When I am debugging in the Plugin Registration Tool, the Plugin Registration Tool crashes and has to be restarted. When I look at the network traffic, this call appears to be failing with a 401 - Unauthorized error.
When I try this same HttpClient call from a console app, the call succeeds. I've tried a few different credentials for authentication without success. I've also tried calling the GetAsync function a few different ways. Is this error related to the async or authentication methods? What am I missing here?
HttpClient client = new HttpClient(new HttpClientHandler() { Credentials = new NetworkCredential("admin", "password", "DOMAIN") });
client.BaseAddress = new Uri(Helpers.GetSystemUrl(COHEN.APIConnector.Application.Dynamics));
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
client.DefaultRequestHeaders.Add("OData-Version", "4.0");
HttpResponseMessage responseMessage;
string url = "ccseq_clients";
responseMessage = client.GetAsync(url).Result;
Update
We are using Dynamics 2016 On-Premise.
The reason we are using the Web API is that this call occurs in a library we have developed that will interface between multiple systems. The library is used within a plugin, but can also be used outside of a plugin for other applications. The code sample we provided is the chunk of code that is failing in the library. We pulled the chunk of code directly into the plugin to see if the error was related more to the library or the plugin.
We noticed that the client.GetAsync(url).Result call was actually returning a correct value. We missed seeing in our network traffic that two calls failed before a third succeeded and returned the correct value (See screenshot below). The odd thing is that when we debug this line of code, stepping over the line of code causing the Plugin Registration Tool to crash while the network traffic shows we returned the correct values. If we set a breakpoint after this line of code, then the Plugin Registration Tool does not crash and we have a correct value in our response. This behavior changes when we went back to debugging in the library rather than directly in the plugin. In the library, the Plugin Registration Tool always crashes when hitting this line regardless of where we set our breakpoints even though the network traffic still shows a successful response.
Update 2
It would appear that my library is successfully making multiple different calls to the Web API so I'm thinking the issue is more that the Plugin Registration Tool can't handle the Web API call more than the call not actually working.

I believe the issue was with the Plugin Registration Tool profiling a plugin execution. My follow up question is here.

This blog states that we can make Web Api work in CRM on-premise (non-IFD) plugin by using WebClient with DefaultCredentials.
using (WebClient client = new WebClient())
{           
client.UseDefaultCredentials = true;
    byte[] responseBytes = client.DownloadData(new Uri("<your web api url>/accounts(3C2D2712-E43F-E411-9402-005056AB452C)"));
    string response = Encoding.UTF8.GetString(responseBytes);
    // parse the json response
}
Make sure you specify the UseDefaultCredentials as true to make the web api call under the context of the user the plugin is running.
We may struggle more with Online plugins because of Sandbox + Adal library + AAD tokens combo as we are trying in a non-interactive plugin code unlike other interface where we can challenge the user by prompt.
Moreover Web api is more useful for cross platform, outside CRM context integration. Inside the platform execution you can use Org service to achieve more.

Related

C# calling a webservice result in 401

I'm trying to call a simple web service to get long and lat of an address, which works when I try it manually :
https://services.gisgraphy.com/geocoding/?address=paris
But with the code, I get 401 unauthorize.. What am I doing wrong ?
WebRequest request = WebRequest.Create("https://services.gisgraphy.com/geocoding/?address=paris");
request.Credentials = CredentialCache.DefaultCredentials;
request.Method = "GET";
WebResponse response = request.GetResponse(); // It happens here.
What am I doing wrong?
You haven't read the big blue bar on top of the website belonging to the API you're calling:
Gisgraphy is open sources and only use open data. This server is for demonstration only. Test it, Play with webservices but then Install Gisgraphy locally or subscribe to premium hosted services
So they're probably detecting that you're calling their API from outside their playground, and are denying you to do so.
So, either install it locally, or subscribe to their hosted services. The latter probably gives you an API key that allows you to make API calls.
Of course you can fake your way around this by imitating that your request comes from a browser, for example with User-agent and Accept headers, but surely they'll try and detect this and block your IP address entirely. Just pay up, or host it locally.
Few things on this question :
Check if the URL/web-service is directly accessible via
browser/postman tool.
Secondly , as one of my fellow friend there mentioned this
web-service has some security protocol. May be its not allowing
requests from outside (i.e. other than its domain to come in)
Once you drill down the above two possibility ,you should be in a good shape to move ahead.

HttpClient.SendAsync call results in multiple triggers on service side, returns internal server error

I have an ASP.NET Web API deployed on Azure App service.
I am experiencing following error: For one specific business object my Web API's GET method is returning Internal server error, while for other business objects the same GET method is working fine.
When I debugged my Web API it turned out, that valid business object is returned, but… GET method was triggered multiple times (and on client side I see that it is called only once)
This is an excerpt where Web API is called from client code
// Create HTTP transport objects
HttpRequestMessage httpRequest = new HttpRequestMessage();
httpRequest.Method = HttpMethod.Get;
httpRequest.RequestUri = new Uri(url);
// Set Credentials
if (this.Credentials != null)
{
cancellationToken.ThrowIfCancellationRequested();
await this.Credentials.ProcessHttpRequestAsync(httpRequest, cancellationToken).ConfigureAwait(false);
}
HttpResponseMessage httpResponse = await this.HttpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
Besides - if I try to open that same url from browser (e.g.: https://myservice.com/api/businessObject/xxx) - request is performed only once (as it should) and correct results (Json) is displayed in browser.
Any suggestions what to try to figure why call from client side (for specific object) results in multiple Web API service executions and how to fix this?
My Web API service is deriving from System.Web.Http.ApiController
I got some information from exception, but it doesn't seem to be very helpful
Exception thrown: 'Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException' in Microsoft.Rest.ClientRuntime.dll The thread 0x27fc has exited with code 0 (0x0)
EDIT
I got some information from Azure Log stream, but that information does not seam to make sense… because this problem happens for one specific business object (and only when requested from my application - not failing from web browser), other business objects are working fine so I don't see how this could be related to access / web.config file...
IIS was not able to access the web.config file for the Web site or application. This can occur if the NTFS permissions are set incorrectly.
IIS was not able to process configuration for the Web site or application.
The authenticated user does not have permission to use this DLL.
..
Ensure that the NTFS permissions for the web.config file are correct and allow access to the Web servers machine account.
Check the event logs to see if any additional information was logged.
Verify the permissions for the DLL.
Install the .NET Extensibility feature if the request is mapped to a managed handler.
Create a tracing rule to track failed requests for this HTTP status code

HTTP Request in Xamarin.Forms

I'm building a Xamarin.Forms App for Android and iOS which is supposed to consume an API. The API is kind of built in a REST spirit, I'm hosting the API on a local IIS Express server and my Android emulator has no problem finding it (tested on various endpoints and I can also display the api-doc).
I'm trying to get in touch with a http://IPOfMyComputer/api/Stuffs endpoint which gives me a JSON list of Stuff. Using Postman I successfully get all the stuff I needed, a valid auth token in that case, to build a proper HTTP GET request. I'm using the Microsoft.Net.Http NuGet package to build this request as it seemed to be the proper tool to do the job. I'm doing this request building process in Xamarin.Forms "Main" project (not the iOS or Android one, the other one which I don't know how to name which is automatically by Visual Studio).
My code looks like this:
var rootUri = "http://IPOfMyComputer"
var requestedUri = "/api/Stuffs"
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
"blablabla");
var response = await client.GetAsync(rootUri + requestedUri);
And this gives me an error "NotSupportedException" on the last instruction.
I'm clueless here so some help would be really appreciated.
Edit
The proper error message is
"System.InvalidCastException: Specified cast is not valid."
I found the source of that error:
Turns out it wasn't directly linked with the GetAsync method but with some mess in the code related with async/await use.
There was a bunch of crappy code everywhere. I dropped it all to go back to a regular MVVM logic and I put the async/await logic into methods invoked by eventhandlers (instead of trying to "create" an async builder for a class...).

Receiving BAD REQUEST when called Okta API from C# MVC application

I am creating a sample application (i.e., a proof of concept) for creating users with the Okta platform. I am using API calls but consistently receiving "BAD REQUEST" when running the C# MVC application from Visual Studio 2013 update 5 to my Okta development instance. I'm wondering if the problem is between CORS and a local app?
Here is what I have so far:
Tested out the API calls using Postman to my dev environment and the calls work (i.e., users get created in my Okta dev admin environment)
Created an API Token and call it with a prefix of "SSWS" in the Authorization header
Using an HttpClient and .PostAsJsonAsync() method to make the API call
My application code works as expected when calling a GET with the API call /api/v1/users?limit=25 and .GetAsync()
Using the following Api call: /api/v1/users?activate=false (create a user with password; this works in Postman, but not in the MVC app)
Used http://json2csharp.com/ to create C# classes that conform to Okta's JSON hierarchy (obtained from Okta's Postman API libraries)
Using the classes above, the JSON displayed in Visual Studio's Text Viewer (obtained while stepping through the code) works with a POST call when pasted into Postman
HttpResponse contains the error message "The request body was not well-formed"
Here is the code used for creating and serializing (with Json.NET) the C# classes:
RootObject root = new RootObject();
root.profile = new Profile();
root.profile.firstName = model.FirstName;
root.profile.lastName = model.LastName;
root.profile.email = model.Email;
root.profile.login = model.UserName;
root.credentials = new Credentials();
root.credentials.password = new OktaTest.Models.Password();
root.credentials.password.value = model.Password;
string rootJson = JsonConvert.SerializeObject(root);
This produces the following JSON (this contains dummy data):
{"profile":{"firstName":"Test","lastName":"User","email":"user#test.org","login":"user#test.org"},"credentials":{"password":{"value":"Testing123"}}}
Here is the line of code that makes the POST call:
HttpResponseMessage responseMessage = await client.PostAsJsonAsync(url, rootJson);
Here is the line that sets the Accept header:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Since I'm able to use the JSON in Postman, and since that JSON comes out as valid when using JSONLint, I'm thinking that the problem is not with the JSON but something around security between my local app and the development environment. Should this test only be run from a hosted application so that a site can be explicitly assigned in the CORS section of the Okta admin environment? At this point, and I'm still researching and experimenting, I'm not sure what I'm missing, but I think I'm close.
Any advice or guidance would be greatly appreciated! Thank you!
I recommend you to use the Okta C# SDK which you can add to your application using the Okta.Core.Client NuGet package.
A sample console app shows how to use it to create Okta users: https://github.com/oktadeveloper/okta-sdk-dotnet-console-user-create
I hope this helps!

Integrate a C# client into a node.js + socket.io chat app

As part of learning node.js, I just created a very basic chat server with node.js and socket.io. The server basically adds everyone who visits the chat.html wep page into a real time chat and everything seems to be working!
Now, I'd like to have a C# desktop application take part in the chat (without using a web browser control :)).
What's the best way to go about this?
I created a socket server in nodejs, and connected to it using TcpClient.
using (var client = new TcpClient())
{
client.Connect(serverIp, port));
using (var w = new StreamWriter(client.GetStream()))
w.Write("Here comes the message");
}
Try using the HttpWebRequest class. It is pretty easy to use and doesn't have any dependencies on things like System.Web or any specific web browser. I use it simulating browser requests and analyzing responses in testing applications. It is flexible enough to allow you to set your own per request headers (in case you are working with a restful service, or some other service with expectations of specific headers). Additionally, it will follow redirects for you by default, but this behavior easy to turn off.
Creating a new request is simple:
HttpWebRequest my_request = (HttpWebRequest)WebRequest.Create("http://some.url/and/resource");
To submit the request:
HttpWebResponse my_response = my_request.GetResponse();
Now you can make sure you got the right status code, look at response headers, and you have access to the response body through a stream object. In order to do things like add post data (like HTML form data) to the request, you just write a UTF8 encoded string to the request object's stream.
This library should be pretty easy to include into any WinForms or WPF application. The docs on MSDN are pretty good.
One gotcha though, if the response isn't in the 200-402 range, HttpWebRequest throws an exception that you have to catch. Fortunately you can still access the response object, but it is kind of annoying that you have to handle it as an exception (especially since the exception is on the server side and not in your client code).

Categories

Resources