0

I am trying to POST a json string to a web API and currently got this code:

async Task<Uri> Post(CapturedImage image)
{
    string json = JsonConvert.SerializeObject(image);
    var content = new StringContent(json.ToString(), Encoding.UTF8, "application/json");
    HttpResponseMessage response = await client.PostAsync(url, content);
    response.EnsureSuccessStatusCode();
    Debug.Log("Request Message Information:- \n\n" + response.RequestMessage + "\n");

    Debug.Log(json.ToString());

    // return URI of the created resource.
    return response.Headers.Location;
}

The code is not done yet so I'm not sure this is the type I want to return in the end (in the end I will have a new json string with information about a specific car supposedly).

Unity hangs when it comes to the line HttpResponseMessage response = await client.PostAsync(url, content); and I have to forcefully close the unity app.

How can I use the httpClient successfully? I am not using the unityWebRequest for the moment because I don't understand in which way WWWForm is being sent (like an object I guess). And I don't want a byte[] to be sent either, but a json string and I can assume that the WWWForm is like a json string but separated-ish. Also I don't get which type to be received in the web API either when its a WWWForm. Like if its a json string I just have the parameter like (string json).

Am I thinking completely wrong with not using unityWebRequest instead of httpClient? I have to use json if possible.

6
  • using unitywebrequest is probably the preferred option, to send the json, the code is not dissimilar, you can post the json in the body just like you do above. Commented Apr 3, 2019 at 8:05
  • 1
    UnityWebRequest.Post(string URL, string data) also takes a simple string as input data not only a WWWForm. I don't want a byte[] to be sent either - well in the end everything you send will be encoded to byte[] ... Commented Apr 3, 2019 at 8:09
  • But use a StartCoroutine() and so instead of await async? What can I exchange UnityWebRequest with in the code? Can you show some code example? @BugFinder Commented Apr 3, 2019 at 8:11
  • @derHugo Ok! I will give it a try! Commented Apr 3, 2019 at 8:12
  • you cuold use this (never used it but looks promising) Commented Apr 3, 2019 at 8:12

1 Answer 1

6

UnityWebRequest.Post(string URL, string data) also takes string as data input not only a WWWForm.

Usually you would use it in a Coroutine

In order to get a result back you could add a simple callback

IEnumerator Upload(string URL, string jsonData, Action<string> callback)
{
    using (UnityWebRequest www = UnityWebRequest.Post(URL, jsonData))
    {
        www.SetRequestHeader("Content-Type", "application/json");

        yield return www.SendWebRequest();

        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log("Form upload complete!");
            callback?.Invoke(www.GetResponseHeader("Location"));
        }
    }
}

and use it with

StartCoroutine(Upload(someURL, someJsonData, 
    // e.g. as lambda expression
    result => 
    {
        Debug.Log(result);
    }
));

or with a method

StartCoroutine(Upload(someURL, someJsonData, HandleUploadResult);

...

private void HandleUploadResult(string result)
{
    Debug.Log(result);
}

But if you really need it to be used with await as said this looks promising (though neevr tried it):

public class UnityWebRequestAwaiter : INotifyCompletion
{
    private UnityWebRequestAsyncOperation asyncOp;
    private Action continuation;

    public UnityWebRequestAwaiter(UnityWebRequestAsyncOperation asyncOp)
    {
        this.asyncOp = asyncOp;
        asyncOp.completed += OnRequestCompleted;
    }

    public bool IsCompleted { get { return asyncOp.isDone; } }

    public void GetResult() { }

    public void OnCompleted(Action continuation)
    {
        this.continuation = continuation;
    }

    private void OnRequestCompleted(AsyncOperation obj)
    {
        continuation();
    }
}

public static class ExtensionMethods
{
    public static UnityWebRequestAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOp)
    {
        return new UnityWebRequestAwaiter(asyncOp);
    }
}

It looks complicated but ... you don't have to do anything with it just put it somewhere in your Assets.

Then as far as I understand it you can simply use something like

www = UnityWebRequest.Post(URL, jsonData);
www.SetRequestHeader("Content-Type", "application/json");
await www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
    Debug.Log(www.error);
}
else
{
    Debug.Log("Form upload complete!");
    var result = www.GetResponseHeader("Location");
}

There are other sources which do something similar .. maybe better?

Sign up to request clarification or add additional context in comments.

2 Comments

What I specifically have to use is json really, so have tried your first example with coroutine only. I do get somewhat of a response. Its an error though 404 not found. My url works in postman so I don't really get why the page is not found. I just have to goole it I guess ^^ Thanks for all your help once again Hugo!
also checkout this answer it used it without Post and configured the rest manually ... especially try to SetRequestHeader("Content-Type", "application/json");

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.