WebHeaderCollection & HttpWebRequest on Xamarin

此生再无相见时 提交于 2019-12-03 21:32:56

There is no implementation of the things mentioned by you so far. But that's ok. They still do their work great!

Answering to your questions.

Error 3. Yes. Currently you can use only Headers["key"] = value. But. Not for every header. I was trying to put "Content-Length" there (as there is no "ContentLength" property implemented as well), but got "restricted headers" exception. However, Request POST processed successfully for me, so I let it go.

Error 4. Yes. There is no such method. (The same way, as there is no "GetRequestStream" (For instance, if you want to write POST data to request stream)). Good news is that there are BeginGetResponse and BeginGetRequestStream respectively, and C# action methods simplify all that kitchen.

(plus, I am sure, that's pretty useful for asynchronous practices general understanding).

Basic sample can be found on Microsoft official docs.

But to do it with actions I used the following:

    public void MakeRequest(string url, string verb, Dictionary<string, string> requestParams,
        Action<string> onSuccess, Action<Exception> onError)
    {
        string paramsFormatted;

        if (verb == "GET")
        {
            paramsFormatted = string.Join("&", requestParams.Select(x => x.Key + "=" + Uri.EscapeDataString(x.Value)));
            url = url + (string.IsNullOrEmpty(paramsFormatted) ? "" : "?" + paramsFormatted);
        }
        else
        {
            // I don't escape parameters here,
            // as Uri.EscapeDataString would throw exception if the parameter length
            // is too long, so you must control that manually before passing them here
            // for instance to convert to base64 safely
            paramsFormatted = string.Join("&", requestParams.Select(x => x.Key + "=" + (x.Value)));
        }

        var request = (HttpWebRequest)WebRequest.Create(url);
        request.Method = verb;

        requestParams = requestParams ?? new Dictionary<string, string>();

        Action goRequest = () => MakeRequest(request, 
            response =>
            {
                onSuccess(response);
            },
            error =>
            {
                if (onError != null)
                {
                    onError(error);
                }
            });

        if (request.Method == "POST")
        {
            request.BeginGetRequestStream(ar =>
            {
                using (Stream postStream = request.EndGetRequestStream(ar))
                {
                    byte[] byteArray = Encoding.UTF8.GetBytes(paramsFormatted);
                    postStream.Write(byteArray, 0, paramsFormatted.Length);
                }
                goRequest();
            }, request);
        }
        else // GET
        {
            goRequest();
        }
    }

    private void MakeRequest(HttpWebRequest request, Action<string> onSuccess, Action<Exception> onError)
    {
        request.BeginGetResponse(token =>
        {
            try
            {
                using (var response = request.EndGetResponse(token))
                {
                    using (var stream = response.GetResponseStream())
                    {
                        var reader = new StreamReader(stream);
                        onSuccess(reader.ReadToEnd());
                    }
                }
            }
            catch (WebException ex)
            {
                onError(ex);
            }
        }, null);
    }

To answer error 4, I made two extension methods so that I can have the GetRespone() and GetRequestStream() methods in the WebRequest class and working like their original versions i.e. blocking the thread. So here it is:

public static class ExtensionMethods
{
    public static WebResponse GetResponse(this WebRequest request){
        ManualResetEvent evt = new ManualResetEvent (false);
        WebResponse response = null;
        request.BeginGetResponse ((IAsyncResult ar) => {
            response = request.EndGetResponse(ar);
            evt.Set();
        }, null);
        evt.WaitOne ();
        return response as WebResponse;
    }

    public static Stream GetRequestStream(this WebRequest request){
        ManualResetEvent evt = new ManualResetEvent (false);
        Stream requestStream = null;
        request.BeginGetRequestStream ((IAsyncResult ar) => {
            requestStream = request.EndGetRequestStream(ar);
            evt.Set();
        }, null);
        evt.WaitOne ();
        return requestStream;
    }
}

Just make sure to place this in a different namespace than your regular code and import that namespace. Then you will have the GetResponse() method for WebRequest instances. Oh and also GetRequestStream() which is usefull for sending POST data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!