I am attempting to create a custom control in ASP.NET that has generic type parameters.
I have read the following articles which provided a starting point.
I have implemented what I feel to be the three crucial elements
1. Non-Generic Class with a ControlBuilder (MyControl.vb)
Imports System.Web.UI
<ControlBuilder(GetType(MyControlBaseBuilder))>
Public Class MyControl
Inherits MyControlBase(Of Object, Object)
Public Property ModelName As String
End Class
2. Generic Base Class (MyControlBase.vb)
Imports System.Web.UI
Imports System.Web.UI.WebControls
Public Class MyControlBase(Of TModel, TValue)
Inherits CompositeControl
Public Property FieldName As String
Public Property Model As TModel
Public Property Value As TValue
Get
Return Model.GetType().GetProperty(FieldName).GetValue(Model)
End Get
Set(value As TValue)
Model.GetType().GetProperty(FieldName).SetValue(Model, value)
End Set
End Property
End Class
3. Control Builder (MyControlBaseBuilder.vb)
Imports System.Web.UI
Public Class MyControlBaseBuilder
Inherits ControlBuilder
Public Overrides Sub Init(parser As TemplateParser, parentBuilder As ControlBuilder, type As Type, tagName As String, id As String, attribs As IDictionary)
Dim modelName As String = attribs("ModelName")
Dim fieldName As String = attribs("FieldName")
Dim modelType = System.Type.GetType(modelName)
Dim model = Activator.CreateInstance(modelType)
Dim valueType = model.GetType().GetProperty(fieldName).PropertyType
Dim concreteType = GetType(MyControlBase(Of ,)).MakeGenericType(New Type() {modelType, valueType})
MyBase.Init(parser, parentBuilder, concreteType, tagName, id, attribs)
End Sub
End Class
The Default.aspx page looks like this:
<%@ Page Title="Home Page" Language="VB" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.vb" Inherits="TestSite._Default" %>
<%@ Register Assembly="ServerControls" Namespace="ServerControls" TagPrefix="cc1" %>
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
<cc1:MyControl runat="server" ID="TestId" ModelName="TestSite.MyClass, TestSite" FieldName="Age" />
</asp:Content>
and I created a simple class MyClass to test the control:
Public Class MyClass
Public Property Age As Integer
Public Property Name As String
End Class
When the code runs I get the following Parse Error in the browser:
Parser Error Message: The base class includes the field 'TestId', but
its type (ServerControls.MyControl) is not compatible with the type of
control (ServerControls.MyControlBase`2[[TestSite.MyClass, TestSite,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Int32,
mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089]])
I downloaded and ran the project in the second link, listed above, and get the same error.
Steven James Gray, the author of the second article has this to say about the error:
This is a known issue with ASP .NET 4.0. What Microsoft have done is rework some of the generics
handling code and type resolution in the ASP .NET codebehind generation classes.
The side effect is that my tutorial, and every other generics enabling tutorial for ASP .NET
is effectively broken at the moment.Here's the Microsoft connect link regarding this bug - I'd raised it 16/07/2010 but still not action:
Questions
1. Since the article was written in 2009, things have changed and Steven's solution no longer works. Can the same functionality be achieved using other methods?
2. How does the Parse Error relate to the situation
3. Are there any modern tutorials that outline how to create generic server controls?
I am using the following:
1. Visual Basic 2012 (VB11)
2. Visual Studio 2012
3. Target Framework: .NET Framework 4.5
NOTE: I have asked this question on stackoverflow here