Anhonga's Blog

May 6, 2010

Using WebClient with UploadValues and UploadString to simulate POST

Filed under: Uncategorized — Tags: , , , , , — anhonga @ 7:57 pm

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.

Blog at WordPress.com.