PixelPaul
PixelPaul

Reputation: 2801

size limit workaround for FormUrlEncodedContent

I'm receiving the error:

System.UriFormatException: Invalid URI: The Uri string is too long.

The problem is with this line:

FormUrlEncodedContent content = new FormUrlEncodedContent(postData); 

Upon researching this I've learned it is because of a size limitation of the class FormUrlEncodedContent. But I'm not sure how I can workaround this? See code below:

 public Token RequestToken(string username, int businessID, string requestXml)
    {
        var postData = new Dictionary<string, string>() { { "username", username }, { "businessID", businessID.ToString() }, { "authenticator", requestXml } };
        FormUrlEncodedContent content = new FormUrlEncodedContent(postData);          

        try
        {
            HttpResponseMessage response = _client.PostAsync("Token", content).Result;
            if (response.IsSuccessStatusCode)
            {
                return response.Content.ReadAsAsync<Token>().Result;
            }
        }
        catch (Exception ex)
        {
            log.Error(ex);
        }

        return null;
    }

Can anyone help with this?

Upvotes: 6

Views: 4606

Answers (3)

Michael Torgovitsky
Michael Torgovitsky

Reputation: 21

This one is working:

using (HttpClient httpClient = new HttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Post, "your_postUrl")
var formUrlEncodedData = ToFormUrlEncoded(collection);
var content = new StringContent("your_content_payload",Encoding.UTF8,"application/x-www-form-urlencoded");
request.Content = content;
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
return result = await response.Content.ReadAsStringAsync();
}

static string ToFormUrlEncoded(Dictionary<string, string> data)
{
    var formData = new StringBuilder();
    foreach (var kvp in data)
    {
        if (formData.Length > 0)
            formData.Append('&');
        formData.Append($"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}");
    }
    return formData.ToString();
}

Upvotes: 0

Marco Scabbiolo
Marco Scabbiolo

Reputation: 7459

Let's adapt your existing code to the solution in this post

int limit = 2000;

StringContent content = new StringContent(postData.Aggregate(new StringBuilder(), (sb, nxt) => {

    StringBuilder sbInternal = new StringBuilder();

    if (sb.Length > 0)
    {
        sb.Append("&");
    }

    int loops = nxt.Value.Length / limit;

    for (int i = 0; i <= loops; i++)
    {
        if (i < loops)
        {
            sbInternal.Append(Uri.EscapeDataString(nxt.Value.Substring(limit * i, limit)));
        }
        else
        {
            sbInternal.Append(Uri.EscapeDataString(nxt.Value.Substring(limit * i)));
        }
    }

    return sb.Append(nxt.Key + "=" + sbInternal.ToString());
}).ToString(), Encoding.UTF8, "application/x-www-form-urlencoded");

Quick walkthrough that code: Implode each key-value pair (parameter) in your dictionary with LINQ's Aggregate using a limit-proof URL encoding method.

The length of string parameter of Uri.EscapteDataString method is limited to 32766 characters, the limit local property must be 32766 to avoid unnecessary iteration.

This is how you should create you content now, instead of using FormUrlEncodedContent

Hopefully it'll help.

Upvotes: 3

michal.jakubeczy
michal.jakubeczy

Reputation: 9479

If your request is larger use multipart/form-data instead:

using (var content = new MultipartFormDataContent())
{
    foreach (var keyValuePair in data)
    {
        content.Add(new StringContent(keyValuePair.Value), keyValuePair.Key);
    }

    // send POST request
    using (var client = new HttpClient())
    {
        return client.PostAsync(identifier.IsirUrl + uri, content).GetAwaiter().GetResult();
    }
}

Upvotes: 4

Related Questions