Archive

Posts Tagged ‘.NET’

Serialize SQL parameters

March 15th, 2010

Convert a collection of SQL parameters into a name:value string suitable for writing to a log.

/// <summary>
/// Serializes a collection of
/// <see cref="System.Data.SqlClient.SqlParameter"/>s.
/// </summary>
/// <param name="parameters">
/// The collection of parameters to serialize.
/// </param>
/// <returns>
/// A <see cref="System.String"/> that contains the parameter values.
/// </returns>
public string SerializeSqlParameterCollection(
    SqlParameterCollection parameters)
{
    StringBuilder sb = new StringBuilder();
    foreach (SqlParameter parameter in parameters)
        sb.Append(
            String.Format("{0}:{1} ",
                parameter.ParameterName, parameter.Value));
    return sb.ToString();
}

Post to Twitter Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

.NET Framework, Programming, Snippets , , ,

Http Modules

February 18th, 2010

The .NET framework provides several mechanisms for extending the behaviors of web pages and other endpoints. One such technique is the http module. Modules are often either overlooked as a solution or are considered too heavyweight or scary for use. This is unfortunate as they are a powerful item in the ASP.NET development toolbox.

An http module is a single unit of code that is executed as part of the web request pipeline. When a web request is received, the list of registered modules are afforded the opportunity to inject themselves at several stages in the execution pipeline. Each module has the opportunity to inspect or modify parts of the request before or after it is processed. This makes them a powerful mechanism for attaching custom behaviors. Modules also have a flexible activation model as they can be attached or detached via configuration allowing them to be enabled or disabled at will without affecting a production site.

The full source code for this example can be found here.

How to Create an HttpModule
The ASP.NET Module type is in the Web category under the Add New Item dialog.

241@229_tmp6C6D

Remove the default sample code that is included in the template. The LogContext event handler is implemented in the template for demonstration purposes but is not used in this example. Your class should now look similar to the following:

using System;
using System.Web;

namespace ModuleWebApp
{

    ///

    /// Custom http module.
    /// 

    public class MyNewModule : IHttpModule
    {

        #region IHttpModule Members

        public void Dispose() {}

        ///

        /// Initializes the module.
        /// 

        /// <param name="context">The application context.</param>
        public void Init(HttpApplication context)
        {

        }

        #endregion

    }
}

Initializing the Module

Modules perform work by registering handlers for events in the request execution pipeline such as BeginRequest and EndRequest. It is within the event handlers that they perform their task. In the example below, the Init method is used to register handlers for the BeginRequest and EndRequest events.

///

/// Raised when the module is initialized.
/// 

/// <param name="context">The application context.</param>
public void Init(HttpApplication context)
{
    context.BeginRequest += new EventHandler(context_BeginRequest);
    context.EndRequest += new EventHandler(context_EndRequest);
}

Implementing the Event Handlers and Finishing the Module

Next provide implementations for the event handlers. This example module is going to calculate and display the time it takes to execute a page within the application. The code example below is for the completed module class. It contains the following changes:

  • Declaration of a dictionary of stopwatches that stores the execution timers.
  • Implementation of the BeginRequest and EndRequest handlers to start and stop the timers.
  • Instantiation of the dictionary of timers in the Init method.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Web;

namespace ModuleWebApp
{

    /// <summary>
    /// A custom http module used to time request execution.
    /// </summary>
    public class RequestTimer : IHttpModule
    {

        #region IHttpModule Members

        public void Dispose() { }

        /// <summary>
        /// Raised when the module is initialized.
        /// </summary>
        /// <param name="context">The application context.</param>
        public void Init(HttpApplication context)
        {
            _timers = new Dictionary<Guid, Stopwatch>();

            context.BeginRequest += new EventHandler(context_BeginRequest);
            context.EndRequest += new EventHandler(context_EndRequest);
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Raised when the request begins.
        /// </summary>
        /// <param name="sender">The source of the event; the <see cref="System.Web.HttpApplication" />.</param>
        /// <param name="e">An <see cref="System.EventsArgs"/> that contains event data.</param>
        protected void context_BeginRequest(object sender, EventArgs e)
        {
            Guid timerId = Guid.NewGuid();
            Stopwatch timer = new Stopwatch();
            _timers.Add(timerId, timer);

            HttpContext.Current.Items.Add(EXECUTION_TIMER_KEY, timerId.ToString());

            timer.Start();
        }

        /// <summary>
        /// Raised when the request ends.
        /// </summary>
        /// <param name="sender">The source of the event; the <see cref="System.Web.HttpApplication" />.</param>
        /// <param name="e">An <see cref="System.EventsArgs"/> that contains event data.</param>
        protected void context_EndRequest(object sender, EventArgs e)
        {
            string timerId = HttpContext.Current.Items[EXECUTION_TIMER_KEY] as string;

            if (String.IsNullOrEmpty(timerId))
                return;

            Stopwatch timer = _timers[new Guid(timerId)];
            if (timer == null)
                return;

            timer.Stop();

            double elapsedSeconds = (timer.ElapsedMilliseconds) / (double)1000;

            HttpContext.Current.Response.Write(
                String.Format(
                    "Request executed in {0} seconds ({1} ticks).",
                    elapsedSeconds.ToString(),
                    timer.ElapsedTicks.ToString()));
        }

        #endregion

        #region Fields

        /// <summary>
        /// The collection of execution timers.
        /// </summary>
        private Dictionary<Guid, Stopwatch> _timers;

        #endregion

        #region Constants

        private const string EXECUTION_TIMER_KEY = "__ExecutionTimer_Id";

        #endregion

    }

}

Some of the concepts used here are beyond the scope of this discussion. Research the Stopwatch class for more information on how to use timers. See the HttpContext class to learn more about request and response objects.

Registering the Module

The final step is to register the module so that it is instantiated and executed on every request. This is done via the web.config file. The <system.web> section contains an <httpModules> section. The registration configuration line for the module should be added to the <httpModules> section as shown below:


	
	
		
		
    
	

That’s it! Running the web application should display the default.aspx page, which now shows the execution time in elapsed seconds (and ticks). This information is displayed at the end of every web request so it works on every page in the system. If you inspect the context_EndRequest handler you can see the following lines:

HttpContext.Current.Response.Write(
	String.Format(
		"Request executed in {0} seconds ({1} ticks).",
		elapsedSeconds.ToString(),
		timer.ElapsedTicks.ToString()));

The HttpContext class exposes the current Request and Response. These are the http request and response that are received from and sent to the client respectively. The execution time was displayed on the page because this handler wrote to the response object after the request had finished executing. The timer was started when the request started and stopped when the request ended. The time taken for the page to performing its processing and the request to finish is then displayed in the response. It is in this way that modules interact with all requests in the system and provide global level behaviors that are attached via configuration.

Post to Twitter Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

.NET Framework, ASP.NET, Programming , ,

The ObjectDataSource Web Control

April 17th, 2007

There exists a wide variety of ways in which data for a web page can be retrieved from a data store. One of the ways introduced in ASP.NET 2.0 involves using the ObjectDataSource control. This article discusses the ObjectDataSource control and how it fits into the ASP.NET 2.0 toolkit. A working example is provided demonstrating how the ObjectDataSource control can be used with a typed data set to provide search results to a GridView that are filtered based upon search parameters entered into other controls on the same page. The results can be paged and sorted within the grid, demonstrating some of the additional capabilities that the ObjectDataSource control provides.

What is it?
In high level terms, the ObjectDataSource is described as “…a middle-tier object with data retrieval and update capabilities” and “…acts as a data interface for data-bound controls“. Fancy! What does this really mean? In basic terms, it can be thought of as wrapping up the code necessary to open a connection to a data store, execute a query and return a result set, as well as provide caching, paging, and parameter support.

The ObjectDataSource can be configured to retrieve some data so that other controls don’t have to worry about data store access. The benefits of this approach over having the controls on the page source the data from a database themselves is that it provides a single structured location to define the data retrieval operation and isolates that retrieval, ostensibly making maintenance and extensions to the page more robust and reliable. As a further benefit, being a web server control means that many uses require no compiled code-behind implementation and the configuration of the ObjectDataSource on the page can be changed in an .aspx page directly; eliminating the requirement for recompilation during maintenance.

For those wishing to follow along with additional reference information, the full declarative syntax for the ObjectDataSource control can be found here: http://msdn2.microsoft.com/en-us/library/ms227436.aspx.

For the purposes of this discussion, a simpler implementation path will be taken; the typed data-set. Strongly typed data sets were introduced in the .NET 1.0 framework and have been vastly enhanced in the .NET 2.0 framework. I would strongly advise anyone who wrote off .NET 1.0 typed data sets as over-bloated and under-implemented sledgehammers to take a look at the .NET 2.0 typed data set before passing judgment. For ease and efficiency of development and maintenance with little to no performance impact at run-time, typed data sets and the ObjectDataSource control can form one of the most powerful duos in any ASP.NET 2.0 developer’s toolkit. http://msdn2.microsoft.com/en-us/library/ms228150.aspx

Basic Syntax
The basic syntax to declare an ObjectDataSource on an ASPX page looks like the following:
<asp:ObjectDataSource ID=”srcSearchResults” runat=”server” SelectMethod=”GetData” TypeName=”VideoManagerTableAdapters.VideoTableAdapter”>
<SelectParameters>
<asp:ControlParameter ControlID=”ddlGenre” Name=”Genre” PropertyName=”SelectedValue” Type=”String” />
</SelectParameters>
</asp:ObjectDataSource>

There are a few interesting points to note about this basic declaration. First, the TypeName attribute, which identifies a class used to perform the actual database access operations. This gives the first clue as to how the ObjectDataSource control is performing its work. The second interesting point is the SelectMethod attribute, which specifies a method on that class that will be used to perform a select query. This gives the next clue as to how the pattern will work. When a control using the ObjectDataSource is bound, the method specified in the SelectMethod attribute will be invoked on an instance of the class specified in the TypeName attribute. The results of this query will then be used by the control that is binding data.

Sourcing Objects
This raises an important question about how the class specified in the TypeName attribute of an ObjectDataSource is defined. Any object that satisfies the requirements of the ObjectDataSource can be specified in this attribute. For more information on the specifics of those requirements and for instructions on how to implement a custom sourcing object, see this article:

What about parameters?
When executing a query to return a result set from a data store, it is often desirable to provide parameters to the query in order to narrow the results that are returned. Imagine a search page on a video library web site that allows a user to specify a genre, director, and title as possible search parameters. When executing the query to return the list of results, any user input provided for those three attributes would need to be passed as well. The ObjectDataSource provides such a mechanism for supplying parameters to queries. Additionally, the ObjectDataSource allows for a different set of parameters to be provided for each of the types of queries configured across it, but more on this later. The syntax used to supply parameters should be instantly familiar to developers who have worked up through the various releases of ADODB, including the popular ADODB 2.5 used with VB6 and the even more popular ADODB.NET released with the .NET 1.0 framework.

The ObjectDataSource control recognizes seven parameter types. Each of these can be provided to any of the five query types. The following tables list the query and parameter types along with a brief description of each.

Query Type Description
SelectParameters The collection of parameters to supply to the SELECT query.
InsertParameters The collection of parameters to supply to the INSERT query.
UpdateParameters The collection of parameters to supply to the UPDATE query.
DeleteParameters The collection of parameters to supply to the DELETE query.
FilterParameters The collection of parameters to supply for the Filter expression.
Parameter Type Name Description
ControlParameter A parameter sourced from another ASP.NET web server control.
CookieParameter A value sourced from a cookie.
FormParameter An item of form-post data received from an HTTP post.
Parameter A literal parameter with either a hard-coded value or sourced programmatically.
ProfileParameter Sourcing a parameter from the current security profile.
QueryStringParameter A parameter sourced from a query-string value.
SessionParameter A value read from the session object.

What else can it do?
In a subsequent article, I am going to discuss the additional features and potential pitfalls of the ObjectDataSource control. These include paging, filtering, and sorting, how caching can work, and the list of most common traps and errors that you might encounter while using the control. For now, it is worthwhile playing with the ObjectDataSource control on a few test pages, examining its syntax and thinking about its application as a middle-tier enabling layer. In essence that is what the ObjectDataSource is trying to provide, a managed ability to employ a middle-tier in your solution architecture that manages some of the grey area items between those layers such as connection string management, parameter marshalling, and the provision of a single point of reference for user interface layer controls.

Working Example
The following section contains a full working example using an ObjectDataSource and a typed data set to bind search results to a GridView on an .aspx page. The ObjectDataSource takes parameters from other controls on the page to provide filtering capabilities to the search.

Creating the SQL database
Open SQL Management Studio and connect to a SQL database server. Create a new database by right-clicking over the Databases folder and selecting New Database… Enter the name ObjectDataSourceDemo as the name of the database and click OK. Expand the new database in the object explorer window and add a new table to the database by right-clicking the Tables folder and selecting New Table… Fill out the table definition as shown below being sure to set VideoID as the Primary Key and the Identity Specification (Is Identity) to Yes. Press Ctrl-S to save the table, which will display the Choose Name dialog. Enter Video as the name of the table and click OK.

Open the table by expanding the Tables folder in the object explorer and then right-clicking over the Video table in the list and selecting Open Table. Enter a few rows of data in the table and then close SQL management studio. Remember that VideoID is an identity column and does not need to have data typed into it. An ID will be assigned automatically by navigating to the next row.

NOTE: In a real solution, the data for directors and genre would not be stored directly as strings within the Video table. For the simplicity and brevity of this example, the contents of several logical tables have been compressed into a single table.

Defining a Typed Data Set
In Visual Studio, create a new C# web site in a new solution. To add a typed data set, right-click the project in the solution explorer and select Add->New Item to show the Add New Item dialog. Select DataSet from the list of item types, enter a name, and then click the Add button.

This will open the newly added data set in design mode. From here you can add items to the data set and visually build its definition. For the purposes of this article, we’re going to add a TableAdapter to the data set for use in an ObjectDataSource. For more information on typed data sets and table adapters, see this article: http://aspnet.4guysfromrolla.com/articles/020806-1.aspx

First, right-click over the design pane and select Add -> TableAdapter. This will add a table adapter to the data set and open the TableAdapter Configuration Wizard. Create a new database connection to the SQL server and select the ObjectDataSourceDemo as the database to connect to.

Click OK on the Add Connection dialog and then click Next to save the connection string to a configuration file. For this example we will just use SQL statements to connect to the database. Select the radio button marked Use SQL statements and click Next. Type the following SQL into the dialog box and click Next.

SELECT Title, [Director Name], Genre
FROM Video
WHERE Genre = @Genre

Finally, accept the default names for the Fill and Return actions of the TableAdapter and click Next. Click Finish to close the dialog. The new table adapter will be displayed in the design pane and you can now save the dataset.

(The newly created TableAdapter)

Creating the ASPX page
In the solution explorer pane, open the Default.aspx page that was added when the web site project was created. Add the following code between the <form> tags on the page:

<asp:DropDownList ID=”ddlGenre” runat=”server” AutoPostBack=”true”>
<asp:ListItem Text=”Action” Value=”Action” />
<asp:ListItem Text=”Comedy” Value=”Comedy” />
<asp:ListItem Text=”Mystery” Value=”Mystery” />
</asp:DropDownList>
<br />
<asp:GridView ID=”gvSearchResults” runat=”server”
AutoGenerateColumns=”false” DataSourceID=”srcSearchResults”>
<Columns>
<asp:BoundField DataField=”Title” HeaderText=”Video Title” />
<asp:BoundField DataField=”Director Name” HeaderText=”Director Name” /> <asp:BoundField DataField=”Genre” HeaderText=”Genre” />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID=”srcSearchResults” runat=”server”

SelectMethod=”GetData” TypeName=”VideoManagerTableAdapters.VideoTableAdapter”>
<SelectParameters>
<asp:ControlParameter ControlID=”ddlGenre” Name=”Genre”
PropertyName=”SelectedValue” Type=”String” />
</SelectParameters>
</asp:ObjectDataSource>

Running the Sample
While not the most advanced example out there, this demonstrates the use of an ObjectDataSource control as a data source proxy for another ASP.NET web control. The DropDownList control is set to post the page back when the selected item in the list is changed. Upon this post-back, the GridView control is data-bound. It is during this data-binding step that the data source specified for the GridView, in this case our ObjectDataSource control, performs its work and retrieves the search results from the database. It uses the selected value of the genre DropDownList control as a parameter to supply during the search.

Post to Twitter Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

ASP.NET, WebControls , , , ,

Overloaded Indexers cause Ambiguous Match

April 13th, 2007
Developing custom web server controls can be a powerful way to provide opportunity for code re-use while retaining strong design-time support and Visual Studio integration.  This is especially useful when developing a solution that will be handed off to a maintenance team as it allows full control of the rendering and behavior of your control whilst retaining ease of use and configuration for the maintenance team at a later date.  One of the common patterns that appears in such server controls is the definition of a child collection of items.  This is akin to the collection property Columns on the System.Web.UI.WebControls.DataGrid control.  When defined in .aspx, it looks like the following:

<asp:DataGrid id=”myGrid” runat=”server”>
<Columns>
… column definitions …
</Columns>
</asp:DataGrid>

This collection is used in the definition of the data-grid to define information about the columns that the control should create when it is rendered.  Similarly, a custom control might have a collection of child items that represent domain objects within your custom solution.

I came across an error in one custom server control I developed that manifested itself as an System.Web.HttpParseException with the error message ‘Parser error: Ambiguous match found’.  The collection property, shown as <ChildItems> in the code below, was highlighted as the source of the error:

<ctl:CustomControl id=”myControl” runat=”server”>
<ChildItems>
… child item definitions …
</ChildItems>
</ctl:CustomControl>

After a little bit of research, I found a Microsoft KnowledgeBase article (#823194) that seemed to describe the symptoms I was observing.  The article indicated that the problem was in the definition of the custom collection itself.  If the collection contained an overloaded indexer then the ASP.NET framework would raise the HttpParseException and display the observed “Parser error: Ambiguous match exception” message when trying to instantiate the control in the page hierarchy.

I quickly popped open the code for the collection class and saw that I had indeed added an overloaded indexer as part of a recent update to the control.  I had added the ability to retrieve an item from the collection by item name as it was useful by another control that aggregated the one exhibiting the error.  There was already an indexer defined for the collection that used an integer to retrieve an item from a specified position.  In terms of C# syntax and for other consumers of the class, having an overloaded indexer is perfectly legitimate, however testing revealed that it was indeed the new this[string] indexer that was causing the problem when ASP.NET tried to instantiate the control programatically and deserialize the .aspx definition into that object instance.  After commenting out the indexer and re-running my tests, the problem was gone.  I have since replaced the overloaded indexer with an additional GetBy…() method and updated the documentation accordingly.  This wasn’t a particularly tricky bug to track down, but it’s interesting nonetheless.

Post to Twitter Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

ASP.NET, C# , , , ,

CascadingDropDownList and Page Validation

April 9th, 2007

While working with the AJAX Control Toolkit (http://ajax.asp.net), I came across something interesting with the CascadingDropDownList control and ASP.NET page validation.

What Does the CascadingDropDownList Do?

The control is used to create tiered drop-down lists that each depend upon parent values for their own data population.  The canonical example given regards using three DropDownList controls to narrow a selection of a car.  The first list displays a list of manufacturers, the second a list of models, and the final a list of common packages, with each successive list control populating only the relevant values based upon its parent.  For example, selecting “Ford” from the manufacturer list would populate “Focus, Sierra, Probe, F-Series, etc…” in the model list.  Selecting “F-Series” would populate “F150, F250, F350, etc…” in the package list.

What’s the Problem?

When the CascadingDropDownList control renders the child lists, it makes an AJAX server request to a web service supplying the selected parent value and requesting the list of relevant child values.  It then uses client-side script to populate the child DropDownList control with the list of returned values. This means that the contents of the child drop-down lists are being modified on the fly by JavaScript and the final values in the list will not match the list that the ASP.NET page thinks it rendered.  The ASP.NET security model contains validation upon a postback to ensure that the contents of a drop-down list being posted back match those that were rendered to avoid injection attacks (see the section below on injection attacks if you want a refresher).

When the page posts back, an exception is raised by the ASP.NET framework because the contents of the originally rendered list don’t match the newly populated list.  ASP.NET provides a solution to “permit” a control to be modified on the fly, however it requires a call to ClientScriptManager.RegisterForEventValidation for each of the additional valid values that might appear.  Since we don’t know (server-side) ahead of time which option the user will choose client-side, we can’t know the list of options that the JavaScript control will add, thus preventing us from using that solution.

The Atlas Solution

The only official solution provided by the Atlas team is to disable validation for the page:

http://ajax.asp.net/ajaxtoolkit/Walkthrough/CCDWithDB.aspx

However, even that team admits that this must be done with extreme caution and a complete understanding of the consequences.  It is fine to disable the automatic validation for a page as long as you are validating the received values manually or if you really trust the users of the application not to inject.  (hint: even on intranet apps you never trust the users not to inject because automated bots and viruses running on client machines inside the intranet are becoming advanced enough to post injections to page controls without the user’s knowledge, not to mention the “password on a sticky note on the monitor” hole.)

Why is the Solution a Problem?

The solution can be worked.  Server-side validation of incoming data from input controls (including DropDownList controls) is a good practice to begin with.  However, it raises some interesting limitations with regards to the standard integration models used by most developers.  If, for example, you are using the <ObjectDataSource> control to take parameters from your page controls and feed their selected values directly into a stored procedure or SQL query, you won’t get the opportunity to manually validate the input.  This means that a control on the page that is used as a parameter in the ObjectDataSource could have an injection string posted back as its value and sent directly to the stored procedure without the opportunity for server-side validation.  This opens up the injection hole and could only be solved by coding some pretty awkward stored procedures.  There is a better way.

Finding a Solution

Things We Know

  • I love the CascadingDropDownList control and want to still use it.
  • To avoid ASP.NET raising validation errors, page-validation must be disabled for the page.
  • Disabling automatic validation and failing to perform manual validation can open a security hole.

Compromises?

  • For the particular page using CascadingDropDownList, don’t use the ObjectDataSource directly.  Bind to the control with the three lines of code it takes in the code-behind file.  You can still use the TableAdapters and fantastic ASP.NET 2.0 DataSet pattern, you just need to validate the incoming paramters with a few assertions before running off with the input to the database.
  • As a lesser, potentially still dangerous, and (to my mind) somewhat messy solution, you could bullet-proof your stored procedures with validation – but this feels like a future stumble and could get ugly in maintenance, testing, and debugging.  Just write the manual validation code and be done!

Injection Attacks You Say?

Without page validation a security hole appears.  Consider the following scenario.  A page is rendered with three items in a drop-down list, arbitrarily the names of three authors.  The ID and name of the author are rendered as the value and text respectively.  Because this is client-side html, the contents of the list can be modified before the page is posted back.  Say you insert the following into the html for the drop-down list:

<option value=”1 or 1=1;“>Foo</option>

This adds a new item to the list whose value is ‘foo’ or 1=1;

If the stored procedure being called was:

SELECT *

FROM   Author

WHERE  AuthorID = @selectedAuthorID

then the executed SQL would now end with:

WHERE AuthorID = 1 or 1=1;

Why is that a Bad Thing?

Well, for one the stored procedure or sql query will now return every item in the table because OR 1=1 will always evaluate to true.  Secondly, there are far, far worse injections that can be performed depending upon the rights of the user that the web application uses to connect to the database.  Because most applications have a single user account for the entire web application (restricting admin features only by url or declarative security), that account usually has vastly elevated rights.  You can now inject any SQL command after the WHERE clause.  For more information on SQL injection attacks, see http://www.unixwiz.net/techtips/sql-injection.html

Post to Twitter Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

AJAX, ASP.NET , , , , ,