Xamarin.Forms UnhandledException when doing a request - c#

I am trying to use the HttpClient PCL from Microsoft in an Android project but whne I attempt to make a request, after a little while I get a "System.Diagnostics.Mono_UnhandledException" and no extra info.
var client = new HttpClient();
client.BaseAddress = new Uri(_apiUrl);
var resourceUrl = "setistas?login=" + login + "&senha=" + senha;
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, resourceUrl);
var response = client.SendAsync(requestMessage).Result;
I am not sure why this happens, I am using the latest version of Xamarin studio, and the latest version of the libraries.
Can anyone help me?
By the way don't mind fact that I am passing secure information on the url, this is just a test. ;)

Probably you are not awaiting your request and trying to read result of unfinished task.
Last line should be
var result = await client.SendAsync(requestMessage);

The problem was on how I referenced the libraries.
When you add the nugget package for HTTPClient to the DLL project, you have to add a reference in the Android project to System.Net.Http, once you do that, it starts working.

Related

Moving emails/messages using Microsoft Graph SDK's Batch Requests

My objective is to process emails in a folder and then move them to another folder to which I have the id. To ease the workload I'm trying to make use of the batch functionality.
Unfortunately, every time I try to run the batch function I'm presented with an exception with the message Code: invalidRequest Message: Unable to deserialize content..
The code in question, simplified for just one request, can be found below.
var batch = new BatchRequestContent();
var json = JsonSerializer.Serialize( new { destinationId = Graph.Me.Messages[messageId].Move(folderId).Request().RequestBody.DestinationId } );
var jsonMessage = Graph.HttpProvider.Serializer.SerializeAsJsonContent(json);
var request = Graph.Me.Messages[messageId].Move(folderId).Request().GetHttpRequestMessage();
request.Method = HttpMethod.Post;
request.Content = jsonMessage;
batch.AddBatchRequestStep(request);
var res = await Graph.Batch.Request().PostAsync(batch);
I've narrowed down the problem to be about the request.Content because without that it will go through, though getting back with a 400 error about missing body.
Copying the string from batch.ReadAsStringAsync() and pasting that directly into the Graph Explorer and using that to run the query returns a 200 success.
Based on what I've tried I'm starting to lean on it being a limitation of the SDK's batch.
Any ideas?
While this wasn't the solution I was looking for, it works as a band aid solution.
Basically, after you add all your steps to the BatchRequestContent you use the ReadAsStringAsync() to get the body of the request. Then you use the library itself to send the HTTP Request, as instructed here.
HttpRequestMessage hrm = Graph.Batch.Request().GetHttpRequestMessage();
hrm.Method = HttpMethod.Post;
hrm.Content = Graph.HttpProvider.Serializer.SerializeAsJsonContent(await batch.ReadAsStringAsync());
// Authenticate (add access token) our HttpRequestMessage
await Graph.AuthenticationProvider.AuthenticateRequestAsync(hrm);
// Send the request and get the response.
HttpResponseMessage res = await Graph.HttpProvider.SendAsync(hrm);

Client-side Blazor using SendAsync for a GetRequest with CORS for an API request

I ran into some issues with CORS when setting up my Blazor client-side API client to make requests. I think I found the solution to that, but the solution is also throwing errors.
The main error is:
"WASM: System.Net.Http.HttpRequestException: TypeError: Failed to execute 'fetch' on 'Window': The provided value '2' is not a valid enum value of type RequestCredentials."
the code is
string link = API_RequestLoginTokenEndPoint;
Http.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
Http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", "basic:testuser:testpassword");
var requestMessage = new HttpRequestMessage(new HttpMethod("GET"), link);
requestMessage.Properties[WebAssemblyHttpMessageHandler.FetchArgs] = new
{
credentials = FetchCredentialsOption.Include
};
var response = await Http.SendAsync(requestMessage);
var responseStatusCode = response.StatusCode;
var responseBody = await response.Content.ReadAsStringAsync();
output = responseBody + " " + responseStatusCode;
I also tried changing the request message to:
var requestMessage = new HttpRequestMessage(HttpMethod.Get, link);
In case this was the ENUM the error referred to. In the Startup ConfigureServices I tried to add:
WebAssemblyHttpMessageHandler.DefaultCredentials = FetchCredentialsOption.Include;
I am using Blazor preview 9. I also tried adding some CORS code to my PHP script on the API route that should accept all origins, but the last question I posted I was told to use this method to fix the CORS problem, which now gives me a new error.
Am I doing something wrong or am I missing something? The error in the browser usually points to the line with the async request:
var response = await Http.SendAsync(requestMessage);
This is a bug not yet fixed. Use this instead :
requestMessage.Properties[WebAssemblyHttpMessageHandler.FetchArgs] = new
{
credentials = "include"
};
I had a similar issue and could not resolve the pre-flight activity.
I WAS ABLE TO SOLVE THIS BY COMMENTING OUT HTTP REDIRECTION MIDDLEWARE.
context: Blazor client calls asp.net.core api in different url.
Not sure if this a good solution but I felt I needed to mention this after
spending 1 week on this frustrating issue! Hope it helps someone.

Use .NET's own httpClient class on Unity

I'm trying to do a HTTP Delete request from Unity and bump into the idea of use the HttpRequest class included in the System.Web namespace of .Net
How can I achieve this, I supose that some sort of import of that namespace must be done, but how?
Hope some one can give me some orientation
HttpClient is only available in 4.5 NET and above and Unity does not use that version. Unity uses about 3.5 .NET version.
If you are using Unity 5.3, UnityWebRequest.Delete can be used to make a Delete request. It can be found in the Experimental.Networking namespace. If you are using Unity 5.4 and above,UnityWebRequestcan be found in the UnityEngine.Networking; namespace.
Full working example:
IEnumerator makeRequest(string url)
{
UnityWebRequest delReq = UnityWebRequest.Delete(url);
yield return delReq.Send();
if (delReq.isError)
{
Debug.Log("Error: " + delReq.error);
}
else
{
Debug.Log("Received " + delReq.downloadHandler.text);
}
}
Usage:
StartCoroutine(makeRequest("http://www.example.com/whatever"));
Make sure to include using UnityEngine.Networking. You can find complete examples with it here.
EDIT (UPDATE)
Unity now supports .NET 4.5 so you can now use HttpClient if you wish. See this post for how to enable it.
After enabling it,
Go to <UnityInstallationDirectory>\Editor\Data\MonoBleedingEdge\lib\mono\4.5 or for example, C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\lib\mono\4.5 on my computer.
Once in this directory, copy System.Net.Http.dll to your <ProjectName>\Assets directory and you should be able to use HttpClient after importing the System.Net.Http namespace. If there are some other error about missing dependencies, you can get the dlls from this path too and copy them to your <ProjectName>\Assets directory too.
In the current versions of Unity httpClient is supported out of the box even on .NET Standard 2.0 targets. Here is sample code on how I use it to access a REST api.
public static async Task<Resource> GetResource()
{
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(URL);
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await httpClient.GetAsync("api/session");
if (response.StatusCode != HttpStatusCode.OK)
return null;
var resourceJson = await response.Content.ReadAsStringAsync();
return JsonUtility.FromJson<Resource>(resourceJson);
}
}
Copy of my answer on https://forum.unity.com/threads/httpclient-on-net-standard-2-0.608800/

Exception calling PutAsJsonAsync from Xamarin

I am trying to write a small test application using WebApi. I have it mostly working, I am able to get data from my web service and display it in Android.
I added a button, and used the same code that I had used in my Winforms test client:
async void buttonSave_Clicked(object sender, EventArgs e)
{
HttpClient client = new HttpClient ();
Customer data = new Customer () {
Surname = editSurname.Text,
GivenName = editGivenName.Text};
var result = await client.PutAsJsonAsync("http://10.0.0.4/WebApplication1/api/Customers/2", data);
if (result.IsSuccessStatusCode ) {
labelStatus.Text = "Saved";
}
}
This works fine in the Windows Forms test app, but in the Xamarin app I get an exception on client.PutAsJsonAsync:
E/mono-rt ( 7519): [ERROR] FATAL UNHANDLED EXCEPTION: System.TypeLoadException: Could not load type 'System.Net.Http.ObjectContent`1[T]' from assembly 'System.Net.Http.Formatting, Version=5.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.
Any suggestions? Using Xamarin 3.
edit:
It works if I format the content manually:
string sData = Newtonsoft.Json.JsonConvert.SerializeObject(data);
HttpContent content = new System.Net.Http.StringContent(sData, System.Text.Encoding.UTF8, "application/json") ;
var result = await client.PutAsync("http://10.0.0.4/WebApplication1/api/Customers/2",content);
I have all the references correct, as far as I can see. I used the WebApi Client nuget package.
References:
Newtonsoft.Json
System.Net.Http
System.Net.Http.Extensions
System.Net.Http.Formatting
System.Net.Http.Primitives
You need to install the following Nuget packages to all the projects that reference your HttpClient project
Microsoft.Bcl.Build
Microsoft.Bcl
These are the warnings from Visual Studio when I built my project and after I done that, it worked!
Serialize your data into a JSON string like this:
string json = JsonConvert.SerializeObject(item);
var content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
response = await client.PostAsync(url, content);
The overload list for the System.Net.Http.PutAsJsonAsync method on MSDN only shows overloads that contain three or four parameters. In your example, I see two that you are passing. It appears correct to be able to leave out the HttpClient parameter when called as a instance from HttpClient based on the code examples from MSDN.
However, with Xamarin it was built as a fork of MonoDevelop. MonoDevelop uses the Mono Framework which is a port of the .NET Framework. Due to that difference, I am interested if a bug should be opened for Mono, MonoDevelop, or Xamarin.
Back to the overload methods list though, I recommend trying to use one of these overloads.
PutAsJsonAsync(HttpClient, String, T)
PutAsJsonAsync(HttpClient, Uri, T)
PutAsJsonAsync(HttpClient, String, T, CancellationToken)
PutAsJsonAsync(HttpClient, Uri, T, CancellationToken)
I recommend trying to pass the HttpClient to the PutAsJsonAsync method without PutAsJsonAsync being called from an instance of HttpClient.
BTW, this is not a guaranteed solution, for it was simply too much information to put into comments. Hope this helps.

HttpClient not supporting PostAsJsonAsync method C#

I am trying to call a web API from my web application. I am using .Net 4.5 and while writing the code I am getting the error HttpClient does not contain a definition PostAsJsonAsync method.
Below is the code:
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:51093/");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var user = new Users();
user.AgentCode = 100;
user.Remarks = "Test";
user.CollectionDate = System.DateTime.Today;
user.RemittanceDate = System.DateTime.Today;
user.TotalAmount = 1000;
user.OrgBranchID = 101;
var response = client.PostAsJsonAsync("api/AgentCollection", user).Result;
and I am getting the error message:
Error: 'System.Net.Http.HttpClient' does not contain a definition for
'PostAsJsonAsync' and No extension method 'PostAsJsonAsync' accepting a first argument of
type 'System.Net.Http.HttpClient' could be found (are you missing
a using directive or an assembly reference?)
Please have a look and advice me.
Yes, you need to add a reference to
System.Net.Http.Formatting.dll
This can be found in the extensions assemblies area.
A good way of achieving this is by adding the NuGet package Microsoft.AspNet.WebApi.Client to your project.
PostAsJsonAsync is no longer in the System.Net.Http.dll (.NET 4.5.2). You can add a reference to System.Net.Http.Formatting.dll, but this actually belongs to an older version. I ran into problems with this on our TeamCity build server, these two wouldn't cooperate together.
Alternatively, you can replace PostAsJsonAsyncwith a PostAsync call, which is just part of new dll.
Replace
var response = client.PostAsJsonAsync("api/AgentCollection", user).Result;
With:
var response = client.PostAsync("api/AgentCollection", new StringContent(
new JavaScriptSerializer().Serialize(user), Encoding.UTF8, "application/json")).Result;
Note that JavaScriptSerializer is in the namespace: System.Web.Script.Serialization.
You will have to add an assembly reference in your csproj: System.Web.Extensions.dll
See https://code.msdn.microsoft.com/windowsapps/How-to-use-HttpClient-to-b9289836
The missing reference is the System.Net.Http.Formatting.dll. But the better solution is to add the NuGet package Microsoft.AspNet.WebApi.Client to ensure the version of the formatting dll worked with the .NET framework version of System.Net.Http in my project.
As already debatted, this method isn't available anymore since .NET 4.5.2. To expand on Jeroen K's answer you can make an extension method:
public static async Task<HttpResponseMessage> PostAsJsonAsync<TModel>(this HttpClient client, string requestUrl, TModel model)
{
var serializer = new JavaScriptSerializer();
var json = serializer.Serialize(model);
var stringContent = new StringContent(json, Encoding.UTF8, "application/json");
return await client.PostAsync(requestUrl, stringContent);
}
Now you are able to call client.PostAsJsonAsync("api/AgentCollection", user).
I had this issue too on a project I'd just checked out from source control.
The symptom was the error described above and a yellow warning triangle on a reference to System.Net.Http.Formatting
To fix this, I removed the broken reference and then used NuGet to install the latest version of Microsoft.AspNet.WebApi.Client.
I know this reply is too late, I had the same issue and i was adding the System.Net.Http.Formatting.Extension Nuget, after checking here and there I found that the Nuget is added but the System.Net.Http.Formatting.dll was not added to the references, I just reinstalled the Nuget
Try to install in your project the NuGet Package: Microsoft.AspNet.WebApi.Client:
Install-Package Microsoft.AspNet.WebApi.Client
Ok, it is apocalyptical 2020 now, and you can find these methods in NuGet package System.Net.Http.Json. But beware that it uses System.Text.Json internally.
And if you really need to find out which API resides where, just use https://apisof.net/
If you are already using Newtonsoft.Json try this:
// Alternative using WebApi.Client 5.2.7
////var response = await Client.PutAsJsonAsync(
//// "api/AgentCollection", user
//// requestListDto)
var response = await Client.PostAsync("api/AgentCollection", new StringContent(
JsonConvert.SerializeObject(user), Encoding.UTF8, "application/json"));
Performance are better than JavaScriptSerializer. Take a look here https://www.newtonsoft.com/json/help/html/Introduction.htm
Instead of writing this amount of code to make a simple call, you could use one of the wrappers available over the internet.
I've written one called WebApiClient, available at NuGet... check it out!
https://www.nuget.org/packages/WebApiRestService.WebApiClient/
If you're playing around in Blazor and get the error, you need to add the package Microsoft.AspNetCore.Blazor.HttpClient.
Just expanding Jeroen's answer with the tips in comments:
var content = new StringContent(
JsonConvert.SerializeObject(user),
Encoding.UTF8,
MediaTypeNames.Application.Json);
var response = await client.PostAsync("api/AgentCollection", content);
For me I found the solution after a lot of try which is replacing
HttpClient
with
System.Net.Http.HttpClient
Based on the answers here talking about using Newtonsoft.Json, I created a helper class for this:
public class JsonContent : StringContent
{
public JsonContent(object model)
: base(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json")
{
}
}
Example usage:
using (var content = new JsonContent(user))
{
var response = client.PostAsync("api/AgentCollection", content).Result;
}
If you are using Blazor components and getting this error that means your component is not able to find the http client.
use this line on top on your blazor component.
#inject HttpClient Http
Make sure you have this line in your Program or startup file
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

Categories

Resources