Brendan Murphy
Brendan Murphy

Reputation: 93

Using HttpClient for Xamarin PCL

I am creating a PCL within Xamarin that is using the Microsoft.Net.Http Nuget package for a HttpClient class. I use the HttpClient to post an audio file to a web API. This has worked well for me up to this point, but now I am having troubles while trying to get the file to be streamed to the API. The API says in its documentation to add set a "Transfer-encoding" header to be "chunked" in order for streaming of the file to be accepted. I can't add this header manually the way I have with other headers, instead a set it from a property of HttpClient. The problem is that when I call HttpClient.PostAsync(), it throws an exception because the SendChunk property of a HttpWebRequest is not True. I'm assuming that the HttpWebRequest object is creating by HttpClient, but I don't know how I can set the SendChunk property to True. When I create a HttpWebRequest object by itself, the SendChunk property is not accessible even though it is a public property. I am guessing that it has something to do with being a PCL, but the SeundChunk property does show up in the Microsoft.Net.Http Assembly.

In short, I need to get the header "Transfer-encoding : chunked" into my HttpClient headers, but can't. How can I add this header while certain properties are unavailable because I am working in a PCL?

public async Task<string> PostAsync(string url, Stream content, Dictionary<string,string> requestHeaders, Dictionary<string,string> contentHeaders)
    {
        var httpClient = new System.Net.Http.HttpClient();
        var httpContent = new System.Net.Http.StreamContent(content);

        httpClient.Timeout = TimeSpan.FromSeconds(20);
        httpClient.DefaultRequestHeaders.TransferEncodingChunked = true;

        if (requestHeaders != null)
        {
            foreach (var headerName in requestHeaders.Keys)
            {
                httpClient.DefaultRequestHeaders.Add(headerName, requestHeaders[headerName]);
            }
        }
        if (contentHeaders != null)
        {
            foreach (var headerName in contentHeaders.Keys)
            {
                httpContent.Headers.Add(headerName, contentHeaders[headerName]);
            }
        }

        HttpResponseMessage response = null;

        try
        {
            response = await httpClient.PostAsync(url, httpContent);
        }

EDIT:

I've update my code to look like this

             HttpClientHandler handler = new HttpClientHandler();

        System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient(handler);
        httpClient.DefaultRequestHeaders.TransferEncodingChunked = true;

        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url);

        var httpContent = new System.Net.Http.StreamContent(content);

        request.Content = httpContent;

        if (handler.SupportsTransferEncodingChunked())
        {
            request.Headers.TransferEncodingChunked = true;
        }

        HttpResponseMessage response = null;


            response = await httpClient.SendAsync(request);

SendAsync throws an exception saying "System.Net.ProtocolViolationException: SendChunked should be true". I modeled my code after this post http://blogs.msdn.com/b/bclteam/archive/2013/02/18/portable-httpclient-for-net-framework-and-windows-phone.aspx.

Upvotes: 1

Views: 10346

Answers (2)

TResponse
TResponse

Reputation: 4125

I found a handly library from this link on the Xamarin Forums; https://forums.xamarin.com/discussion/25274/httpclient-in-pcl

There is a Nuget Package by Robert McLaws and Richard Beauchamp called PortableRest.

Its a library for consuming REST APIs from Portable Class Libraries (.NET 4.5, Silverlight 5, Windows Phone 8.x, and Windows 8.x). Designed to be partially drop-in compatible with RestSharp.

GitHub link here: https://github.com/AdvancedREI/PortableRest Nuget package here: https://www.nuget.org/packages/PortableRest

Source: https://forums.xamarin.com/discussion/25274/httpclient-in-pcl

To use this:

var client = new RestClient { BaseUrl = Constants.API_BASE_URI };
var request = new RestRequest("Token", HttpMethod.Post, ContentTypes.FormUrlEncoded);
request.AddHeader("Accept", "application/json");
request.AddParameter("grant_type", "password", ParameterEncoding.UriEncoded);
request.AddParameter("username", userEntry.Text, ParameterEncoding.UriEncoded);
request.AddParameter("password", passwordEntry.Text, ParameterEncoding.UriEncoded);

var result = await client.SendAsync<AuthToken>(request);

Upvotes: 0

Jazzeroki
Jazzeroki

Reputation: 163

I'm trying to deal with a similar situation. I've come across a couple of options that may help.

ModernHTTPClient

or this Rest Sharp

As a status update, I did get ModernHTTPClient to work. My solution though I had to delete the contents of my package folder, then install that nuget package, and then restore my other packages. Otherwise the solution was a simple as

var httpClient = new HttpClient(new NativeMessageHandler());

Upvotes: 1

Related Questions