MVC: Strongly Typed ViewData Without A Code-Behind

January 7, 2008 11:00 PM

If you've tried to use strongly-typed ViewData with a ViewPage or ViewContentPage without using a code-behind file you may have run into the curious scenario of how to specify a generic in the <%@ Page %> element's Inherits attribute.

The Problem

Let's say you wanted to specify that the ViewData for this view would be an integer. Normally you would specify this in the code-behind like so:

   1: using System;
   2: using System.Web;
   3: using System.Web.Mvc;
   4:  
   5: namespace MVC_Example.Views.Home
   6: {
   7:     public partial class Index : ViewPage<int>
   8:     {
   9:     }
  10: }

Since we don't have a code-behind file though, we have to change the .aspx file's <%@ Page %> element. Trying to set it to the following will not work:

   1: <%@ Page Language="C#" Inherits="MVC_Example.Views.Home.Index<int>" %>

The Basic Answer

The value of the Inherits attribute appears to be delivered straight to the CLR without any language specific parsing, which means we have to specify it the way the CLR wants to interpret it. I browsed around and found (here and here) some information that points out the proper way to do this:

   1: <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage`1[ [System.Int32,mscorlib] ]" %>

WTF?

Eww, huh? The syntax is gnarly, but it gets the job done. Let's break the syntax down to make sure you understand what is going on:

ParentType`1[ [ChildType,ChildTypeAssembly] ]

  • "ParentType" is fairly obvious. This is the generic object that you want to create a reference to.
  • "`1[ [" is a bit more obscure. The "`1" specifies the number of generics in this argument, which we'll come back to in a second. The double square brackets are required. A single square bracket will NOT work.
  • "ChildType" is the type of object you wish to have the generic consume (what is the proper terminology here? anyone know?).
  • "ChildTypeAssembly" is the name of the assembly (NOT the namespace) that contains the ChildType. All of your common value types will be located in "mscorlib".

Multiple Generic Types

Let's say ViewPage took two arguments as part of its generic declaration area (ie: ViewPage<X,Y>). It doesn't, by the way, but we'll pretend it does for the sake of argument; you may find this information useful someday.

To have two type parameters, you'll have to change the "`1" to a "`2" and add an extra "[ChildType, ChildTypeAssembly]" reference, separated by a space. More parameters would continue to follow the same logic.

If you wanted to achieve the equivalent of ViewPage<int,string> it would look like this:

   1: System.Web.Mvc.ViewPage`2[ [System.Int32,mscorlib], [System.String,mscorlib] ]

A Generic of Generics

A more likely scenario is that you may want to have your ViewData be a generic List<T>. In this case you'll just nest the declarations. If you wanted to pass ViewData of the type List<string> to the ViewPage it would look like:

   1: System.Web.Mvc.ViewPage`1[[System.Collections.Generic.List`1[[System.String,mscorlib]], mscorlib]]
Tags: ,
Categories: MVC
Actions: E-mail | Permalink | Comments (5) RSS Feed for this post's comments.

Comments

1/8/2008 5:14 AM #

Chad

Thanks for this, it'll help while I port my website to the ASP.NET framework.

Keep up the good work.

Chad us

1/11/2008 2:05 PM #

Andrey Shchekin

Extremely impressive.

I was trying to do the same things with Pages some years ago, but I forgot to set the assembly name for the parameter type.

So I was really sure it is impossible.

Andrey Shchekin ru

3/18/2008 2:14 AM #

kihsa

how about if you need to refer to open generic type? for eg. ViewPage<T, IdT>?

kihsa au

3/18/2008 11:19 AM #

Troy Goode

I'm not sure what you mean by an open generic type, Kihsa. As far as I know you must specify the type of the generic so that it can compile correctly. Can you give me an example of what you are trying to accomplish?

Troy Goode us

3/18/2008 6:17 PM #

kihsa

if you need to refer to MyNamespace.ClassType<T> it would be MyNamespace.ClassType'1. So i was wondering how i could refer to MyNamespace.ClassType<T,IdT>? I want to be able to inject DI in generic way.

kihsa au

Add Comment


(Will show your Gravatar icon)  

  Country flag

biuquote
  • Comment
  • Preview
Loading




Troy Goode

Troy Goode
Microsoft Certified Professional Developer
AddThis Feed Button

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in  anyway.

© Copyright 2008

Colophon

Powered by:
BlogEngine.NET 1.4
Template:
Designs by Darren
Header Font:
Stamper
Syntax Highlighting:
WLW Code Snippet Plugin