在Windows Phone 8上使用Unity进行POST请求

9
我正在尝试在Unity平台上从Windows Phone 8执行POST请求。 我不想使用Unity的WWW方法,因为它会阻塞渲染(而且不是线程安全的)。以下代码在编辑器和Android上运行正常,但在构建WP8时出现错误。
“System.Byte [] System.Net.WebClient :: UploadData(System.String,System.String,System.Byte [])”在目标框架中不存在。
这个错误的原因在这里解释了:
这是因为Windows Phone 8使用了一个不同的.NET版本,称为Windows Phone的.NET,其中缺少其他平台上可用的某些类型。 您必须使用不同的类型替换这些类型或自己实现它们。 - http://docs.unity3d.com/Manual/wp8-faq.html 这是我的代码:
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
    }
}

我也尝试过WebRequests,但GetResponse()会导致它崩溃,而HttpClient不存在。那么,在Windows Phone 8上,如何在Unity中发布数据而不使用WWW呢?
根据评论请求的更新 - WebRequests
这段代码使用HttpWebRequest在编辑器和Android上运行正常,但在Windows Phone上会抛出下面列出的错误。
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)
{}

错误1:

错误:目标框架中不存在方法System.IO.Stream System.Net.HttpWebRequest::GetRequestStream()

错误2:

System.Net.WebResponse System.Net.HttpWebRequest::GetResponse()在目标框架中不存在。

更多细节更新 - UploadStringAsync

使用此代码进行异步请求,在编辑器中再次正常工作,但在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)
{}

错误1

方法 System.Void System.Net.WebClient::add_UploadDataCompleted(System.Net.UploadDataCompletedEventHandler) 在目标框架中不存在。

错误2

错误:方法 System.Void System.Net.WebClient::UploadDataAsync(System.Uri,System.Byte[]) 在目标框架中不存在。

错误3

错误:类型 System.Net.UploadDataCompletedEventArgs 在目标框架中不存在。

错误4

错误:方法 System.Byte[] System.Net.UploadDataCompletedEventArgs::get_Result() 在目标框架中不存在。


我以为通过创建一个原始的 System.Net.Sockets 请求已经解决了问题,但结果发现这也不被支持... Unity 开始变得很糟糕。 - JensB
当你说“我也尝试过WebRequests,但GetResponse()会破坏它”时,你具体指什么?它是如何出现问题的? - Peter Torr - MSFT
4个回答

1
使用以下代码可以让它在Windows手机上工作。在编辑器、Android和WP8上编译和运行(太棒了!)。尚未在iOS上尝试过。
同时,我在这里写了一篇关于它的文章:在Unity中创建可在所有平台上使用的Web请求,甚至是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;
}

1

尝试使用这些方法,但结果仍然是相同的烦人的“在目标平台上不存在”的错误。已更新问题并附上结果。 - JensB
@JensB,你尝试使用了 UploadDataAsync 方法,然而该方法在 Windows Phone 上并不存在。只有字符串版本的方法是受支持的 - Stefan Hoffmann
虽然这并没有给我解决方案,但它帮助我找到了解决问题的正确文档(被接受的答案),所以我会给你赏金 :) - JensB

0

你不能在Unity中使用这些框架,因为它们是线程化/异步的/使用另一个版本的.Net

简而言之:

  • Unity运行在一个只接受.Net 3.5的mono版本上
  • Unity不允许你启动线程、任务或任何接近真正异步的东西
  • 但你可以实现这些功能。

要在Windows Phone上实现这一点,你需要创建一个类库(实际上需要两个),Unity称之为插件。

那么为什么需要两个dll呢?

因为编辑器需要一个模拟dll(或者实际的dll,如果你也想为桌面实现它)来实现与在Windows Phone上兼容的dll相同的接口。

明确一下:

  • 编辑器中的dll(在Assets/Plugins中)需要兼容.Net 3.5和桌面
  • 放置在Assets/plugins/WP8中的dll需要兼容Windows Phone .Net子集(据我记得,你可以使用.Net 4.5而没有问题)

所以你应该在一个dll中实现这个功能,然后在Unity中引用它,并直接调用它。

所有的内容都在这里解释了:http://docs.unity3d.com/Manual/wp8-plugins-guide-csharp.html

它比看起来简单。


Unity将在构建时交换这两个dll,以便在您的Windows Phone解决方案中引用与Windows Phone兼容的dll。 - Géry Arduino

0

我知道你说你不想使用WWW类,但是你给出的理由在我看来没有意义。

如果你使用协程来检查“.isDone”标志,而不是使用Thread.Sleep()来检查它,它不会阻塞渲染,并且是线程安全的(因为Unity只在单个线程上提供其信息)。

如果你想在另一个线程中访问返回数据,你只需要在主Unity线程中读取该数据,然后将其传递给你想要使用它的任何线程。

Unity的设计是所有内容都在单个线程上运行,以使经验不足的程序员更容易入门。虽然你应该能够使用.NET线程创建多个线程,但你将无法直接与任何Unity组件通信,但你可以将数据传回Unity并等待Update或Unity的另一个调用来使用数据。我知道这并没有完全回答你的问题,但如果你无法解决它,我认为重新考虑使用WWW类和使用最佳实践是值得的。


据我所知,这是不正确的。我在Unity论坛上有一个帖子,关于这个问题:http://goo.gl/3sC9gp 基本上WWW将会阻塞渲染线程。 - JensB
1
你尝试过使用while循环并检查isDone而不是使用yield return wwwObject吗?这对我来说真的很奇怪,因为我从未见过这种情况发生,但根据那个链接,看起来你做得很正确,很抱歉我不能提供更多帮助:( - Colton White

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接