Use .NET's own httpClient class on Unity - c#

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/

Related

Using Protobuf in .Net Core with .proto files

I'm looking into using Protobuf to send data between my Microservices, and
I'm using the C# support in Google.ProtoBuf and not ProtoBuf-Net, since I want to compile classes from .proto files.
The reason for this is the Microservices are not strictly .Net. Some of the are written in Go etc.
I'm looking for something like the ProtoBufFormatter in the package WebApiContrib.Formatting.ProtoBuf, but support Google.ProtoBuf.
The ProtoBufFormatter returns serialized protobuf data if the client have set content type to application/x-protobuf, otherwise Json.
How can I achieve something similar for Google.ProtoBuf? Further I'm also looking into find this kind of support for the Nancy Framework on .Net Core as well.
I have found this link where it explains how to use protobuf files with Protobuf-Net, but does not seem up to date (.Net Core + VSCode).
I could not find any solution for my use case with Google.Protobuf, so I used a custom InputFormatter and OutputFormatter like in this blog post, with Protobuf-Net.
Then to call and deserialize the protobuf content in the client, I came up with this solution:
var client = new System.Net.Http.HttpClient { BaseAddress = new Uri("http://localhost:5002") };
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-protobuf"));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync("api/home");
if (response.IsSuccessStatusCode)
{
if (response.Content.Headers.ContentType.MediaType == "application/x-protobuf")
{
using(var stream = await response.Content.ReadAsStreamAsync())
{
var protoBufModel = ProtoBuf.Serializer.Deserialize<ProtobufModelDto>(stream);
return $"{protoBufModel.Name}, {protoBufModel.StringValue}, {protoBufModel.Id}";
}
}
var content = await response.Content.ReadAsStringAsync();
var jsonModel = JsonConvert.DeserializeObject<ProtobufModelDto>(content);
return $"{jsonModel.Name}, {jsonModel.StringValue}, {jsonModel.Id}";
}
return "Failed";
Next step will be to figure out how to create models from .proto files with Protobuf-Net.

Is WebRequest (System.Net) a safe choice in Unity?

First of all, let me state my problem: my game server does not provide WebAPI (we do not have resources for it now), but rather our client is tring to work like a web browser and I need cookie support for Session ID.
Searching around with Google, I see the best I can do is manually set the headers of request and get the response header. I am ok with that, because I am originally ASP.NET MVC developer.
However, I then realize they use Dictionary for both the request and response. Now that's the problem. We know that the header can be duplicated, in my case is the Set-Cookie.
Then I tried another, and find out UnityWebRequest class, which is still in UnityEngine.Experimental.Networking namespace (so I suppose it is still in beta?), but I try my luck anyway; only sad to realize they also use Dictionary for header items.
So now my only chance is the vanilla .NET WebRequest (in System.Net namespace). However, I see no documentation on the .NET Framework compability in Unity. Can anyone tell me if it is supported on most platform? My main targets are Windows, Android and Web. If possible, even for WebClient would be nicer.
Here is my current solution, which work good in the Unity Editor, but I have yet to test them on other devices. Is there any solution for this?
public class CookieWebRequest
{
private CookieContainer cookieContainer;
public CookieWebRequest()
{
this.cookieContainer = new CookieContainer();
}
public void GetAsync(Uri uri, Action<HttpWebResponse> onFinished)
{
var webRequest = HttpWebRequest.Create(uri) as HttpWebRequest;
webRequest.Method = WebRequestMethods.Http.Get;
webRequest.CookieContainer = this.cookieContainer;
new Thread(() =>
{
HttpWebResponse httpResponse;
try
{
httpResponse = webRequest.GetResponse() as HttpWebResponse;
}
catch (WebException ex)
{
if (onFinished != null)
{
onFinished(ex.Response as HttpWebResponse);
}
return;
}
if (httpResponse.Cookies != null && httpResponse.Cookies.Count > 0)
{
this.cookieContainer.Add(httpResponse.Cookies);
}
if (onFinished != null)
{
onFinished(httpResponse);
}
httpResponse.GetResponseStream().Dispose();
}).Start();
}
}
System.Net.HttpWebRequest and System.Net.WebClient work on most platforms supported by Unity. However when you want to build for the Unity Web Player or WebGL you will run into problems since Unity does not support most of the System.Net networking stuff since javascript does not have direct access to IP Sockets.
WebGL network restictions
As you already mentioned UnityWebRequest or the legacy WWW object from Unity is your best bet. With Unity 5.3 UnityWebRequest work on most platforms including WebGL and the Unity Web player. But as you also already mentioned the complete UnityWebRequest is still experimental but is under constant development and will probably improve in every new update.
The only downside, using the WWW or UnityWebRequest object is (as far as I understood the UnityWebRequest object) that they need to run in the Unity main thread so you will have to use Coroutines instead of pushing the request into a different thread. As long as you do not have millions of webrequest this should not lead into any performance issues of your app. And is probably less error prone.
The bigger issue is that WWW and UnityWebRequest do not support keep-alive on most platforms at the moment (WEBGL might be an exception, actually). Expect any SSL encrypted requests to each have a huge amount of overhead (300+ milliseconds on a good machine).

Xamarin.Forms UnhandledException when doing a request

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.

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