HTTP Request in Xamarin.Forms - c#

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...).

Related

How to use the AWSSDK.AppSync .net Core NuGet package to perform mutations and query data?

I want to send chat messages using AppSync from a .net Core backend, using the nuget package AWSSDK.AppSync. But I Can't find any guide or sample code to do so.
I'm trying to code something similar to the AWS mobile sample application AppSync Chat Starter Angular. The goal is to have a conversation between the user (on a browser) and my backend. There are many samples for iOS, Android, web and react native, where I could find some clues on how to do it, but couldn't manage to get it working in .net core. The best documentation I've found so far is the official Amazon.AppSync API but there you'll find only classes and fields descriptions, not sample code.
I have that Angular AppSync Chat sample app running fine. I did manage to run the React sample app too. Everything goes smoothly with those. However I'm unable to fully understand what's going on only by reading the angular and react sample code, especially because I'm not proficient on those.
Would be great to have a sample code on how to initialise the AmazonAppSyncClient, run some queries, perform some mutations, subscribe/unsubscribe and set background tasks.
AWSSDK.AppSync Is just for managing AppSync, to query GraphQl server provided by AppSync you need GraphQL.Client.
Ok, so here is a little snippet for how to setup client and do a simple query.
Setup client.
Install GraphQL client library, for example from NuGet (works also in Unity),
you need these things:
using GraphQL;
using GraphQL.Client.Http;
using GraphQL.Client.Serializer.Newtonsoft;
using GraphQL.Client.Abstractions;
Then initialize your client like this:
var client = new GraphQLHttpClient("your_graphql_endpoint_url", new NewtonsoftJsonSerializer());
Optionally, you may want to add authentication or api key headers, here is example of how to add authorization token (notice, there is no "Bearer " word in it, just the token)
client.HttpClient.DefaultRequestHeaders.Add("Authorization", "your_long_token_string");
Now about how to do a simple query. Here is an example for listing items query, create request:
var request = new GraphQLRequest
{
Query = #"
query MyQuery {
listItems {
items {
id
ItemName
}
}
}"
};
Send request:
var request = await _client.SendQueryAsync(request, () => new
{
listItems = new
{
items = new List<Your_Item_Type>()
}
});
Your_Item_type[] items = request.Data.listItems.items.ToArray();
Check the official repository for the client here: https://github.com/graphql-dotnet/graphql-client

Call Dynamics Web API in C# Plugin

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.

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!

Why does HttpClient.PostAsync fail to return in a WPF environment?

I have a piece of code that loads data from a web service :
client = new HttpClient(handler) {Timeout = TimeSpan.FromSeconds(60)};
var post = await client.PostAsync(url, new FormUrlEncodedContent(parameters));
When I run this in the stand-alone applications - one of which is WPF, the other is WinForms - this works perfectly OK.
However, I also have a version of this embedded in a larger WPF application. In both cases, when the embedded version is used, the application hangs on the post line.
I have checked at the web service end, and on fiddler, and it is definitely sending the request, and the response is being returned. It seems as if the PostAsync is just not getting the returned response, and so not being able to progress. Is there something I need to do to enable this to function?
All of the HTTP request and response looks fine, so I don't think it is anything to do with that. It is just the capture of this response.
I had a similar problem recently, and it was solved by using ConfigureAwait(false), like this:
var post = await client
.PostAsync(url, new FormUrlEncodedContent(parameters))
.ConfigureAwait(false);

HTML message or login pages intercepting web service requests

I am busy working on a mobile application that retrieves data from a web service.
Ofcourse everything is working perfectly, I get everything I need to and I can consume the services without much effort... on the emulator.
However, when I move over to testing this application on the device, instead of getting back the data that I am expecting I am getting a website returned. How am I supposed to handle this?
Currently I am using this to call my service: (using system.net - I dont know if this is what I should be using on windows phone 7 either)
WebClient proxy = new WebClient();
string strURI = "http://www.google.co.za";
proxy.OpenReadCompleted +=
new OpenReadCompletedEventHandler(proxy_openreadcompleted);
proxy.OpenReadAsync(new Uri(strURI));
Please note: I am not really calling google, it is just an example. So anyways I am expecting my JSON to be returned, instead I am getting a message from the service provider to change mobile options... I can put this into isolated storage and render it with a browser, however I do not know what the source of the message is so when you click on a button, the forms use relative URLs, so instead of it doing what it is intened to do I just see what it is trying to call.
Is there anyway to get the source of the response? I am looking for a source like http://vodafonelive.mobi/ or something like that. If someone can tell me what to do I would greatly appreciate it, my current thinking is that if I can identify the source I can create a webbrowser task so that my application does not need to handle this, however... since I am calling a specific source I don't know how to identify where the response is comming from.
Any help is appreciated.
This is most likely due to differences in the user agent of the emulator and the device. Check what is sent or set this explicitly to ensure that the 2 behave in the same way. To ensure the server doesn't try and redirect to a different location.
Alternatively, it could be a mobile operator proxy being "helpful" and adjusting the request that goes over their network.
Ok so after spending some time on this, I finally found a way that I could get a response uri (where the response was comming from) by using another method to do the call to the service:
So basically this is the call:
WebRequest request = HttpWebRequest.Create(strURI);
var result = (IAsyncResult)request.BeginGetResponse(ResponseCallback, request);
So in the function ResponseCallBack function I do something like this:
WebRequest request = (HttpWebRequest)result.AsyncState;
WebResponse response = request.EndGetResponse(result);
which then allows me to check the response uri (the source of the intercepted message) and have the native browser handle the html that I was not expecting.
WebBrowserTask webBrowserTask = new WebBrowserTask();
webBrowserTask.Uri = response.ResponseUri;
Thanks for the help though, hopefully this will help someone with a similar issue.

Categories

Resources