Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET Form Data Helper Class

0.00/5 (No votes)
7 Apr 2010 1  
A utility class allowing you to deal with form data as a collection.

Introduction

One of the most common things that .NET WebForms developers deal with is form data. Treating form data as a strongly typed editable collection improves the handling of form data greatly. I have created a wrapper class that handles many of the common scenarios developers run into. It allows form data to be read in as input for processing, and/or allows a collection to be created that can subsequently be used to pass data between pages as POST or GET data.

Here are the primary features provided by this library. When exporting the collection data into a querystring , it URL-encodes the value data for you, and when exporting the collection data into hidden variables in a form to be posted, it HTML-encodes this data. A very useful feature is that it provides the capability to use thread local storage (TLS) to allow the Server.Transfer API call result in data being available in the page that execution has been transferred to. The ASP.NET model only permits the existing read-only collection of form data to be relayed to the transferred page.

I have created a test page that allows you to experiment with almost all of the import and export options. It allows you to submit the source page using either the GET or POST method. You always have the choice to Response.Redirect using the GET method, or Server.Transfer with TLS storing data between page. The other sample page provided shows how to take data passed into a page upon its initial load and store this data as a set of hidden fields on the form.

The code is extremely straightforward, yet is among the most useful utility classes that I work with. Data is imported using the BuildFromGetRequest, BuildFromPostRequest, and BuildFromTls methods. Key value pairs can also be added or removed. Data is exported, if necessary, using the ToPostForm, ToQueryString, and ToTls methods.

The only bit of code that is somewhat esoteric is the TLS-related API calls in System.Threading. First, we allocate a named data slot using a name of our choice, with the Thread.AllocateNamedDataSlot call. Since ASP.NET will use a thread per request, we are safe (unless the asynchronous page model is specifically being utilized) in using a constant name. Second, we obtain a reference to the data slot with Thread.GetNamedDataSlot. Finally, we call the Thread.SetData API to assign the collection to the data slot.

Retrieving TLS data is similar in nature to setting TLS data. First, the reference to the data slot is retrieved as above. Subsequently, the Thread.GetData API will retrieve the collection. It is important to remember to deallocate the memory being used, with the Thread.FreeNamedDataSlot call.

There are a few usage considerations worth noting in the class. TLS data is only useful in processing a single request. After a response is returned to the user, the thread will be returned to the thread pool. Another scenario worth noting is when a page has several text fields with the same name. These fields are provided as a series of comma-delimited values for the name attribute used. For example, if the fields have values val1 and val2, the results would be "val1, val2". Supporting this usage would be difficult at best. I ignore this scenario and treat the results as a single value (as above). Another design choice is that if you add an entry whose key already exists in the collection, then the old entry is deleted. Yet another design choice made was to always remove the entry, if it exists, with a key value of submit, since this is commonly used as the name of the Submit button field.

Imports System.Collections.Specialized
Imports System.Text
Imports System.Threading
Public Class HttpFormUtil
Inherits System.Object
'allocating here to prevent misuse with null reference

    Private fc As New NameValueCollection
    Private sActionPage As String
    Public Sub Add(ByVal sKeyName As String, ByVal sValString As String)
        If Not fc.Item(sKeyName) Is Nothing Then
            fc.Remove(sKeyName)
        End If
        fc.Add(sKeyName, sValString)
    End Sub

    Public Function Count() As Integer
        Return fc.Count()
    End Function  

    Public Sub Remove(ByVal sKeyName As String)
       If Not fc.Item(sKeyName) Is Nothing Then
           fc.Remove(sKeyName)
       End If
    End Sub

    Public Function Lookup(ByVal sKeyName As String) As String
        Dim sValueString As String
        sValueString = fc.Item(sKeyName)
        If sValueString Is Nothing Then   
            sValueString = String.Empty
        End If    
        Return sValueString
    End Function

    Public Sub BuildFromPostRequest()
        fc = New NameValueCollection(System.Web.HttpContext.Current.Request.Form)
    End Sub
    
    Public Sub BuildFromGetRequest()
        fc = New NameValueCollection(System.Web.HttpContext.Current.Request.QueryString)
End Sub
    
Public Sub BuildFromTls()
    Dim dataSlot As LocalDataStoreSlot  
    Dim retrievedData As Object  
    dataSlot = Thread.GetNamedDataSlot("passedData")
    retrievedData = Thread.GetData(dataSlot)
    Try
        If retrievedData Is Nothing Then
        'do nothing
        Else
            fc = CType(retrievedData, NameValueCollection)
        End If
    Catch ex As Exception
    'treat collection has having nothing in it.
        fc = New NameValueCollection
    Finally
        Try
            Thread.FreeNamedDataSlot("passedData")
        Catch ex As Exception
        End Try
    End Try
End Sub

Public Function ToPostForm() As String
    Dim iCurrElem As Integer  
    Dim sb As New StringBuilder
    Remove("submit")
    For iCurrElem = 0 To fc.Count - 1
        sb.Append("<input type=""hidden"" name =""")
      sb.Append( System.Web.HttpContext.Current.Server.HtmlEncode(fc.Keys(iCurrElem)))
    sb.Append(""" value=""")
    sb.Append( System.Web.HttpContext.Current.Server.HtmlEncode(fc.Get(iCurrElem)))
    sb.AppendLine(""" />")  
    Next  
    Return sb.ToString() 
End Function

Public Function ToQueryString() As String
    Dim sb As New StringBuilder
    Dim oPageContext As System.Web.HttpContext   
    Dim iCurrElem As Integer  
    oPageContext = System.Web.HttpContext.Current    
    Remove("submit")
    For iCurrElem = 0 To fc.Count - 1
        If iCurrElem = 0 Then
            sb.Append("?")
        Else
            sb.Append("&")
        End If
        sb.Append(oPageContext.Server.UrlEncode(fc.Keys(iCurrElem)))
        sb.Append("=")
        sb.Append(oPageContext.Server.UrlEncode(fc.Get(iCurrElem)))    
    Next   
    Return sb.ToString()    
End Function
    
Public Sub ToTls() 
    Dim dataSlot As LocalDataStoreSlot    
    Remove("submit")   
    Thread.AllocateNamedDataSlot("passedData")
    dataSlot = Thread.GetNamedDataSlot("passedData")
    Thread.SetData(dataSlot, fc)
End Sub
    
Public Function ToDictionary() As Dictionary(Of String, String)
    Dim oList As New Dictionary(Of String, String)  
    For Each currEntry As String In fc.AllKeys 
        oList.Add(currEntry, fc(currEntry))   
    Next  
    Return oList
End Function
End Class

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here