如何在返回之前等待回调

时间:2018-01-17 14:58:16

标签: c# .net http unity3d

我正在尝试将代码从.Net移植到Unity C#,我仍然坚持使用包含回调的语法。

基本上,我不得不更换.Net' HttpClient' this one的库,也称为HttpClient'。但是' Get'语法不一样,并使用回调。我是C#和Http查询的新手,并且不知道如何处理这种语法以获得预期的回报。

用.Net编写的原始函数:

internal static JObject GetToBackOffice(string action)
{
    var url = backOfficeUrl;
    url = url + action;

    HttpClient httpClient = new HttpClient();

    var response =
        httpClient.GetAsync(url
        ).Result;
    if (response.StatusCode == System.Net.HttpStatusCode.OK)
    {
        var idProcess = Newtonsoft.Json.Linq.JObject.Parse(response.Content.ReadAsStringAsync().Result);

        return idProcess;
    }
    else
        return null;

我为Unity写的C#代码:

internal class Utils
{ 
    internal static JObject GetToBackOffice(string action)
    {
        var url = backOfficeUrl;
        url = url + action;

        HttpClient httpClient = new HttpClient();

        JObject idProcess = new JObject();

        httpClient.GetString(new Uri(url),
            (response) =>
            {
                // Raised when the download completes
                if (response.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    idProcess = Newtonsoft.Json.Linq.JObject.Parse(response.Data);
                }
                else
                {
                    idProcess = null;
                }
            });
        // Here I would like to wait for the response, so that idProcess is filled with the received data before returning
        return idProcess;
    } 

public class Action
{
     public bool SendData(string id, string secretKey, FakeData data)
    {
        var idProcess = Utils.GetToBackOffice(String.Format("Events/{0}/infos",id));
        //...I do then something with idProcess
        //Currently, when I use idProcess here, it is still empty since the GetString response hasn't been received yet when this line is executed

        return true;
    }
}

public class EventHubSimulator : MonoBehaviour
{
    void Start()
    {
        //Fill the parameters (I skip the details)
        string oId = ...;
        string secretKey = ...;
        var vh = ...;

        Action action = new Action();
        action.SendData(oId, secretKey, vh);
    }
}

我的问题是在GetToBackOffice函数之后,我的代码直接使用' idProcess'对于其他东西,但此对象为空,因为尚未收到响应。我想在函数返回之前等待响应。

我希望我足够清楚。我知道类似的问题已经发布,但无法找到我特定问题的解决方案。

编辑:

最后我按照Nain的建议使用了一个协程,但是无法按照他的说法得到我所期望的。这种方式似乎有效(事件虽然可能不是一个很好的方法)。

public class EventHubSimulator : MonoBehaviour
    {
        void Start()
        {
            //Fill the parameters (I skip the details)
            string oId = ...;
            string secretKey = ...;
            var vh = ...;

            Utils utils = new Utils();
            StartCoroutine(utils.SendData(oId, secretKey, vh));
        }
    }

public class Utils: MonoBehaviour
{
    private const string backOfficeUrl = "http://myurl/api/";

    public CI.HttpClient.HttpResponseMessage<string> response;

    public IEnumerator SendData(string id, string secretKey, FakeData data)
    {
        response = null;
        yield return GetToBackOffice(String.Format("Events/{0}/infos", id)); //Make a Http Get request
        //The next lines are executed once the response has been received
        //Do something with response
        Foo(response);
    }

    IEnumerator GetToBackOffice(string action)
    {
        var url = backOfficeUrl;
        url = url + action;

        //Make a Http Get request
        HttpClient httpClient = new HttpClient();
        httpClient.GetString(new Uri(url), (r) =>
        {
            // Raised when the download completes
            if (r.StatusCode == System.Net.HttpStatusCode.OK)
            {
                //Once the response has been received, write it in the global variable
                response = r;
                Debug.Log("Response received : " + response);
            }
            else
            {
                Debug.Log("ERROR =============================================");
                Debug.Log(r.ReasonPhrase);
                throw new Exception(r.ReasonPhrase);
            }
        });

        //Wait for the response to be received
        yield return WaitForResponse();
        Debug.Log("GetToBackOffice coroutine end ");
    }

    IEnumerator WaitForResponse()
    {
        Debug.Log("WaitForResponse Coroutine started");
        //Wait for response to become be assigned
        while (response == null) 
        {
            yield return new WaitForSeconds(0.02f);
        }
        Debug.Log("WaitForResponse Coroutine ended");
    }
}    

4 个答案:

答案 0 :(得分:1)

一个解决方案是轮询完成,因为Nain提交了答案。如果您不想进行投票,可以使用TaskCompletionSourceThis Q&A深入了解了原因和方法。

您的代码可以这样编写:

async Task CallerMethod()
{
    JObject result = await GetToBackOffice(...);
    // Do something with result
}

internal static Task<JObject> GetToBackOffice(string action)
{
    var tsc = new TaskCompletionSource<JObject>();
    var url = backOfficeUrl;
    url = url + action;

    HttpClient httpClient = new HttpClient();

    JObject idProcess = new JObject();

    httpClient.GetString(new Uri(url),
        (response) =>
        {
            // Raised when the download completes
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                tsc.SetResult(Newtonsoft.Json.Linq.JObject.Parse(response.Data));
            }
            else
            {
                tsc.SetResult(null);
            }
        });

    return tsc.Task;
}

另请参阅this msdn blogpost的异步方法调用协程并等待完成部分。

注意任务和async / await支持仅在Unity中以beta functionality的形式提供。另请参阅this帖子。

答案 1 :(得分:0)

写一个Co例程,如

  //Class scope variable is neede to hold Resopnce other wise it will 
  //be destroied as soon as function is ended
  ResponceType  response;
  IEnumerator WaitForResponce(ResponceType  response)
  {
        this.response = response;
        while(this.response.Data == null)
        yield return new WaitForSeconds (0.02f);
   //do what you want here

  }

并致电合作例程

 httpClient.GetString(new Uri(url),
    (response) =>
    {
        // Raised when the download completes
        if (response.StatusCode == System.Net.HttpStatusCode.OK)
        {
            //idProcess = Newtonsoft.Json.Linq.JObject.Parse(response.Data);
            StartCoroutine(WaitForResponce(responce));
        }
        else
        {
            idProcess = null;
        }
    });

答案 2 :(得分:0)

您需要提供回复&#34; return&#34;数据

internal static  void GetToBackOffice(string action, Action<JObject>onCompletion)
{
    var url = backOfficeUrl;
    url = url + action;

    HttpClient httpClient = new HttpClient();

    JObject idProcess = new JObject();

    httpClient.GetString(new Uri(url),
    (response) =>
    {
        // Raised when the download completes
        if (response.StatusCode == System.Net.HttpStatusCode.OK)
        {
            idProcess = Newtonsoft.Json.Linq.JObject.Parse(response.Data);
        }
        else
        {
            idProcess = null;
        }
        if (onCompletion){ onCompletion(idProcess);
    });
} 

方法返回boid,但如果需要,你可以返回HttpRequest。

请求的回调会将redult传递给onCompletion回调。

答案 3 :(得分:-1)

如果GetString方法返回一个Task对象,那么您可以使用Wait()方法让Task在返回结果之前完成处理。

&#13;
&#13;
 var task = httpClient.GetString({
    impl here..
 });
 
 task.Wait();
 return idProcess;
 
 
&#13;
&#13;
&#13;