38

Given the following attempt to post data to a web service that generates PDF files, PDF rocket (which is awesome by the way).

I get the error Invalid URI: The uri string is too long
Why would anyone impose an arbitrary limit on POSTed data?

using (var client = new HttpClient())
{
 // Build the conversion options
 var options = new Dictionary<string, string>
 {
 { "value", html },
 { "apikey", ConfigurationManager.AppSettings["pdf:key"] },
 { "MarginLeft", "10" },
 { "MarginRight", "10" }
 };
 // THIS LINE RAISES THE EXCEPTION
 var content = new FormUrlEncodedContent(options);
 var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
 var result = await response.Content.ReadAsByteArrayAsync();
 return result;
}

I receive this rediculous error.

 {System.UriFormatException: Invalid URI: The Uri string is too long.
 at System.UriHelper.EscapeString
 at System.Uri.EscapeDataString
 at System.Net.Http.FormUrlEncodedContent.Encode
 at System.Net.Http.FormUrlEncodedContent.GetContentByteArray

This reminds me of 640k ought to be enough... I mean really?

asked Jul 18, 2016 at 15:29
6
  • With a post can include the content in the http message instead of the URI. A uri has a max length of 2083 characters. Commented Jul 18, 2016 at 15:30
  • aaah, that makes sense, how? Commented Jul 18, 2016 at 15:31
  • 1
    Also why use a web service to make PDF from HTML when you can do it yourself with a free library? Commented Jul 18, 2016 at 15:32
  • See this so question, in this instance they send it as json in the http message. There is no limitation on data length when it is done this way. Create a json string using JsonConvert.SerializeObject and then send as string content using StringContent and send that. Commented Jul 18, 2016 at 15:35
  • Am I therefore correct in saying that there is no built in equivalent in HttpClient for UploadValues("https://api.html2pdfrocket.com/pdf", options) in the WebClient class? Commented Jul 18, 2016 at 15:39

5 Answers 5

55

If, like me, you're faced with some wonky 3rd party web service that will only accept form content, you can work around the problem like this:

// Let's assume you've got your key-value pairs organised into a nice Dictionary<string, string> called formData
var encodedItems = formData.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");
// Post away!
var response = await client.PostAsync(url, encodedContent);
answered Aug 15, 2018 at 7:07
Sign up to request clarification or add additional context in comments.

3 Comments

Best answer here. Needs upvoting.
This saved the day!
Note that Uri.EscapeDataString conforms to RFC2986 (for example, "!" is escaped and spaces are hexified) but WebUtility.UrlEncode doesn't ("!" is unaltered, spaces become "+").
26

With a post can include the content in the http message instead of the URI. A uri has a max length of 2083 characters. You could send it as JSON in the http message instead of the URI which is the recommended way to send larger chunks of data in an HttpPost/HttpPut. I altered your code to make use of it. This assumes that your service you are contacting can work with JSON (.net Web Api out of the box should have no problem with this).

using (var client = new HttpClient())
{
 // Build the conversion options
 var options = new 
 {
 value = html,
 apikey = ConfigurationManager.AppSettings["pdf:key"],
 MarginLeft = "10",
 MarginRight = "10"
 };
 // Serialize our concrete class into a JSON String
 var stringPayload = JsonConvert.SerializeObject(options);
 var content = new StringContent(stringPayload, Encoding.UTF8, "application/json");
 var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
 var result = await response.Content.ReadAsByteArrayAsync();
 return result;
}

Make sure to install newtonsoft json.

Black
20.9k47 gold badges188 silver badges300 bronze badges
answered Jul 18, 2016 at 15:39

7 Comments

thanks, I didn't read the name of the class carefully enough, I thought it was already a regular post. Thanks.
it would be nice to know if there's a built in equivalent to the WebClient, UploadValues method, which doesn't use json, and still manage to post all the content.
@Jim - this SO answer might be the approach you are looking for.
thanks, that example posts a single value, but the principle applies - crazy it's not built in - thanks for your help.
as a matter of interest, the data I am posting is actually not in the url, it's posted exactly like StringContent. The error is not in using an incorrect method, the error is in an arbitrary limit on the EscapeDataString that FormUrlEncodedContent happens to use.
|
13

I just solved a similar problem. For me I was integrating with a backend I didn't control and had to POST file along with form data (eg customerID) as form variables. So switching to JSON or Multipart would break the backend I didn't control. The problem was that large files would cause the FormUrlEncodedContent to throw an error saying "The uri string is too long".

This is the code that solved it for me after two days of effort (note still needs to be tweaked to be ASYNC).

private string UploadFile(string filename, int CustomerID, byte[] ImageData) {
 string Base64String = "data:image/jpeg;base64," + Convert.ToBase64String(ImageData, 0, ImageData.Length);
 var baseAddress = new Uri("[PUT URL HERE]");
 var cookieContainer = new CookieContainer();
 using (var handler = new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = cookieContainer })
 using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
 {
 try {
 //ENCODE THE FORM VARIABLES DIRECTLY INTO A STRING rather than using a FormUrlEncodedContent type which has a limit on its size. 
 string FormStuff = string.Format("name={0}&file={1}&id={2}", filename, HttpUtility.UrlEncode(Base64String), CustomerID.ToString());
 //THEN USE THIS STRING TO CREATE A NEW STRINGCONTENT WHICH TAKES A PARAMETER WHICH WILL FormURLEncode IT AND DOES NOT SEEM TO THROW THE SIZE ERROR
 StringContent content = new StringContent(FormStuff, Encoding.UTF8, "application/x-www-form-urlencoded");
 //UPLOAD
 string url = string.Format("/ajax/customer_image_upload.php");
 response = client.PostAsync(url, content).Result;
 return response.Content.ToString();
 }
 catch (Exception ex) {
 return ex.ToString();
 }
 }
 }
answered Jan 23, 2018 at 3:52

Comments

8

@Mick Byrne : Thanks - your solution worked like a charme!

Here is my complete code:

 public async Task DateienSendenAsync (string PfadUndDatei, string Dateiname, String VRPinGUID, String ProjektGUID, String VRPinX, String VRPinY, String VRPinZ)
 {
 var client = new HttpClient();
 // Create the HttpContent for the form to be posted.
 var requestContent = new[] {
 new KeyValuePair<string, string>("dateiname", Dateiname),
 new KeyValuePair<string, string>("bild", Convert.ToBase64String(File.ReadAllBytes(PfadUndDatei))),
 new KeyValuePair<string, string>("VRPinGUID", VRPinGUID),
 new KeyValuePair<string, string>("ProjektGUID", ProjektGUID),
 new KeyValuePair<string, string>("ebene", "ebene"),
 new KeyValuePair<string, string>("raumnummer", "raumnummer"),
 new KeyValuePair<string, string>("ansichtsname", "ansichtsname"),
 new KeyValuePair<string, string>("VRPinX", VRPinX),
 new KeyValuePair<string, string>("VRPinY", VRPinY),
 new KeyValuePair<string, string>("VRPinZ", VRPinZ),
 };
 String url = "http://yourhomepage/path/upload.php";
 var encodedItems = requestContent.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
 var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");
 // Post away!
 var response = await client.PostAsync(url, encodedContent);
 }
answered Oct 13, 2018 at 14:46

Comments

-1

Completely working code, in Form URL Encoded format:

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();
}
answered Apr 1, 2024 at 12:05

1 Comment

Thank you for contributing to the Stack Overflow community. This may be a correct answer, but it’d be really useful to provide additional explanation of your code so developers can understand your reasoning. This is especially useful for new developers who aren’t as familiar with the syntax or struggling to understand the concepts. Would you kindly edit your answer to include additional details for the benefit of the community?

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.