简体   繁体   English

如何在不阻塞主线程的情况下返回异步HttpWebResponse?

[英]How to return an async HttpWebResponse without blocking the main thread?

I'm making a simple app for connecting to a webservice, and I'm having problems managing async requests. 我正在制作一个用于连接到Web服务的简单应用,但是在管理异步请求时遇到了问题。

The problem is with the function ProcessRequest, which basically makes an async HttpWebRequest, and returns the HttpWebResponse. 问题出在函数ProcessRequest上,该函数基本上使异步HttpWebRequest并返回HttpWebResponse。 As the request is async, I'm having problems with the return value, and with the functions calling the ProcessRequest method and waiting for the HttpWebResponse object. 由于请求是异步的,因此返回值以及调用ProcessRequest方法并等待HttpWebResponse对象的函数遇到问题。

By the way, the request in itself works perfectly, already tested inside functions so I don't need to return an HttpWebResponse. 顺便说一句,该请求本身运行良好,已经在函数内部进行了测试,因此我无需返回HttpWebResponse。

I hope I'm making myself clear, as I said, this is my first time ever touching c#, .NET, and Windows Phone development. 我希望我能像我所说的那样使自己更清楚,这是我第一次接触c#、. NET和Windows Phone开发。 ( And WebRequests for that matter ) (以及与此相关的WebRequest)

The errors that Visual Studio is throwing are: Visual Studio引发的错误是:

1: Since 'System.AsyncCallback' returns void, a return keyword must not be followed by an object expression
2: Cannot convert lambda expression to delegate type 'System.AsyncCallback' because some of the return types in the block are not implicitly convertible to the delegate return type    

And this is the code: 这是代码:

namespace SimpleNoteConcept
{
public sealed class SimpleNote
{
    private static readonly SimpleNote _instance = new SimpleNote();
    private static string _authToken = string.Empty;
    private static string _email = string.Empty;
    private static string _authQsParams
    {
        get
        {
            if (string.IsNullOrEmpty(_authToken)) throw new SimpleNoteConceptAuthorisationException();
            return string.Format("auth={0}&email={1}", _authToken, _email);
        }
    }

    private SimpleNote() { }

    public static SimpleNote Instance
    {
        get { return _instance; }
    }

    public bool Connect(string email, string password)
    {
        try
        {
            StringParamCheck("email", email);
            StringParamCheck("password", password);

            var data = string.Format("email={0}&password={1}", email, password);
            var bytes = Encoding.GetEncoding("utf-8").GetBytes(data);
            data = Convert.ToBase64String(bytes);

            using (var resp = ProcessRequest( loginPath, "POST", content: data))
            {
                if (resp != null)
                {
                    _authToken = resp.Cookies["auth"].Value;
                    _email = email;
                    System.Diagnostics.Debug.WriteLine("Connection established! -> " + _authToken);
                    return true;
                }
                return false;
            }
        }
        catch (Exception)
        {
            throw;
        }

    }

    public void GetIndex(int length = 100, string mark = null, DateTimeOffset? since = null)
    {
        try
        {
            string sinceString = null;
            if (since.HasValue)
                sinceString = Json.DateTimeEpochConverter.DateToSeconds(since.Value);

            var queryParams = string.Format("{0}&length={1}&mark={2}&since={3}", _authQsParams, length, mark, sinceString);
            using (var resp = ProcessRequest( indexPath, "GET", queryParams))
            {
                var respContent = ReadResponseContent(resp);
                System.Diagnostics.Debug.WriteLine("GetIndex: " + respContent.ToString());
                //var notes = JsonConvert.DeserializeObject<Objects.NoteEnumerable<T>>(respContent);
                //return notes;
            }
        }
        catch (WebException ex)
        {
            var resp = (HttpWebResponse)ex.Response;
            switch (resp.StatusCode)
            {
                //401
                case HttpStatusCode.Unauthorized:
                    throw new SimpleNoteConceptAuthorisationException(ex);
                default:
                    throw;
            }
        }
        catch (Exception) { throw; }
    }

    /// <summary>
    /// Generic method to process a request to Simplenote.
    /// All publicly expose methods which interact with the store are processed though this.
    /// </summary>
    /// <param name="requestPath">The path to the request to be processed</param>
    /// <param name="method">The HTTP method for the request</param>
    /// <param name="content">The content to send in the request</param>
    /// <param name="queryParams">Queryparameters for the request</param>
    /// <returns>An HttpWebResponse continaing details returned from Simplenote</returns>
    private static HttpWebResponse ProcessRequest(string requestPath, string method,
                                                  string queryParams = null, string content = null)
    {
        try
        {
            var url = string.Format("{0}{1}{2}", "https://", domainPath, requestPath);
            if (!string.IsNullOrEmpty(queryParams)) url += "?" + queryParams;
            var request = WebRequest.Create(url) as HttpWebRequest;
            request.CookieContainer = new CookieContainer();
            request.Method = method;

            request.BeginGetRequestStream((e) =>
            {
                using (Stream stream = request.EndGetRequestStream(e))
                {
                    // Write data to the request stream
                    var bytesBody = Encoding.GetEncoding("utf-8").GetBytes(content);

                    stream.Write(bytesBody, 0, bytesBody.Length);
                    stream.Close();
                    stream.Dispose();
                }
                request.BeginGetResponse((callback) =>
                {
                    try
                    {
                        HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callback);
                        return response;

                    }
                    catch (WebException ex)
                    {
                        using (WebResponse Exresponse = ex.Response)
                        {
                            HttpWebResponse httpResponse = (HttpWebResponse)Exresponse;
                            System.Diagnostics.Debug.WriteLine("Error code: {0}", httpResponse.StatusCode);
                            using (Stream str = Exresponse.GetResponseStream())
                            {
                                string text = new StreamReader(str).ReadToEnd();
                                System.Diagnostics.Debug.WriteLine(text);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine("Message: " + ex.Message);
                    }
                }, request);
            }, request);

        }
        catch (Exception)
        {
            throw;
        }
    }

    /// <summary>
    /// Reads the content from the response object
    /// </summary>
    /// <param name="resp">The response to be processed</param>
    /// <returns>A string of the response content</returns>
    private static string ReadResponseContent(HttpWebResponse resp)
    {
        if (resp == null) throw new ArgumentNullException("resp");
        using (var sr = new StreamReader(resp.GetResponseStream()))
        {
            return sr.ReadToEnd();
        }
    }

    /// <summary>
    /// String parameter helper method.
    /// Checks for null or empty, throws ArgumentNullException if true
    /// </summary>
    /// <param name="paramName">The name of the paramter being checked</param>
    /// <param name="value">The value to check</param>
    private void StringParamCheck(string paramName, string value)
    {
        if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(paramName, "Value must not be null or string.Empty");
    }

} // Class End

} // Namespace End

Thanks in advance! 提前致谢!

You cannot do async programming the same as normal. 您不能像正常情况那样进行异步编程。 Here .Net is running the async parts in different thread, how can they be communicated? .Net在不同的线程中运行异步部分,如何进行通信? So what you can do is passing a delegate with your ProcessRequest method. 因此,您可以做的是通过您的ProcessRequest方法传递一个委托。 which will take a parameter of HttpWebResponse. 它将采用HttpWebResponse的参数。

Call your method like this: 像这样调用您的方法:

Action<HttpWebResponse> actionDelegate = DoAfterGettingResponse;
ProcessRequest(indexPath, "GET", actionDelegate, queryParams);

Function that handle the response 处理响应的功能

public static void DoAfterGettingResponse(HttpWebResponse resp)
{
    if (resp != null)
    {
        _authToken = resp.Cookies["auth"].Value;
        _email = email;
        System.Diagnostics.Debug.WriteLine("Connection established! -> " + _authToken);

    }

    //Do anything else with the response
}    

ProcessRequest will have the new signature. ProcessRequest将具有新的签名。

private static HttpWebResponse ProcessRequest(
    string requestPath, string method, Action<HttpWebResponse> reponseDelegate,
    string queryParams = null, string content = null)
{
    //Do what you are already doing        
}

And the place where you are returning response, just do 而您返回响应的地方,只需执行

HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callback);
responseDelegate(response);

You can do this way or use events, fire an event passing HttpWebResponse as parameter and handle the response in the listener. 您可以这样做或使用事件,通过HttpWebResponse作为参数触发事件,并在侦听器中处理响应。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM