UI忙时阻止WebResponses

时间:2012-05-18 13:40:01

标签: asynchronous httpwebrequest windows-phone-7.1 system.reactive

我对Windows Phone 7 WebRequests有一点问题。 在我的程序中很少有“web进程” - 每个进程必须向服务器发送一个或多个REST消息。响应此消息的信息将在下一个REST中使用,因此必须以正确的顺序发送所有WebRequest。因此,为了轻松地同步我创建的所有消息,方法如下:

//There was some try-catch blocks,  I cut them because they are not important 
//for the problem
public string SendString(string URL, string message)
        {
            WebRequest wr = HttpWebRequest.CreateHttp(URL);
            wr.Method = "POST";
            var req = Observable.FromAsyncPattern<Stream>(wr.BeginGetRequestStream, wr.EndGetRequestStream);
            var resp = Observable.FromAsyncPattern<WebResponse>(wr.BeginGetResponse, wr.EndGetResponse);
            WebResponse WR = req().SelectMany(reqStream =>
                {
                    byte[] stream = UTF8Encoding.UTF8.GetBytes(message);
                    reqStream.Write(stream, 0, stream.Length);
                    reqStream.Close();
                    return resp();
                })
                .First();
            Stream respStream = WR.GetResponseStream();
            StreamReader readStream = new StreamReader(respStream, UTF8Encoding.UTF8);
            String response = readStream.ReadToEnd();
            _acctualResponse = response;

            return _acctualResponse;
        }

当然,“web进程”正在异步运行:

Observable.Start(() => _registration.Execute(String.Empty)).Subscribe();

问题是,当UI线程忙时,在UI线程空闲之前不会响应。我不知道为什么。也许有人会帮助我。

修改

我制作一些伪图来可视化我的应用程序的结构。 每个进程必须是异步的,但每个进程必须等待前一个进程的结果。

Application flow

编辑2

Action部分的代码,在所有情况下都很简单,看起来像这样:

public override JsonMap.Response Perform(string token)
        {
            JsonMap.authenticationRequest dataToSend = new JsonMap.authenticationRequest
            {
                tid = token,
                platform = "wp7",
                version = "1.0.0",
                userid = ApplicationData.Instance.UserID
            };
            string jsonDataToSend = JsonConvert.SerializeObject(dataToSend,Formatting.Indented,new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
            string jsonResponse = _webClient.SendString(_serviceURL, jsonDataToSend);
            Response response = JsonConvert.DeserializeObject<Response>(jsonResponse);
            return response;

        }

1 个答案:

答案 0 :(得分:1)

我怀疑您的问题是您正在拨打First()这是一个阻止来电。

每当你致电First()时,你可能会做错事。

你可能已经领先于这条“黑暗路径”,因为你的功能签名也是一个阻塞签名。您需要将其更改为:

public IObservable<string> SendString(string URL, string message)

现在你可以这样编写你的函数:

public IObservable<string> SendString(string URL, string message)
{
    WebRequest hwr = HttpWebRequest.CreateHttp(URL);
    hwr.Method = "POST";

    Func<IObservable<Stream>> getRequest = 
        Observable
            .FromAsyncPattern<Stream>(
                hwr.BeginGetRequestStream,
                hwr.EndGetRequestStream);

    Func<Stream, IObservable<WebResponse>> getResponse = ...

    Func<WebResponse, string> getResult = ...

    return
        from rq in getRequest()
        from rp in getResponse(rq)
        select getResult(rp);
}

请注意,最终查询确实非常简洁。

getResponse函数如下所示:

    Func<Stream, IObservable<WebResponse>> getResponse =
        st =>
        {
            var resp =
                Observable
                    .FromAsyncPattern<WebResponse>(
                        hwr.BeginGetResponse,
                        hwr.EndGetResponse);
            var bytes = UTF8Encoding.UTF8.GetBytes(message);
            st.Write(bytes, 0, bytes.Length);
            st.Close();
            return resp();          
        };

getResult看起来像这样:

    Func<WebResponse, string> getResult =
        wr =>
        {
            using (var st = wr.GetResponseStream())
            {
                using (var sr = new StreamReader(st, UTF8Encoding.UTF8))
                {
                    return sr.ReadToEnd();
                }
            }
        };

最后,您需要订阅生成的observable以获得结果。您可能需要调用ObserveOn来调用以返回UI线程。

如果有帮助,请告诉我。