The ObjectDataSource supports using generic classes in the TypeName property although it doesn't provide any support for it. Usually you'll see that the TypeName property stores the name of a type (i.e. CustomProject.MyDAL), but it can store the type's full assembly qualified name (i.e. CustomProject.MyDAL, CustomProject, Version=188.8.131.52, Culture=neutral, PublicKeyToken=a7a65c534534e209).
The type's full assembly qualified name can be quite complicated and it is described by the following grammar:
TypeName := NamespaceTypeName | NamespaceTypeName ',' AssemblyNameSpec
NamespaceTypeName := NestedTypeName | NamespaceSpec '.' NestedTypeName
NestedTypeName := GenericTypeName | NestedTypeName '+' GenericTypeName
GenericTypeName := IDENTIFIER | IDENTIFIER '`' Number '[' GenericTypeArgList ']'
GenericTypeArgList := GenericTypeArg | GenericTypeArg ',' GenericTypeArgList
GenericTypeArg := NamespaceTypeName | '[' TypeSpec ']'
NamespaceSpec := IDENTIFIER | NamespaceSpec '.' IDENTIFIER
AssemblyNameSpec := IDENTIFIER | IDENTIFIER ',' AssemblyProperties
AssemblyProperties := AssemblyProperty | AssemblyProperties ',' AssemblyProperty
AssemblyProperty := AssemblyPropertyName '=' AssemblyPropertyValue
For more details about the grammar for type's full assembly qualified name in .NET Framework v1 take a look here
If you look in detail the grammar, it accept generic type names, that have a '`', then the number of generic argument and then the generic arguments inside square brackets.
So the following are valid type names:
MyGraph`2[[Utilities.Set, Utilities],[Utilities.Graph, Utilities]], MyGraphLibrary
MyGraph`2[[Utilities.Set, Utilities, Version=184.108.40.206, Culture=neutral, PublicKeyToken=a7a65c534534e209],[Utilities.Graph, Utilities, Version=220.127.116.11, Culture=neutral, PublicKeyToken=a7a65c534534e209]], MyGraphLibrary, Version=18.104.22.168, Culture=neutral, PublicKeyToken=2134afb4534e209
So if you want to use a generic type in the ObjectDataSource you just have to specify it using the syntax explained above. Be sure to add the assembly names if you use generic types.
What happens if the generic type you want to use is in the App_Code folder? The code in the App_Code folder gets compiled into a dynamically generated assembly with a random name so it is impossible to know it. Fortunately, you can use __code as the assembly name and it will work. Why does this work? When the framework can't resolve an assembly, the AppDomain AssemblyResolve event is fired. The BuildManager class (that is a helper class for ASP.NET compilation), captures this event and checks the specified assembly name. If it is __code, it returns the dynamically generated assembly for the App_Code folder. Returning App_Code also works (and you save executing a few instructions).
As an special case, you can use VB, C# or other .NET supported language in the same web application if you place the code for each language in a different folder. For example, if you want to use VB and C# you have to create these folders:
and add this to the web.config:
If you use this configuration two assemblies will be dynamically generated for your code behind classes, one for each folder. If you want to reference it in the TypeName of the ObjectDataSource or where the framework expects a fully qualified name you have to use App_SubCode_VB or App_SubCode_CS.
Of course, the ObjectDataSource doesn't have design time support for this. In fact, the ObjectDataSource choose type dialog filters out the generic types, the interfaces and the types registered in the GAC.
The ExtendedObjectDataSource will have full design time support for generic types and more control about the types that are filtered in the next version:
When you select a generic type, a textbox and a button appear. You can use the textbox to specify the type of the generic parameters and click in the button to select the generic type. Also, there are some checkbox to have control over what types get filtered.
The above dialog has some little positioning issues that I think are caused by Windows Vista, because the dialog was defined as:
In a future post I'll talk about generic methods.