To read the article online, visit http://www.4GuysFromRolla.com/articles/110106-1.aspx

Accessing and Updating Data in ASP.NET: Creating Custom Parameter Controls

By Scott Mitchell


Introduction


As discussed in previous installments of this article series, ASP.NET 2.0 ships with a number of built-in data source controls that can be used to programmatically access data (the SqlDataSource, ObjectDataSource, XmlDataSource, and so on). The SqlDataSource and ObjectDataSource commonly return or modify data based upon parameters. For example, a SqlDataSource might use a parameterized query, like SELECT * FROM TableName WHERE ColumName = @parameterName; the ObjectDataSource's parameters are those expected input parameters to the methods it invokes. In either case, the values of the parameters can be specified using Parameter controls. (See Filtering Database Data with Parameters installment for more information on using parameters with the data source controls.)

A Parameter controls is a control whose purpose is to provide a value for a given parameter. ASP.NET 2.0 ships with seven Parameter controls - the generic ControlParameter and the more specific ControlParameter, CookieParameter, FormParameter, ProfileParameter, QueryStringParameter, and SessionParameter controls - which pull their values from web controls on the page, session state, querystring fields, and so on.

If you need to use a value that's not provided by one of the specific Parameter controls, you can use the generic Parameter control and set its value programmatically (a topic we'll address in a future article in this series). Alternatively, you can create a custom Parameter control that grabs the specific data you need. Creating such a custom Parameter control is quite easy and straightforward, as we'll see in this article. Read on to learn more!

Parameter Control Basics


The Parameter class in the .NET Framework's System.Web.UI.WebControls namespace spells out the core functionality of every Parameter control. At a minimum, a Parameter control must provide an Evaluate() method that returns the value for the parameter. This Evaluate() method is passed two input parameters:
  • An HttpContext object that represents the context of the HTTP request, and includes the intrinsic server objects - Request, Session, and so on, and
  • A reference to the control that the Parameter control is bound to (the SqlDataSource or ObjectDataSource)
The Evaluate() method simply returns the value for the parameter and, as such, the code for this method is typically very short and simple. For example, the built-in QueryStringParamter, which returns the value of a specified querystring field, has an Evaluate() method that's a scant three lines of code. It checks to ensure that the passed-in HttpContext object is not null, and that its Request object is not null, and then returns context.Request.QueryString(QueryStringField) (where QueryStringField is the QueryStringParamter property that specifies the name of the querystring field whose value to use).

When creating a custom Parameter control, we'll also want to override the Parameter class's Clone() method. The Clone() method creates a deep copy of the parameter object and needs to be provided in order to enjoy design-time support for custom Parameter controls; see Eilon Lipton's blog entry, Custom Parameters for Data Sources for more information on the need for supplying the Clone() method to obtain design-time support.

That's all there is to a Parameter control! In addition to creating the Evaluate() and Clone() methods, we might also want to add control properties that affect the value returned from Evaluate(). (Like how the QueryStringParamter's QueryStringField property is used to indicate the querystring field name whose value is to be returned.) The remainder of this article examines two custom Parameter controls I created, which can be downloaded at the end of this article and immediately used in your ASP.NET 2.0 applications!

Creating a Parameter Control to Return the Current Date and Time


In certain scenarios we want to have the current date and time inserted into a particular date/time value. For example, imagine that we had an Employees database table that, among other columns, had a HireDate column. When adding a new employee through the website, we might want to have the HireDate value be today's date and time. Or we may want to have a data source control that returns all employees hired today. Unfortunately, there's no built-in Parameter control that returns the current date and time, meaning we have to have this parameter value set programmatically.

Let's examine how to create our own TodayParameter control that returns the current date (and, optionally, the time). This parameter was inspired by Eilon Lipton's Custom Parameters for Data Sources blog entry. The code we'll be examining is in VB; Eilon's blog entry provides similar functionality, but is written in C#.

In the download you'll find a Visual Studio 2005 Solution that includes two projects: skmParameters, a Visual Basic Control Library project, and TestWebsite, which is a file system-based website for testing skmParameters. The TodayParameter.vb file in skmParameters includes the code for the TodayParameter control. In the simplest form, we could create the TodayParameter control so that it blindly returns the current date and time:

Imports System.ComponentModel
Imports System.Web.UI.WebControls

Public Class TodayParameter
    Inherits Parameter

    Protected Overrides Function Evaluate(ByVal context As System.Web.HttpContext, ByVal control As System.Web.UI.Control) As Object
       Return DateTime.Now
    End Function
End Class

That's all there is to it! Of course without the Clone() method, the TodayParameter control will need to be modified through the declarative syntax (as there will be no design-time support), but it meets the minimum requirements. To use this parameter in an ASP.NET page, you'd first need to add a reference to the project (or drop the DLL from the project into the website's /bin folder), and then "register" the control (either at the page level or in Web.config). At the page level, this can be accomplished by using the <% @Register %> directive like so:

<%@ Register Assembly="skmParameters" Namespace="skmParameters" TagPrefix="skm" %>

Then, in one of the SqlDataSource or ObjectDataSources parameters collections, the TodayParameter control can be used. In the download at the end of this article you'll find a demo page (TodayParameter.aspx) that provides a DetailsView that allows new employees to be added to the Employees table. When adding a new employee, the HireDate value is determined via the TodayParameter control (resulting in the current date/time). The syntax for the SqlDataSource is as follows:

<asp:SqlDataSource ID="EmployeesDataSource" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
   

InsertCommand="INSERT INTO [Employees] ([Name], [Salary], [HireDate]) VALUES (@Name, @Salary, @HireDate)"


   SelectCommand="SELECT [EmployeeID], [Name], [Salary], [HireDate] FROM [Employees]">
   <InsertParameters>
      <asp:Parameter Name="Name" Type="String" />
      <asp:Parameter Name="Salary" Type="Decimal" />
      

<skm:TodayParameter Name="HireDate" />


   </InsertParameters>
</asp:SqlDataSource>

Notice how the InsertCommand has a parameter named @HireDate. This parameter value is specified via the TodayParameter in the InsertParameters collection.

We can further augment the TodayParameter by providing a property that specifies whether the value returned should be just the current date or the current date and time:

Public Property IncludeTime() As Boolean
    Get
       Dim o As Object = ViewState("IncludeTime")
       If o Is Nothing Then
            Return True 'value not set, return default
       Else
            Return CType(o, Boolean)
       End If
    End Get
    Set(ByVal value As Boolean)
       ViewState("IncludeTime") = value
    End Set
End Property

Note that this property persists its value to the Parameter class's ViewState collection. This ensures that the if the value for this property is changed programmatically, that the changed value is persisted across postbacks. For a more in-depth look at view state, it's purpose, and why custom controls are responsible for managing their own view state (and common design patterns in doing so), see my article Understanding ASP.NET View State.

With this property defined, we can update the Evaluate() method so that it returns only the current date (and not the time) if IncludeTime is False:

Protected Overrides Function Evaluate(ByVal context As System.Web.HttpContext, ByVal control As System.Web.UI.Control) As Object
    If IncludeTime Then
       Return DateTime.Now
    Else
       Return DateTime.Now.Date
    End If End Function

And the TodayParameter control's declarative markup can be modified to include this value (although it's really only needed if you want to omit the time, since the default value of IncludeTime is True.

<skm:TodayParameter Name="HireDate" IncludeTime="False" />

Determining the Currently Logged On User's UserId


If you use ASP.NET 2.0's new Membership feature to manage user account information, and if there is user-specific data in your data model, you've no doubt come across a situation where you want to add a new record and use the currently logged in user's UserId value. Or maybe you are listing information specific to a user and want to get the data for the currently logged in user. When using the Membership system, the currently logged on user's information can be accessed using Membership.GetUser(), and the UserId value is returned in the MembershipUser object's UserProviderKey property. Unfortunately, there is no built-in Parameter control that returns the currently logged in user's UserId value, meaning we either have to programmatically provide this value, or... create a custom Parameter control! (If you are not familiar with ASP.NET 2.0's Membership subsystem, check out the Examining ASP.NET 2.0's Membership, Roles, and Profile article series.)

To facilitate this, I've created a MembershipUserIdParameter control that returns the currently logged on user's UserId. Needless to say, the code is very simple, relying entirely on the Membership API. The Evaluate() method follows:

Protected Overrides Function Evaluate(ByVal context As System.Web.HttpContext, ByVal control As System.Web.UI.Control) As Object
    Dim currentUser As MembershipUser = Membership.GetUser()
    If currentUser Is Nothing Then
       'Either Membership is not setup or the visitor to this page is anonymous
       Return Nothing
    Else
       'Return the currently logged on user's UserId
       Return currentUser.ProviderUserKey
    End If
End Function

That's all there is to it! In the download at the end of this article, you'll find a MembershipUserIdParameter.aspx demo that has a PersonalNotes table in the database. This database table is designed to allow logged on user's to add personal reminders or TODO notes. Each record has a UserId record, which serves as a foreign key back to the UserId column in the aspnet_Users table (one of the tables in the schema used by the SqlMembershipProvider provider).

As the following markup shows, the MembershipUserIdParameter control is used in the SelectParameters collection to return the notes for the currently logged on user, and in the InsertParameters collection to automatically add the currently logged on user's UserId to the INSERT statement when adding a new note through a DetailsView. The PersonalNotes table also has a NoteDate date/time field; the TodayParameter control is used to provide that value in the InsertParameters collection.

<asp:SqlDataSource ID="PersonalNotesDataSource" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString %>"   
    InsertCommand="INSERT INTO [PersonalNotes] ([UserId], [NoteDate], [Subject], [Body]) VALUES (@UserId, @NoteDate, @Subject, @Body)"
    SelectCommand="SELECT [PersonalNoteID], [UserId], [NoteDate], [Subject], [Body] FROM [PersonalNotes] WHERE UserId = @UserId ORDER BY NoteDate DESC"
>
    <InsertParameters>
       <skm:MembershipUserIdParameter Name="UserId" />
       <skm:TodayParameter Name="NoteDate" />

       <asp:Parameter Name="Subject" Type="String" />
       <asp:Parameter Name="Body" Type="String" />
    </InsertParameters>
    <SelectParameters>
      

<skm:MembershipUserIdParameter Name="UserId" />


    </SelectParameters>
</asp:SqlDataSource>

Conclusion


ASP.NET 2.0 ships with a generic Parameter control and six specific controls, who pull their value from a particular source. With just a little bit of code, you can create your own custom Parameter controls. In this article we saw how to build two custom Parameter controls: TodayParameter, which returned the current date (and, optionally, the time); and MembershipUserIdParameter, which returned the currently logged on user's UserId (when using ASP.NET's Membership subsystem). These custom Parameter controls can be included in the parameter collections just like the built-in Parameter controls. Be sure to check out the test website and code available for download at the end of this article!

Happy Programming!

  • By Scott Mitchell


    Further Readings:


  • Creat Your Own Parameter to the Data Source Control's Parameters Collection
  • Custom Parameters for Data Sources
  • Attachments


  • Download the code and examples for this article (in ZIP format)
  • Article Information
    Article Title: ASP.NET.Accessing and Updating Data in ASP.NET: Creating Custom Parameter Controls
    Article Author: Scott Mitchell
    Published Date: November 1, 2006
    Article URL: http://www.4GuysFromRolla.com/articles/110106-1.aspx


    Copyright 2014 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers