Unity3D WWW Post data async - unity3d

I want to post a JSON to a website using the WWW class, But I get this answer from the server: "Synchronization problem.". Is there a way to change from sync to async? Thank You

You can run your WWW job in a coroutine (WWW supports this well):
using UnityEngine;
public class PostJSON : MonoBehaviour {
void Start () {
string url = "http://your_url_endpoint";
WWWForm form = new WWWForm();
Hashtable headers = form.headers;
headers["Content-Type"] = "application/json";
Hashtable data = new Hashtable();
data["message"] = "a sample message sent to service as json";
string json = JSON.JsonEncode(data);
byte[] bytes = Encoding.UTF8.GetBytes(json);
WWW www = new WWW(url, bytes, headers);
StartCoroutine(WaitForRequest(www));
}
IEnumerator WaitForRequest(WWW www)
{
yield return www
// check for errors
if (www.error == null)
{
Debug.Log("WWW Ok!: " + www.data);
} else {
Debug.Log("WWW Error: "+ www.error);
}
}
}
Here you have a running project which I use to talk to a json based REST service called KiiCloud:
http://blog.kii.com/?p=2939
HTH

The answer from German was very helpful, but I made some tweaks so that it'll compile and run (with sample serialization / deserialization bits).
Just pass in the BaseUrl you want to post to, i.e.
http://www.domain.com/somecontroller/someaction or whatever.
using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class Person
{
public string Name;
}
[Serializable]
public class Response
{
public string SomeValue;
}
public class PostJSON : MonoBehaviour
{
public string BaseUrl;
private WWWForm form;
private Dictionary<string, string> headers = null;
void Start ()
{
var basUrlNotSpecified = string.IsNullOrEmpty(BaseUrl);
if(basUrlNotSpecified)
{
Debug.LogWarning("BaseUrl value not specified. Post abandoned.");
return;
}
form = new WWWForm();
headers = form.headers;
headers["Content-Type"] = "application/json";
headers["Accept"] = "application/json";
var person = new Person
{
Name = "Iulian Palade"
};
var json = JsonUtility.ToJson(person);
byte[] bytes = Encoding.UTF8.GetBytes(json);
WWW www = new WWW(BaseUrl, bytes, headers);
StartCoroutine(WaitForRequest(www));
}
IEnumerator WaitForRequest(WWW www)
{
yield return www;
if (www.error == null)
{
Debug.Log("WWW Ok!: " + www.text);
var response = JsonUtility.FromJson<Response>(www.text);
Debug.Log(response.SomeValue);
}
else
{
Debug.Log("WWW Error: "+ www.error);
}
}
}

Related

Why does Post request to OpenAI in Unity result in error 400?

I am trying to use GPT3 in a game I am making but I can't seem to be able to call the OpenAI API correctly. I got most of this from the Unity docs.
Here is the code I am using:
public class gpt3_complete : MonoBehaviour
{
public string model;
public string prompt;
public int len;
public string temp;
public string api_key = "<key>";
void Start()
{
StartCoroutine(Upload());
}
IEnumerator Upload()
{
WWWForm form = new WWWForm();
form.AddField("model", model);
form.AddField("prompt", prompt);
form.AddField("max_tokens", len);
form.AddField("temperature", temp);
//form.headers.Add("Authorization", "Bearer "+api_key);
using (UnityWebRequest www = UnityWebRequest.Post("https://api.openai.com/v1/completions", form))
{
www.SetRequestHeader("Authorization", "Bearer " + api_key);
www.SetRequestHeader("Content-Type", "application/json");
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(www.error);
}
else
{
Debug.Log(www.result);
Debug.Log("Form upload complete!");
}
}
}
}
This always returns: 400 Bad Request.
The GPT3 docs can be found here: https://beta.openai.com/docs/api-reference/completions/create
Any idea why this is?
This is my first time making any web requests in unity so I'm probably missing something obvious.
Thanks!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using System.Text;
public class OpenAIRequest : MonoBehaviour
{
public string apiKey = "YOUR_API_KEY_HERE";
public string prompt = "Once upon a time, in a land far far away, there lived a brave knight";
public string model = "text-davinci-002";
public int maxTokens = 100;
void Start()
{
StartCoroutine(GetOpenAIResponse());
}
IEnumerator GetOpenAIResponse()
{
string url = "https://api.openai.com/v1/engines/" + model + "/completions";
string requestData = "{\"prompt\": \"" + prompt + "\", \"max_tokens\": " + maxTokens + "}";
UnityWebRequest request = new UnityWebRequest(url, "POST");
byte[] bodyRaw = Encoding.UTF8.GetBytes(requestData);
request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("Authorization", "Bearer " + apiKey);
yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success)
{
Debug.Log(request.error);
}
else
{
string response = request.downloadHandler.text;
Debug.Log(response);
}
}
}
result

POST requests to Flask from Unity result in `null` values

After getting this demo server working I am able return GET requests from it to Unity, but when I would try to send data from Unity to the local server using POST requests it would only show null values added into the server. This is the code I was using in Unity:
IEnumerator Upload()
{
WWWForm form = new WWWForm();
form.AddField("charge","+4/3");
form.AddField("name", "doubletop");
using (UnityWebRequest www = UnityWebRequest.Post("http://localhost:5000/quarks/", form))
{
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Form upload complete!");
}
}
}
I would get "Form upload complete!" in the console, and GET requests would work, but those null values kept coming.
I modified my Upload() method to the PostRequest() in this example, and now it works!
Here's the full code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class HTTP : MonoBehaviour
{
void Start()
{
// A correct website page.
StartCoroutine(GetRequest("localhost:5000/quarks"));
PostData();
StartCoroutine(GetRequest("localhost:5000/quarks"));
// A non-existing page.
//StartCoroutine(GetRequest("https://error.html"));
}
IEnumerator GetRequest(string uri)
{
using (UnityWebRequest webRequest = UnityWebRequest.Get(uri))
{
// Request and wait for the desired page.
yield return webRequest.SendWebRequest();
string[] pages = uri.Split('/');
int page = pages.Length - 1;
if (webRequest.isNetworkError)
{
Debug.Log(pages[page] + ": Error: " + webRequest.error);
}
else
{
Debug.Log(pages[page] + ":\nReceived: " + webRequest.downloadHandler.text);
}
}
}
[Serializable]
public class Quark
{
public string name;
public string charge;
}
public void PostData()
{
Quark gamer = new Quark();
gamer.name = "doublebottom";
gamer.charge = "4/3";
string json = JsonUtility.ToJson(gamer);
StartCoroutine(PostRequest("http://localhost:5000/quarks", json));
}
IEnumerator PostRequest(string url, string json)
{
var uwr = new UnityWebRequest(url, "POST");
byte[] jsonToSend = new System.Text.UTF8Encoding().GetBytes(json);
uwr.uploadHandler = (UploadHandler)new UploadHandlerRaw(jsonToSend);
uwr.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
uwr.SetRequestHeader("Content-Type", "application/json");
//Send the request then wait here until it returns
yield return uwr.SendWebRequest();
if (uwr.isNetworkError)
{
Debug.Log("Error While Sending: " + uwr.error);
}
else
{
Debug.Log("Received: " + uwr.downloadHandler.text);
}
}
}

Encountered Invalid redirect. Missing location header. Unity issue

I am using Unity WWWForm to post licence validation request to a URL.
The code is working in Unity 5.6, but it is not working in Unity 2017.3.1f1. I also tried this in Unity 2018. It didn't work.
This is the error message:
Encountered invalid redirect (missing Location header?)
This is the code I am using.
void Awake() {
Instance = this;
WWWForm form = new WWWForm ();
mainHeader = form.headers;
mainHeader ["Authorization"] = "Basic " + System.Convert.ToBase64String (System.Text.Encoding.ASCII.GetBytes ("dummyId:#dummyPassword"));
}
public void HitForLicence(){
string jsonData = JsonUtility.ToJson (new LicenseData {
LICENCE_KEY="kwsnfdksfksnf",
MACHINE_IP="192.168.1.1"
});
Debug.Log (jsonData);
byte[ ] postData = System.Text.Encoding.ASCII.GetBytes (jsonData);
//headers ["Authorization"] = "Basic " + System.Convert.ToBase64String (System.Text.Encoding.ASCII.GetBytes ("unity:#piun!ty"));
if (mainHeader.ContainsKey ("Content-Type")) {
mainHeader ["Content-Type"] = "application/json";
} else {
mainHeader.Add ("Content-Type", "application/json");
}
WWW www = new WWW (LicenseURL, postData, mainHeader);
StartCoroutine (CheckForLicense (www));
}
public IEnumerator CheckForLicense (WWW www)
{
Debug.Log("Check For License..");
yield return www;
//if (www.isDone ) {
if (www.error != null) {
ClearKeyBox ();
print (www.error);
}
else {
print (www.text);
jsonNode = SimpleJSON.JSON.Parse(www.text);
print ("MSG "+ jsonNode["MSG"].ToString());
}
//}
if (jsonNode != null && jsonNode["MSG"].Equals(ValidStr)) {
HandleTextFile.WriteString(_SystemMACAddress+"-"+keyEntered);
// Next screen
} else {
ClearKeyBox ();
}
}
Anyone faced this before? Please help.
I had some problems with WWW under Unity 2018, too.
Currently I am using UnityWebRequest - I think WWW is obsolete, but I can not find any reference to this.
Basically change your code like this:
...
UnityWebRequest www = UnityWebRequest.Post(LicenseURL, form)
StartCoroutine (CheckForLicense (www));
}
public IEnumerator CheckForLicense (WWW www)
{
Debug.Log("Check For License..");
...
I think you have to set the head via SetRequestHeader and put your post data into the WWWForm...
I am not able to check it right now... Hopefully it helps!
Like dome12b said, change to UnityWebRequest.
Additionaly however, set chunked transfer to false. I had the same problem and it was driving me nuts. Chunked transfer fixed it all.
UnityWebRequest www = UnityWebRequest.Post(LicenseURL, form)
www.chunkedTransfer = false;
This finally solved my problem.
public void Post(string url)
{
ServicePointManager.ServerCertificateValidationCallback =
delegate(object s, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
};
string jsonData = JsonUtility.ToJson (new LicenseData {
LICENCE_KEY="kwsnfdksfksnf",
MACHINE_IP="192.168.1.1"
});
Debug.Log (jsonData);
byte[ ] postData = System.Text.Encoding.ASCII.GetBytes (jsonData);
if (mainHeader.ContainsKey ("Content-Type")) {
mainHeader ["Content-Type"] = "application/json";
} else {
mainHeader.Add ("Content-Type", "application/json");
}
StartCoroutine (HttpRequest(postData, url));
}
IEnumerator HttpRequest(byte[] postData, string url)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
httpWebRequest.AllowAutoRedirect = false;
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string jsonData = JsonUtility.ToJson(new LicenseData
{
LICENCE_KEY = "kwsnfdksfksnf",
MACHINE_IP = "192.168.1.1"
});
streamWriter.Write(jsonData);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
print(result);
}
yield return null;
}

Object is null after model binding in Web API, using POSTMAN

I am trying to learn Web API and created my first project as below. I am testing it using postman. The post method works fine and I get response message – but the input received at the controller for the post action is null. What need to be done to get the post value in the controller?
using System.Collections.Generic;
using System.Net.Http;
using System.Web.Http;
using WebApplication1.Models;
namespace WebApplication1.Controllers
{
public class ValuesController : ApiController
{
List<Comment> comments;
// GET api/values
public IEnumerable<Comment> Get()
{
return comments;
}
// GET api/values/5
public Comment Get(int id)
{
Comment c = comments[id-1];
if (string.IsNullOrEmpty(c.Description))
{
throw new HttpResponseException(System.Net.HttpStatusCode.NotFound);
}
return c;
}
// POST api/values
public HttpResponseMessage Post(Comment inputComment)
{
Comment c = new Comment();
if (inputComment != null)
{
c.Description = inputComment.Description;
c.ID = inputComment.ID;
}
//var response = new HttpResponseMessage(HttpStatusCode.Created);
//return response;
var response = Request.CreateResponse<Comment>(System.Net.HttpStatusCode.Created, c);
response.Headers.Location=new System.Uri(Request.RequestUri,"/api/values/"+c.ID.ToString());
return response;
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
public ValuesController()
{
comments = new List<Comment>();
Comment comment1 = new Comment();
comment1.ID = 1;
comment1.Description = "Test1";
Comment comment2 = new Comment();
comment2.ID = 2;
comment2.Description = "";
comments.Add(comment1);
comments.Add(comment2);
}
}
}
POSTMAN Request/Response
POSTMAN Request Header
UPDATE
After using 'raw' in the request body, it worked fine. In POSTMAN, when I clicked "Generate Code", it is now displaying correct headers.
Use Raw as body type instead of Form-data and input you JSON.

ASP.NET JSON Web Service Response format

I have written one simple web service which get product list in JSONText which is string object
Web Service code is below
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
using System.Web.Script.Services;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Text;
/// <summary>
/// Summary description for JsonWebService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class JsonWebService : System.Web.Services.WebService
{
public JsonWebService () {
//Uncomment the following line if using designed components
//InitializeComponent();
}
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string GetProductsJson(string prefix)
{
List<Product> products = new List<Product>();
if (prefix.Trim().Equals(string.Empty, StringComparison.OrdinalIgnoreCase))
{
products = ProductFacade.GetAllProducts();
}
else
{
products = ProductFacade.GetProducts(prefix);
}
//yourobject is your actula object (may be collection) you want to serialize to json
DataContractJsonSerializer serializer = new DataContractJsonSerializer(products.GetType());
//create a memory stream
MemoryStream ms = new MemoryStream();
//serialize the object to memory stream
serializer.WriteObject(ms, products);
//convert the serizlized object to string
string jsonString = Encoding.Default.GetString(ms.ToArray());
//close the memory stream
ms.Close();
return jsonString;
}
}
now it give me resoponse like below :
{"d":"[{\"ProductID\":1,\"ProductName\":\"Product 1\"},{\"ProductID\":2,\"ProductName\":\"Product 2\"},{\"ProductID\":3,\"ProductName\":\"Product 3\"},{\"ProductID\":4,\"ProductName\":\"Product 4\"},{\"ProductID\":5,\"ProductName\":\"Product 5\"},{\"ProductID\":6,\"ProductName\":\"Product 6\"},{\"ProductID\":7,\"ProductName\":\"Product 7\"},{\"ProductID\":8,\"ProductName\":\"Product 8\"},{\"ProductID\":9,\"ProductName\":\"Product 9\"},{\"ProductID\":10,\"ProductName\":\"Product 10\"}]"}
But i am looking for below out put
[{"ProductID":1,"ProductName":"Product 1"},{"ProductID":2,"ProductName":"Product 2"},{"ProductID":3,"ProductName":"Product 3"},{"ProductID":4,"ProductName":"Product 4"},{"ProductID":5,"ProductName":"Product 5"},{"ProductID":6,"ProductName":"Product 6"},{"ProductID":7,"ProductName":"Product 7"},{"ProductID":8,"ProductName":"Product 8"},{"ProductID":9,"ProductName":"Product 9"},{"ProductID":10,"ProductName":"Product 10"}]
can any one tell me what is actual problem
Thanks
First there was a change with ASP.NET 3.5 for security reasons Microsoft added the "d" to the response. Below is a link from Dave Ward at the Encosia that talks about what your seeing:
A breaking change between versions of ASP.NET AJAX. He has several posts that talks about this that can help you further with processing JSON and ASP.NET
Actually, if you just remove the
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
from the method, and you return the jsonString that you serialized using the JavaScriptSerializer you will get exactelly the output that you were looking for.
Notice that u have double quotes beside ur array in your response.In this way u return json format not json object from ur web method.Json format is a string.Therefore u have to use json.parse() function in order to parse json string to json object.If u dont want to use parse fuction,u have to remove serialize in ur web method.Thus u get a json object.
in .net web service
[WebMethod]
public string Android_DDD(string KullaniciKey, string Durum, string PersonelKey)
{
return EU.EncodeToBase64("{\"Status\":\"OK\",\"R\":[{\"ImzaTipi\":\"Paraf\", \"Personel\":\"Ali Veli üğişçöıÜĞİŞÇÖI\", \"ImzaDurumTipi\":\"Tamam\", \"TamamTar\":\"1.1.2003 11:21\"},{\"ImzaTipi\":\"İmza\", \"Personel\":\"Ali Ak\", \"ImzaDurumTipi\":\"Tamam\", \"TamamTar\":\"2.2.2003 11:21\"}]}");
}
static public string EncodeToBase64(string toEncode)
{
UTF8Encoding encoding = new UTF8Encoding();
byte[] bytes = encoding.GetBytes(toEncode);
string returnValue = System.Convert.ToBase64String(bytes);
return returnValue;
}
in android
private static String convertStreamToString(InputStream is)
{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try
{
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
is.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
return sb.toString();
}
private void LoadJsonDataFromASPNET()
{
try
{
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost httpPostRequest = new HttpPost(this.WSURL + "/WS.asmx/Android_DDD");
JSONObject jsonObjSend = new JSONObject();
jsonObjSend.put("KullaniciKey", "value_1");
jsonObjSend.put("Durum", "value_2");
jsonObjSend.put("PersonelKey", "value_3");
StringEntity se = new StringEntity(jsonObjSend.toString());
httpPostRequest.setEntity(se);
httpPostRequest.setHeader("Accept", "application/json");
httpPostRequest.setHeader("Content-type", "application/json");
// httpPostRequest.setHeader("Accept-Encoding", "gzip"); // only set this parameter if you would like to use gzip compression
HttpResponse response = (HttpResponse) httpclient.execute(httpPostRequest);
HttpEntity entity = response.getEntity();
if (entity != null)
{
InputStream instream = entity.getContent();
String resultString = convertStreamToString(instream);
instream.close();
resultString = resultString.substring(6, resultString.length()-3);
resultString = new String(android.util.Base64.decode(resultString, 0), "UTF-8");
JSONObject object = new JSONObject(resultString);
String oDurum = object.getString("Status");
if (oDurum.equals("OK"))
{
JSONArray jsonArray = new JSONArray(object.getString("R"));
if (jsonArray.length() > 0)
{
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject jsonObject = jsonArray.getJSONObject(i);
String ImzaTipi = jsonObject.getString("ImzaTipi");
String Personel = jsonObject.getString("Personel");
String ImzaDurumTipi = jsonObject.getString("ImzaDurumTipi");
String TamamTar = jsonObject.getString("TamamTar");
Toast.makeText(getApplicationContext(), "ImzaTipi:" + ImzaTipi + " Personel:" + Personel + " ImzaDurumTipi:" + ImzaDurumTipi + " TamamTar:" + TamamTar, Toast.LENGTH_LONG).show();
}
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}