I was recently tasked with converting a vendor-provided web form to a more robust ASP.Net page. This form would be public facing, would POST user data from the form to the vendor, and would require extensive validations/manipulations before posting. This needed to happen without the use of javascript or any client-side validation. To keep it simple, I created a new ASP.Net page and reconstructed the vendor form using all ASP.Net controls. The “Submit” button called a code-behind method which performed the validations, then built a NameValueCollection from the form controls and submitted it using WebClient.UploadValues, like so:
System.Net.WebClient myWebClient = new System.Net.WebClient(); myWebClient.Headers.Add("Charset", "text/html; charset=UTF-8"); NameValueCollection frm = new NameValueCollection(); // Perform server-side validations if (this.F_Name.Text.Length == 0 || this.L_Name.Text.Length == 0) { AppendError("First and Last name must be provided"); } … // Add the user-provided name values frm.Add("last_name", this.L_Name.Text); frm.Add("first_name", this.F_Name.Text); frm.Add("address", this.Address.Text); … // Add the Toppings foreach (ListItem item in this.ToppingsChkBoxList.Items) { if (item.Selected) { Frm.Add("Toppings", item.Value.ToString()); } } myWebClient.UploadValues("http://www.Destination.com/...?encoding=UTF-8", "POST", frm);
This solution worked like a charm, except for one small problem. For the Toppings field, the vendor allowed for multiple selections. In their sample form, they used the <SELECT MULTIPLE… /> control to gather multiple values from the user. In Fiddler, multiple selections for this field looked something like this:
Toppings=Extra+cheese&Toppings=Mushrooms&Toppings=Pepperoni&Toppings=Olives
NameValueCollection does not handle multiple values for the same key in this way. Instead, the NameValueCollection would read my Toppings control as:
&Toppings=Extra+cheese,Mushrooms,Pepperoni,Olives
The vendor’s import process was reading this as a single value, rather than multiple values as intended, causing the upload to fail. To get around this, I used WebClient.UploadString instead to build an uploadable string from scratch. Now, my upload process looks like this:
StringBuilder _strBld = new StringBuilder();
int _intItemCount = 0;
protected void btnSubmit_Click(object sender, EventArgs e)
{
System.Net.WebClient myWebClient = new System.Net.WebClient();
myWebClient.Headers.Add("Charset", "text/html; charset=UTF-8");
myWebClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); // ◄ This line is essential
// Perform server-side validations (same as before)
if (this.F_Name.Text.Length == 0 || this.L_Name.Text.Length == 0)
{ AppendError("First and Last name must be provided"); }
…
// Add the user-provided name values
AppendUploadString("last_name", this.L_Name.Text);
AppendUploadString ("first_name", this.F_Name.Text);
AppendUploadString ("address", this.Address.Text);
// Add the Toppings
foreach (ListItem item in this.ToppingsChkBoxList.Items)
{
if (item.Selected)
{
AppendUploadString("Toppings", item.Value.ToString());
}
}
myWebClient.UploadString("https http://www.Destination.com/...?encoding=UTF-8", "POST", _strBld.ToString());
}
private void AppendUploadString(string strName, string strValue)
{
_intItemCount++;
_strBld.Append((intItemCount == 1 ? "" : "&") + strName + "=" + strValue);
_strBld.Append((intItemCount == 1 ? "" : "&") + strName + "=" + System.Web.HttpUtility.UrlEncode(strValue));
// Update: Use UrlEncode to ensure that the special characters are included in the submission
}
To get around the NameValueCollection restriction, I built my own string and submitted is using WebClient.UploadString.
A concise description of WebClient can be found here.