Click here to Skip to main content
15,936,802 members
Articles / Web Development / CSS

Support for Generics in ASP.NET Server Controls

Rate me:
Please Sign up or sign in to vote.
4.77/5 (16 votes)
29 Jan 2009CPOL4 min read 61.6K   446   29   13
Implementation of a framework to support Generics in ASP.NET server controls, including strong-typing of ITemplate containers.

Generics in ASP .NET? Why?

Anyone who has ever built a WebForms based application has no doubt come across the well-worn Repeater control. A staple of web programming, it allows for the display of a collection of items, and exposes the items through the Eval or Bind methods.

Under the hood, Eval and Bind work through Reflection in order to provide late binding support. This is also what you see if you reference properties such as:

XML
<%# Container.DataItem.PropertyNameHere %>

The reason for this is that ASP.NET allows transparent late binding, so even though it believes that Container.DataItem is typed as 'Object', the evaluation will only occur at runtime. This leads to all sorts of problems such as:

  • Pages breaking when a property is changed, and no warnings at compile-time.
  • Reduced performance, as every data-field display point becomes a Reflection call.

If we could tell ASP.NET what the type of the data items actually are, though, then during site start-up/compilation, we would be able to ensure the right types are being used, and no late-binding ever occurs. Compile time checking of all pages, master-pages, and user control binding tags sounds good?

If that's not enough for you, what about full intellisense support?

StrongTypingIntellisense.png

Generics in ASP.NET? How?

During start-up and the first hit to a page in a given folder, ASP.NET performs batch compilation of your ASPX files. That is, the conversion of them and the content therein into actual .NET code that will be run. The trouble previously with ASP.NET Generics was that there is no syntax support in ASP.NET to specify a generic type, for example:

ASP.NET
<asp:Repeater ID="Repeater1" runat="Server" />

is all well and good, but you can't say:

ASP.NET
<asp:GenericRepeater<String> ID="StringRepeater" />

As a result, we're going to have to find a workaround. I've ended up taking a very similar route to another tutorial that gives a typed Repeater implementation, by Andrey Shchekin. You can find his tutorial here. The way this works is as follows:

  • We intercept compile-time construction of pages using a ControlBuilder sub-class assigned to a non-generic class.
  • This ControlBuilder's Init method switches the non-generic type for a real generic type, using type-names read from properties of the non-generic control.
  • We wrap the real type inside a TypeDelegator that intercepts any calls to properties of the type (such as the templated containers).
  • Whenever ASP.NET requests the TemplateContainer attribute of the type, we give it back a dynamically constructed instance that contains the correct strong-typing information.

In the example code, I've created a 'GenericRepeater' that displays a strongly typed collection and the items therein. I have then sub-classed that GenericRepeater with <Object, Object> in order to create an ObjectRepeater like so:

C#
[ControlBuilder(typeof(GenericTemplatedControlBuilder))]
[GenericControlType(typeof(GenericRepeater<,>), "CollectionTypeName", "ItemTypeName")]
public class ObjectRepeater : GenericRepeater<IEnumerable<Object>, Object>

The ObjectRepeater inherits the real generic repeater type, and the attributes tell ASP.NET to use the special control builder instead of the base one. The GenericTemplatedControlBuilder then looks for the GenericControlType attribute, and will activate the 'real' GenericRepeater instance with the two type parameters.

Inside the generic repeater implementation, we mark up the various ITemplate properties with other attributes:

C#
[^__strong__^GenericTemplateContainerParameter(typeof(IndexedDataContainer<,>), 0, 1)]
[PersistenceMode(PersistenceMode.InnerProperty)]
public ITemplate ItemTemplate { get; set; }

The GenericTemplateContainerParameter declaration tells the system what type of data container to instantiate, and also the indices of the generic parameters to pass down. Thus, since IndexedDataContainer takes two generic parameters, we are telling to take generic parameters 0 (TCollectionType) and 1 (TItemType) from the GenericRepeater as the relevant parameters.

When ASP.NET scans the properties of the control, we have now switched the control for a generic control and instructed our GenericControlPropertyDelegator to remap all calls for TemplateContainer to our real, generic template containers.

The Final Product

Now that we have everything in play, let's define a simple ASP.NET page that uses the control:

StrongTypingRenderedOutput.png

And, there you have it, a simple generics framework for ASP.NET that allows you to deal with pretty much any generic control scenario, and is not specifically tied down to the example for use with Repeaters.

Notes About the Code

The example code supplied does not actually implement any post-back support, so don't be surprised if you need to add some code to load/save data in the viewstate and so forth.

Additionally, if you're going to reference this code on your own Web Applications, please ensure you take the web.config elements across to register the CFC tag prefix.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Insurance Industry
United Kingdom United Kingdom
Steve Gray is a Senior Developer at a British insurance company, working on a popular aggregator. When he's not writing ASP .NET, it's because there's SQL or WCF to write instead.

Comments and Discussions

 
GeneralNot working on asp.net 4 Pin
Hedgic24-Jan-11 4:27
Hedgic24-Jan-11 4:27 
GeneralRe: Not working on asp.net 4 Pin
Steven James Gray1-Feb-11 21:19
Steven James Gray1-Feb-11 21:19 
GeneralFantastic Pin
BKK199223-Sep-09 9:40
BKK199223-Sep-09 9:40 
QuestionAny Attribute to Hide Generic Class in ASPX? Pin
Barry Dorman23-Apr-09 10:02
Barry Dorman23-Apr-09 10:02 
AnswerRe: Any Attribute to Hide Generic Class in ASPX? Pin
Steven James Gray11-Oct-09 18:15
Steven James Gray11-Oct-09 18:15 
GeneralGreat code - but some queries... Pin
MR_SAM_PIPER2-Feb-09 21:05
MR_SAM_PIPER2-Feb-09 21:05 
GeneralRe: Great code - but some queries... Pin
Steven James Gray3-Feb-09 0:37
Steven James Gray3-Feb-09 0:37 
MR_SAM_PIPER wrote:
First, I have to say that this is really well-written, interesting code - the use of a custom TypeDelegator for type and property interception is cool and novel to me, and the overall approach illuminates some pretty obscure parts of the ASP.NET framework, given that most of us will probably never implement our own custom data-bound templated control. It took me a long time to work out how everything you've written works together to achieve the desired outcome, and it's pretty clever.


Thanks for the feedback Sam. The key to doing this kind of work with ASP .NET really is to have a copy of Reflector installed and start digging, and once you find the relevant bits head over to MSDN's website. The trouble is that Microsoft are very keen on sealing certain parts under the hood away.

MR_SAM_PIPER wrote:
My only criticism is that this solution is perhaps a little impractical for most web projects, as most sites will probably use a combination of different databound controls such as Repeater, GridView, ListView, DataList, etc, and this solution as proposed would require all of those controls to essentially be re-implemented with support for generics.


It's admittedly impractical to go through and generics-enable each individual control, but for presentation-focused scenarios it'll work reasonably well. I might try and include generic form and list views in the next release to save people some work.

MR_SAM_PIPER wrote:
I really hope that we get proper generics support in the next version of ASP.NET, as it would make everyone's life easier. I want to be able to whack a GridView<T> on a page using markup, set the item type property in markup using a typed expression, not a string, then get all the IDE goodness without writing a lick of special code.


I originally wanted to inherit the PageBuilder (that compiles ASPX files to code) and modify the parser to support generics in the syntax, but that's not possible due to various reasons (Sealed types, internal types etc).

Native support for this in ASP .NET would require modifications of the CLR (To support generics on attributes, so you can say [TemplateContainer(typeof(DataContainer<titemtype>))], which is presently not possible, not to mention the pagebuilder syntax support required.
GeneralGreat job! Pin
Andrey Shchekin1-Feb-09 10:44
Andrey Shchekin1-Feb-09 10:44 
Questionwhat abound Bind ? Pin
emperon30-Jan-09 8:49
emperon30-Jan-09 8:49 
AnswerRe: what abound Bind ? [modified] Pin
Steven James Gray30-Jan-09 19:01
Steven James Gray30-Jan-09 19:01 
GeneralMy vote of 2 Pin
ProJester130-Jan-09 2:43
ProJester130-Jan-09 2:43 
QuestionListView? Pin
bertkid29-Jan-09 8:00
bertkid29-Jan-09 8:00 
AnswerRe: ListView? Pin
Steven James Gray29-Jan-09 8:44
Steven James Gray29-Jan-09 8:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.