I'm trying to do a post request on windows phone 8 from the Unity Platform. I do not want to use the unity WWW method as this blocks rendering (and is not thread safe).
The following code works in the editor and on Android, but when building it for WP8 I get the following error.
System.Byte[] System.Net.WebClient::UploadData(System.String,System.String,System.Byte[])` doesn't exist in target framework.
The reason for this error is explained here
It’s because Windows Phone 8 uses a different flavor of .NET called .NET for Windows Phone which is missing some of the types available on other platforms. You’ll have to either replace these types with different ones or implement them yourself.
- http://docs.unity3d.com/Manual/wp8-faq.html
This is my code
using (WebClient client = new WebClient())
{
client.Encoding = System.Text.Encoding.UTF8;
client.Headers[HttpRequestHeader.ContentType] = "application/json";
byte[] requestData = new byte[0];
string jsonRequest = "{}";
if (data != null)
{
string tempRequest = Converter.SerializeToString (data);
jsonRequest = "{\"Data\": \"" + tempRequest + "\"}";
requestData = System.Text.Encoding.UTF8.GetBytes(jsonRequest);
}
// below line of code is the culprit
byte[] returnedData = client.UploadData(url, "POST", requestData);
if(returnedData.Length > 0)
{
// do stuff
}
}
I've also tried WebRequests, but GetResponse() breaks it, and HttpClient does not exist.
So, how do I post data in Unity, without using WWW, on windows phone 8?
UPDATE AS PER COMMENT REQUEST - WebRequests
This code, using HttpWebRequest works in the editor and on Android, but on windows phone throws the errors listed below the code.
var request = (System.Net.HttpWebRequest) System.Net.WebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "POST";
var sw = new System.IO.StreamWriter(request.GetRequestStream(), System.Text.Encoding.UTF8);
sw.Write(jsonRequest); // jsonRequest is same variable as in above code, string with json object.
sw.Close();
var re = request.GetResponse();
string resultString = "";
using (var outputStream = new System.IO.StreamReader(re.GetResponseStream(), System.Text.Encoding.UTF8))
{
resultString = outputStream.ReadToEnd();
}
if(resultString.Length > 0)
{}
Error 1:
Error: method System.IO.Stream System.Net.HttpWebRequest::GetRequestStream() doesn't exist in target framework.
Error 2:
System.Net.WebResponse System.Net.HttpWebRequest::GetResponse() doesn't exist in target framework.
UPDATE WITH MORE DETAILS - UploadStringAsync
Using this code to make an async request it again works great in the editor, errors are thrown on the WP8.
bool isCompleted = false;
byte[] returnedData = null;
client.UploadDataCompleted +=
new UploadDataCompletedEventHandler((object sender, UploadDataCompletedEventArgs e) =>
{
Debug.Log("return event");
returnedData = e.Result;
isCompleted =true;
});
Debug.Log("async call start");
client.UploadDataAsync(new Uri(url), requestData);
while(isCompleted == false){
Thread.Sleep(100);
}
if(returnedData.Length > 0)
{}
Error 1
method System.Void System.Net.WebClient::add_UploadDataCompleted(System.Net.UploadDataCompletedEventHandler) doesn't exist in target framework.
Error 2
Error: method System.Void System.Net.WebClient::UploadDataAsync(System.Uri,System.Byte[]) doesn't exist in target framework.
Error 3
Error: type System.Net.UploadDataCompletedEventArgs doesn't exist in target framework.
Error 4
Error: method System.Byte[] System.Net.UploadDataCompletedEventArgs::get_Result() doesn't exist in target framework.
I don't know about any potential restrictions placed on you by Unity, but Windows Phone 8 has the WebClient.UploadStringAsync method and the WebClient.UploadStringCompleted event for doing just this.
HttpWebRequest should also work (again, I don't know about any Unity limitations - see comment above asking for clarification).
Go it to work on the windows phone using the code below. Compiles and runs in the editor, on Android and on WP8 (yay!). Haven't tried it on iOS yet.
Also wrote a post about it here: Create Web requests for unity that work on all platforms, even WP8
/// <summary>
/// Make post request to url with given paramaters
/// </summary>
/// <param name="url">URL to post data to http://server.com/method </param>
/// <param name="data">{ Data: data }</param>
/// <returns>string server response</returns>
public string PostData(string url, string data)
{
// json request, hard coded right now but use "data" paramater to set this value.
string jsonRequest = "{\"Data\": \"data\"}"; // the json request
var request = System.Net.WebRequest.Create(url) as System.Net.HttpWebRequest;
// this could be different for your server
request.ContentType = "application/json";
// i want to do post and not get
request.Method = "POST";
// used to check if async call is complete
bool isRequestCallComplete = false;
// store the response in this
string responseString = string.Empty;
request.BeginGetRequestStream(ar =>
{
var requestStream = request.EndGetRequestStream(ar);
using (var sw = new System.IO.StreamWriter(requestStream))
{
// write the request data to the server
sw.Write(jsonRequest);
// force write of all content
sw.Flush();
}
request.BeginGetResponse(a =>
{
var response = request.EndGetResponse(a);
var responseStream = response.GetResponseStream();
using (var sr = new System.IO.StreamReader(responseStream))
{
// read in the servers response right here.
responseString = sr.ReadToEnd();
}
// set this to true so the while loop at the end stops looping.
isRequestCallComplete = true;
}, null);
}, null);
// wait for request to complete before continuing
// probably want to add some sort of time out to this
// so that the request is stopped after X seconds.
while (isRequestCallComplete == false) { Thread.Sleep(50); }
return responseString;
}
You cannot use these frameworks from unity because they are threaded / async / use another version of .Net
In short :
Unity runs on a version of mono which accepts only .Net 3.5
Unity does not allow you to start threads, tasks or anything close to real asynchronicity
You can implement those though.
To do that on windows phone you will need to create a class library (two in fact) what unity calls a plugin
So why two dlls?
Because the editor needs a mockup dll (or the actual one if you want to implement it for desktop as well) that implements the same interface as the dll which is compatible on windows phone.
To be clear :
The dll for the editor (in Assets/Plugins) needs to be compatible .Net 3.5 and desktop
The dll placed in Assets/plugins/WP8 needs to be compatible windows phone .Net subset (as i remember you can be .Net 4.5 with no pb)
So you should implement that functionality in a dll, then reference that in unity, and finally call it directly.
All is explained here : http://docs.unity3d.com/Manual/wp8-plugins-guide-csharp.html
It is simpler than it looks like.
I know you said you don't want to use the WWW class, but the reasons you gave to dont make sense IMO.
If you use a Coroutine to check the ".isDone" flag and not check it by using the Thread.Sleep() it wont block rendering and is thread safe (since unity only gives you access to its info on a single thread).
If you want to access the return data on another thread you just need to read that data in the main unity thread and then pass it along to whatever thread you want to use it on.
Unity by design is all runs on a single thread to make life easier for less experienced programmers. Though you should be able to create multiple threads using .NET threading, you will not be able to communicate directly with any Unity components, but you can pass the data back to Unity and wait until Update or another call by Unity to use the data. I know this doesnt answer your question exactly but if you cant solve it I think it would be worthwhile to look again at the WWW class and the best practices in using it.
Related
I download a Console Application on GitHub and works fine.
But I want to translate this C# Console Application to a Universal Windows 10 Application.
The error on Visual Studio: Web Request does not contain a definition for...
This is the code:
private AccessTokenInfo HttpPost(string accessUri, string requestDetails)
{
//Prepare OAuth request
WebRequest webRequest = WebRequest.Create(accessUri);
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
byte[] bytes = Encoding.ASCII.GetBytes(requestDetails);
webRequest.ContentLength = bytes.Length;
using (Stream outputStream = webRequest.GetRequestStream())
{
outputStream.Write(bytes, 0, bytes.Length);
}
using (WebResponse webResponse = webRequest.GetResponse())
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(AccessTokenInfo));
//Get deserialized object from JSON stream
AccessTokenInfo token = (AccessTokenInfo)serializer.ReadObject(webResponse.GetResponseStream());
return token;
}
}
basically I get an error on this 3 functions:
webRequest.ContentLength
webRequest.GetRequestStream()
webRequest.GetResponse()
This is an image of the error:
Image with error: "Does not contain a definition"
Aditional Comments:
I read a few similar problems on GitHub and it seems I need to create a AsyncResult like this
This is the answer for some similar question (I dont know how to apply this to my problem):
/** In case it is a Windows Store App (and not WPF) there is no synchronous GetResponse method in class WebResponse.
You have to use the asynchronous GetResponseAsync instead, e.g. like this: **/
using (var response = (HttpWebResponse)(await request.GetResponseAsync()))
{
// ...
}
Thanks in advance!
in the answer you linked there is a comment with the actual answer:
In case it is a Windows Store App (and not WPF) there is no
synchronous GetResponse method in class WebResponse
you have to use the async methods in UWP apps since they don't have synchronous cals anymore to improve user interface performance (no more hanging UI because it's doing a web request on the same thread)
your code should be in the form of
HttpWebResponse response = await webrequest.GetResponseAsync();
Here is some more info on async/await and how to use it: https://msdn.microsoft.com/en-us/library/hh191443.aspx
So on my client (windows phone 8.1 app) I have posted a JSON just for testing, here is the code for this:
public async void SendJSON()
{
try
{
string url = "http://posttestserver.com/post.php?dir=karim";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "text/plain; charset=utf-8";
httpWebRequest.Method = "POST";
using (var stream = await Task.Factory.FromAsync<Stream>(httpWebRequest.BeginGetRequestStream,
httpWebRequest.EndGetRequestStream, null))
{
//create some json string
string json = "{ \"my\" : \"json\" }";
// convert json to byte array
byte[] jsonAsBytes = Encoding.UTF8.GetBytes(json);
// Write the bytes to the stream
await stream.WriteAsync(jsonAsBytes, 0, jsonAsBytes.Length);
}
}
catch(Exception ex)
{
}
}
Now I'm trying to figure out, from the www.myurl.com how would I retrieve what has been posted from the mobile app using a Web Service?
UPDATE
When I debug these lines, it runs perfectly without breaking nor falling within the catch. However when looking at where it should post to (the results are here http://www.posttestserver.com/data/2015/12/14/karim/) it doesn't post anything.
Does anyone know what I'm doing wrong?
BTW: it already has results there because I have done this directly from my desktop.
Not sure what you are trying to do but if you want to inspect your http requests fiddler is a good choice. Since your are using windows phone apps you can configure the windows phone emulator to proxy through fiddler.
Here is a blog post how to set this up: http://blogs.msdn.com/b/wsdevsol/archive/2013/06/05/configure-the-windows-phone-8-emulator-to-work-with-fiddler.aspx - Configure the Windows Phone 8 Emulator to work with Fiddler
// Edit: Have you considered to use HttpClient
var httpClient = new HttpClient();
string resourceAddress = "http://posttestserver.com/post.php?dir=karim";
string postBody = "{ \"my\" : \"json\" }"
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await httpClient.PostAsync(resourceAddress, new StringContent(postBody, Encoding.UTF8, "application/json"));
Code is from the top of my head so you might have to tweak it... and of course you need to handle error cases and/or retry, etc
HTH
If you just want to see, what have you send, you can use this http://posttestserver.com
Otherwise there is not easy way how to force some endpoint to retrieve data. There must but set up server, which is allowing it, proccessing it, storing it etc.
If you POST anything to http://posttestserver.com/post.php it will return you this message
Successfully dumped 0 post variables. View it at
http://www.posttestserver.com/data/2015/12/15/00.19.29177030164 Post
body was 134 chars long.
So just print somewhere your response and you will get the exact url
You should use fiddler to see the outputted content:
http://www.telerik.com/fiddler
Windows Phone 8.1 Emulator not proxying through Fiddler
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).
I have been playing with ASP.NET Web API. I am looking to see can I post to a method I have built which simply returns back the object I have POSTED:
On The Accounts Controller:
// POST /api/accounts
public Account Post(Account account)
{
return account;
}
Code Used To Post:
public void PostAccount()
{
// http://local_ip/api/accounts
var uri = string.Format("{0}", webServiceRoot);
var acc = new Account();
acc.AccountID = "8";
acc.AccountName = "Mitchel Cars";
acc.AccountNumber = "600123801";
acc.SubscriptionKey = "2535-8254-8568-1192";
acc.ValidUntil = DateTime.Now;
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/xml";
request.ContentLength = 800;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Account));
xmlSerializer.Serialize(request.GetRequestStream(), acc);
var response = (HttpWebResponse)request.GetResponse();
XmlSerializer serializer = new XmlSerializer(typeof(Account));
var newAcc = (Account)serializer.Deserialize(response.GetResponseStream());
}
I have removed any error checking or any boiler plate code to make it easier to read. This is strictly a spike just to under stand to to actually POST. My understanding is that you should write to the GetRequestStream(). All the reading and such seems to work ok but I never here back from the request.GetResponse();
If I do a simple get it works fine. I did see you can use a class called HTTPClient for doing this stuff but I can't use it as I need to get this working for WinForms, Silverlight and Windows Phone all based on .Net 3.5
Any help pushing POCO's to the server would be a great help, cheers!
ADDITIONAL INFO:
Currently I get no error, the test app just hangs.
If I turn off the WebAPI project I get a server not found response.
I have not changed any routes or any of that.
Gets to the same controller work.
You will need to close the response stream. Most examples I see also show setting the content length. You may be better to serialize to a memory stream and then use the length of that stream as the Content-Length. Unfortunately in .net 3.5 there is no CopyStream so you may have to write that yourself.
If you want to use the HttpClient, you can install the download the REST starter Kit. and use the DLLs as external DLLs
http://forums.asp.net/t/1680252.aspx/1
I'm having a lot of problems calling a Java based Google App Engine server from a C# client
This is how my client code looks like:
// C# Client
static void Main(string[] args)
{
const string URL = "http://localhost:8888/googlewebapptest7/greet";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "text/x-gwt-rpc; charset=utf-8";
string content = "<?xml version='1.0'?><methodCall><methodName>greetServlet.GetName</methodName><params></params></methodCall>";
byte[] contentBytes = UTF8Encoding.UTF8.GetBytes(content);
request.ContentLength = contentBytes.Length;
using (Stream stream = request.GetRequestStream())
{
stream.Write(contentBytes, 0, contentBytes.Length);
}
// get response
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
string res = new StreamReader(responseStream).ReadToEnd();
Console.WriteLine("response from server:");
Console.WriteLine(res);
Console.ReadKey();
}
The server is basically the Google default web project with an additional method:
public String GetName()
{
return "HI!";
}
added to GreetingServiceImpl.
Everytime I run my client, I get the following exception from the server:
An IncompatibleRemoteServiceException was thrown while processing this call.
com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException: This application is out of date, please click the refresh button on your browser. ( Malformed or old RPC message received - expecting version 5 )
I would like to keep it in plain HTTP requests.
Any idea what's going on?
As Nick pointed out you're trying to emulate GWT's RPC format. I tried that too :)
Then I took different approach. I used Google Protocol Buffers as encoder/decoder over HTTP(S).
One of my projects is desktop application written in C#. Server-side is also C#.Net. Naturally we use WCF as transport.
You can plug-in Protocol Buffers into WCF transport. You'll have same interface configuration both for C# client and Java server. It's very convenient.
I'll update this answer with code-samples when I'm less busy with work.
I never found a good way to use XML based RPC on the Google App Engine. Instead i found this excellent JSON library with tutorial:
http://werxltd.com/wp/portfolio/json-rpc/simple-java-json-rpc/
it works very well!