简体   繁体   中英

Refactor HttpWebRequest to HttpClient?

How would I convert this to HttpClient? What I'm looking to do is submit a Tweet to the Twitter api and get the response as Json. The HttpWebRequest is working fine but I just want to port it to HttpClient. I made an attempt at it in the second code example, but it's not actually sending or receiving the response.

HttpWebRequest request = null;
WebResponse response = null;
string responseCode = String.Empty;
try
{
    string postBody = "status=" + EncodingUtils.UrlEncode(status);

    request = (HttpWebRequest)HttpWebRequest.Create(resource_url);        
    request.ServicePoint.Expect100Continue = true;
    request.UseDefaultCredentials = true;
    request.PreAuthenticate = true;
    request.Credentials = CredentialCache.DefaultCredentials;
    request.ServicePoint.ConnectionLimit = 1;
    request.Headers.Add("Authorization", authHeader);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";

    using (Stream stream = request.GetRequestStream())
    {
        using (StreamWriter writer = new StreamWriter(stream))
        {                       
            writer.Write(postBody);
        }
    }
    using (response = request.GetResponse())
    {
        response.ContentType = "application/json";
        responseCode = ((HttpWebResponse)response).StatusCode.ToString();
    }
}
catch (WebException ex)
{
    if (ex.Status != WebExceptionStatus.NameResolutionFailure)
    {
        request.Abort();
        request = null;
    }
    throw ex;
}
return responseCode;

This is what I've tried to get it work:

private async Task<string> MakeWebRequest1(string status, string resource_url, string authHeader)
    {
        HttpClientHandler clientHandler = new HttpClientHandler();
        clientHandler.Credentials = CredentialCache.DefaultCredentials;
        clientHandler.PreAuthenticate = true;
        clientHandler.AllowAutoRedirect = true;
        string responseCode = "";
        string postBody = "status=" + EncodingUtils.UrlEncode(status);
        var request = new HttpRequestMessage()
        {
            RequestUri = new Uri(resource_url),
            Method = HttpMethod.Post,

        };
        request.Headers.Add("Authorization", authHeader);
       // request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
        request.Content = new StringContent(postBody, Encoding.UTF8,"application/x-www-form-urlencoded");//CONTENT-TYPE header

        using (HttpClient client = new HttpClient(clientHandler))
        {
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
            //  Stream stuff = await client.GetStreamAsync(resource_url);
            using (HttpResponseMessage response = await client.SendAsync(request))
            {
                response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                if(response.StatusCode == HttpStatusCode.OK)
                {
                    responseCode = "OK";
                }
            }
        }
        clientHandler.Dispose();
        return responseCode;
    }
enter code here

I've tried to add another parameter to the request and it's always coming back as 401 unauthorized. I'm trying to create a Twitter thread. If I remove the in_reply_to_status_id then it's fine.

data = new Dictionary<string, string> {
      ["status"] = "@username + status,
      ["in_reply_to_status_id"] = "1167588690929115136"
};

The Twitter API describes it here https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update

Reference You're using HttpClient wrong to understand why a static client is being used.

static Lazy<HttpClient> client = new Lazy<HttpClient>(() => {
    HttpClientHandler clientHandler = new HttpClientHandler {
        Credentials = CredentialCache.DefaultCredentials,
        PreAuthenticate = true,
        AllowAutoRedirect = true
    };
    return new HttpClient(clientHandler);
});

private async Task<string> PostStatusRequestAsync(string status, string resource_url, string authHeader) {
    using (var request = new HttpRequestMessage(HttpMethod.Post, resource_url)) {
        request.Headers.TryAddWithoutValidation("Authorization", authHeader);
        request.Headers.Accept.Clear();
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        var data = new Dictionary<string, string> {
            ["status"] = status
        };

        request.Content = new FormUrlEncodedContent(data);

        using (HttpResponseMessage response = await client.Value.SendAsync(request)) {
            return response.StatusCode.ToString();
        }
    }
}

Note the use of the FormUrlEncodedContent for the request body, which will encode and concatenate the data as well as take care of the mime type header

...but it's not actually sending or receiving the response.

Ensure that the above is not invoked as a synchronous blocking call, like .Result , which could cause a deadlock.

For example, an async event handler can be used to make the async call

public async void onButtonClick(object sender, EventArgs args) {
    //Non-blocking call
    var tweetRequestCode = await PostStatusRequestAsync(TweetText, AuthUtils.GetResourceUrl(), AuthUtils.GetWebRequestHeader())); 

    //back on UI thread
    //...
}

Reference Async/Await - Best Practices in Asynchronous Programming

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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