gazuntype / graphQL-client-unity

This repository houses a unitypackage that can be included in your Unity Project to enable it communicate with a graphQL server.
Apache License 2.0
292 stars 50 forks source link

'UnityWebRequestAsyncOperation' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' #41

Open Benjamin-Rhodes-Kropf opened 2 years ago

Benjamin-Rhodes-Kropf commented 2 years ago

When I opened the demo project I get three errors from the HttpHandler... here are all three:

1.Assets\graphQl-client\Scripts\Core\HttpHandler.cs(31,17): error CS1061: 'UnityWebRequestAsyncOperation' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'UnityWebRequestAsyncOperation' could be found (are you missing a using directive or an assembly reference?)

2.Assets\graphQl-client\Scripts\Core\HttpHandler.cs(53,5): error CS1061: 'UnityWebRequestAsyncOperation' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'UnityWebRequestAsyncOperation' could be found (are you missing a using directive or an assembly reference?)

3.Assets\graphQl-client\Scripts\Core\HttpHandler.cs(75,17): error CS1061: 'UnityWebRequestAsyncOperation' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'UnityWebRequestAsyncOperation' could be found (are you missing a using directive or an assembly reference?)

Vlakdo commented 2 years ago

I have the same problem, any solution?

Benjamin-Rhodes-Kropf commented 2 years ago

Yea, Actually, I’m working on it now. Should be done later today! I’ve got one solution already, but I’ve got to refine it. How soon do you need it?

Benjamin-Rhodes-Kropf commented 2 years ago

Alright, here was my solution: First, I just went and cloned the repo and then opened it in unity and didn't have that problem. Everything just worked out of the box. when I tried to import it into an existing project, that's when I had this problem...

However, if you wish the fix the current unity project, here is a really janky solution: Replace the class 'HttpHandler' with this: `public class HttpHandler {

    public static async Task<UnityWebRequest> PostAsync(string url, string details, string authToken = null){
        string jsonData = JsonConvert.SerializeObject(new{query = details});
        byte[] postData = Encoding.ASCII.GetBytes(jsonData);
        UnityWebRequest request = UnityWebRequest.Post(url, UnityWebRequest.kHttpVerbPOST);
        request.uploadHandler = new UploadHandlerRaw(postData);
        request.SetRequestHeader("Content-Type", "application/json");
        if (!String.IsNullOrEmpty(authToken)) 
            request.SetRequestHeader("Authorization", "Bearer " + authToken);

        OnRequestBegin  requestBegin = new OnRequestBegin();
        requestBegin.FireEvent();

        try{
            request.SendWebRequest();
            await Task.Delay(10000); //this is the janky fix.... idk why request.SendWebRequest() isn't awaitable
        }
        catch(Exception e){
            Debug.Log("Testing exceptions");
            OnRequestEnded requestFailed = new OnRequestEnded(e);
            requestFailed.FireEvent();
        }
        Debug.Log(request.downloadHandler.text);

        OnRequestEnded requestSucceeded = new OnRequestEnded(request.downloadHandler.text);
        requestSucceeded.FireEvent();
        return request;
    }

    public static async Task<UnityWebRequest> PostAsync(UnityWebRequest request, string details){
        string jsonData = JsonConvert.SerializeObject(new{query = details});
        byte[] postData = Encoding.ASCII.GetBytes(jsonData);
        request.uploadHandler = new UploadHandlerRaw(postData);
        OnRequestBegin  requestBegin = new OnRequestBegin();
        requestBegin.FireEvent();

        try{
            request.SendWebRequest();
            await Task.Delay(10000);
        }
        catch(Exception e){
            Debug.Log("Testing exceptions");
            OnRequestEnded requestFailed = new OnRequestEnded(e);
            requestFailed.FireEvent();
        }
        Debug.Log(request.downloadHandler.text);

        OnRequestEnded requestSucceeded = new OnRequestEnded(request.downloadHandler.text);
        requestSucceeded.FireEvent();
        return request;
    }

    public static async Task<UnityWebRequest> GetAsync(string url, string authToken = null){
        UnityWebRequest request = UnityWebRequest.Get(url);
        if (!String.IsNullOrEmpty(authToken)) 
            request.SetRequestHeader("Authorization", "Bearer " + authToken);
        OnRequestBegin  requestBegin = new OnRequestBegin();
        requestBegin.FireEvent();
        try{
            request.SendWebRequest();
            await Task.Delay(10000);
        }
        catch(Exception e){
            Debug.Log("Testing exceptions");
            OnRequestEnded requestEnded = new OnRequestEnded(e);
            requestEnded.FireEvent();
        }
        Debug.Log(request.downloadHandler.text);
        OnRequestEnded requestSucceeded = new OnRequestEnded(request.downloadHandler.text);
        requestSucceeded.FireEvent();
        return request;
    }

    #region Websocket

    //Use this to subscribe to a graphql endpoint
    public static async Task<ClientWebSocket> WebsocketConnect(string subscriptionUrl, string details, string authToken = null, string socketId = "1", string protocol = "graphql-ws"){
        string subUrl = subscriptionUrl.Replace("http", "ws");
        string id = socketId;
        ClientWebSocket cws = new ClientWebSocket();
        cws.Options.AddSubProtocol(protocol);
        if (!String.IsNullOrEmpty(authToken))
            cws.Options.SetRequestHeader("Authorization", "Bearer " + authToken);
        Uri u = new Uri(subUrl);
        try{
            await cws.ConnectAsync(u, CancellationToken.None);
            if (cws.State == WebSocketState.Open)
                Debug.Log("connected");
            await WebsocketInit(cws);
            await WebsocketSend(cws, id, details);
        }
        catch (Exception e){
            Debug.Log("woe " + e.Message);
        }

        return cws;
    }

    public static async Task<ClientWebSocket> WebsocketConnect(ClientWebSocket cws, string subscriptionUrl, string details, string socketId = "1"){
        string subUrl = subscriptionUrl.Replace("http", "ws");
        string id = socketId;
        Uri u = new Uri(subUrl);
        try{
            await cws.ConnectAsync(u, CancellationToken.None);
            if (cws.State == WebSocketState.Open)
                Debug.Log("connected");
            await WebsocketInit(cws);
            await WebsocketSend(cws, id, details);
        }
        catch (Exception e){
            Debug.Log("woe " + e.Message);
        }

        return cws;
    }

    static async Task WebsocketInit(ClientWebSocket cws){
        string jsonData = "{\"type\":\"connection_init\"}";
        ArraySegment<byte> b = new ArraySegment<byte>(Encoding.ASCII.GetBytes(jsonData));
        await cws.SendAsync(b, WebSocketMessageType.Text, true, CancellationToken.None);
        GetWsReturn(cws);
    }

    static async Task WebsocketSend(ClientWebSocket cws, string id, string details){
        string jsonData = JsonConvert.SerializeObject(new {id = $"{id}",  type = "start", payload = new{query = details}});
        ArraySegment<byte> b = new ArraySegment<byte>(Encoding.ASCII.GetBytes(jsonData));
        await cws.SendAsync(b, WebSocketMessageType.Text, true, CancellationToken.None);
    }

    //Call GetWsReturn to wait for a message from a websocket. GetWsReturn has to be called for each message
    static async void GetWsReturn(ClientWebSocket cws){
        ArraySegment<byte> buf = new ArraySegment<byte>(new byte[1024]);
        buf = WebSocket.CreateClientBuffer(1024, 1024);
        WebSocketReceiveResult r;
        string result = "";
        do{
            r = await cws.ReceiveAsync(buf, CancellationToken.None);
            result += Encoding.UTF8.GetString(buf.Array ?? throw new ApplicationException("Buf = null"), buf.Offset,
                r.Count);
        } while (!r.EndOfMessage);

        if (String.IsNullOrEmpty(result))
            return;
        JObject obj = new JObject();
        try{
            obj = JObject.Parse(result);
        }
        catch (JsonReaderException e){
            throw new ApplicationException(e.Message);
        }

        string subType = (string) obj["type"];
        switch (subType){
            case "connection_ack":
            {
                Debug.Log("init_success, the handshake is complete");
                OnSubscriptionHandshakeComplete subscriptionHandshakeComplete =
                    new OnSubscriptionHandshakeComplete();
                subscriptionHandshakeComplete.FireEvent();
                GetWsReturn(cws);
                break;
            }
            case "error":
            {
                throw new ApplicationException("The handshake failed. Error: " + result);
            }
            case "connection_error":
            {
                throw new ApplicationException("The handshake failed. Error: " + result);
            }
            case "data":
            {
                OnSubscriptionDataReceived subscriptionDataReceived = new OnSubscriptionDataReceived(result);
                subscriptionDataReceived.FireEvent();
                GetWsReturn(cws);
                break;
            }
            case "ka":
            {
                GetWsReturn(cws);
                break;
            }
            case "subscription_fail":
            {
                throw new ApplicationException("The subscription data failed");
            }

        }
    }

    public static async Task WebsocketDisconnect(ClientWebSocket cws, string socketId = "1"){
        string jsonData = $"{{\"type\":\"stop\",\"id\":\"{socketId}\"}}";
        ArraySegment<byte> b = new ArraySegment<byte>(Encoding.ASCII.GetBytes(jsonData));
        await cws.SendAsync(b, WebSocketMessageType.Text, true, CancellationToken.None);
        await cws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closed", CancellationToken.None);
        OnSubscriptionCanceled subscriptionCanceled = new OnSubscriptionCanceled();
        subscriptionCanceled.FireEvent();
    }

    #endregion

    #region Utility

    public static string FormatJson(string json)
    {
        var parsedJson = JsonConvert.DeserializeObject(json);
        return JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
    }

    #endregion
}`

I wouldn't recommend this, though... instead, I would just try and clone the repo and then open it like you would a normal unity project instead of importing it like a package (that's what fixed it for me)

Vlakdo commented 2 years ago

Thanks for the solution, when I clone and open it I get errors, what version of Unity are you using?

Benjamin-Rhodes-Kropf commented 2 years ago

2021.3.7f1

Benjamin-Rhodes-Kropf commented 2 years ago

can you send me the error?

Vlakdo commented 2 years ago

These two:

Multiple precompiled assemblies with the same name Newtonsoft.Json.dll included on the current platform. Only one assembly with the same name is allowed per platform. (Assets/JsonDotNet/Assemblies/Standalone/Newtonsoft.Json.dll)

Multiple precompiled assemblies with the same name Newtonsoft.Json.dll included on the current platform. Only one assembly with the same name is allowed per platform. (/Users/vladimirea/Downloads/graphQL-client-unity-master/Library/PackageCache/com.unity.nuget.newtonsoft-json@3.0.2/Runtime/Newtonsoft.Json.dll)

Benjamin-Rhodes-Kropf commented 2 years ago

Oh yes, I got that as well at one point... go to: Assets/JsonDotNet/Assemblies you should see a bunch of files with different OS listed... delete the ones that arent yours though I'm not sure if it truly matters

Caju0ne commented 2 years ago

If you got this error too, this is the solution that worked for me: Why error? Unity do not have native support to async await. If you check inside the repository folders, you'll notice it has a Plugin called AsyncAwaitUtil. Solution Before installing the graphQL client package, grab AsyncAwaitUtil from Unity asset store. You might need to change its deprecated WWW references for UnityWebRequest. Then, install graphQL client package. No more errors.

violetforest commented 2 years ago

If you got this error too, this is the solution that worked for me: Why error? Unity do not have native support to async await. If you check inside the repository folders, you'll notice it has a Plugin called AsyncAwaitUtil. Solution Before installing the graphQL client package, grab AsyncAwaitUtil from Unity asset store. You might need to change its deprecated WWW references for UnityWebRequest. Then, install graphQL client package. No more errors.

https://assetstore.unity.com/packages/tools/integration/async-await-support-101056

Benjamin-Rhodes-Kropf commented 2 years ago

Yea Actully I’m working on it now. Should be done later today! I’ve got one solution already but I’ve got to refine it. How soon do you need it?

On Wed, Aug 17, 2022 at 11:11 AM Vladimir @.***> wrote:

I have the same problem, any solution?

— Reply to this email directly, view it on GitHub https://github.com/gazuntype/graphQL-client-unity/issues/41#issuecomment-1218143146, or unsubscribe https://github.com/notifications/unsubscribe-auth/AUJCD2S7DXURMFBVZSJKLS3VZT6LJANCNFSM56GIDCFA . You are receiving this because you authored the thread.Message ID: @.***>

pixelpax commented 2 years ago

I'm still getting this problem today. I think I fixed it by adding the following file, but I'm not sure if it's going to work everywhere. Seems like a priority fix.

using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using UnityEngine.Networking;

public static class UnityWebRequestExtension
{
    public static TaskAwaiter<UnityWebRequest.Result> GetAwaiter(this UnityWebRequestAsyncOperation reqOp)
    {
        TaskCompletionSource<UnityWebRequest.Result> tsc = new();
        reqOp.completed += asyncOp => tsc.TrySetResult(reqOp.webRequest.result);

        if (reqOp.isDone)
            tsc.TrySetResult(reqOp.webRequest.result);

        return tsc.Task.GetAwaiter();
    }
}
lucas-villalva commented 1 year ago

I changed it to this but now I have a 405 error when try to introspect the scriptable object stuff in the pokemon

` public static async Task PostAsync(string url, string details, string authToken = null){ string jsonData = JsonConvert.SerializeObject(new{query = details}); byte[] postData = Encoding.ASCII.GetBytes(jsonData); UnityWebRequest request = UnityWebRequest.PostWwwForm(url, UnityWebRequest.kHttpVerbPOST); request.uploadHandler = new UploadHandlerRaw(postData); request.SetRequestHeader("Content-Type", "application/json"); if (!String.IsNullOrEmpty(authToken)) request.SetRequestHeader("Authorization", "Bearer " + authToken);

        OnRequestBegin  requestBegin = new OnRequestBegin();
        requestBegin.FireEvent();

        try{
            var asyncOperation = request.SendWebRequest();
            while (!asyncOperation.isDone) {
                await Task.Yield();
            }

            if (request.result == UnityWebRequest.Result.ProtocolError)
            {
                Debug.LogError("Error: " + request.error);
                OnRequestEnded requestEnded = new OnRequestEnded(request.error);
                requestEnded.FireEvent();
            }
            else
            {
                Debug.Log(request.downloadHandler.text);
                OnRequestEnded requestSucceeded = new OnRequestEnded(request.downloadHandler.text);
                requestSucceeded.FireEvent();
            }
        }
        catch(Exception e){
            Debug.Log("Testing exceptions");
            OnRequestEnded requestFailed = new OnRequestEnded(e);
            requestFailed.FireEvent();
        }

        return request;
    }`
VietnameseRick commented 7 months ago

I just got this issue and resolved it by copy the plugin folder in Assets then place it inside my Unity project Assets folder