tags:

views:

193

answers:

2

I have created a base class that derives from ViewPage with a custom public attribute that I want to be able to set in the @page directive however I am getting the following error.

Error 24 Error parsing attribute 'attrame': Type 'System.Web.Mvc.ViewPage' does not have a public property named 'attrname'.

the directive looks as so

<%@ Page Title="" Language="C#" AttrName="Test" Inherits="Web.Helpers.Views.BaseViewPage" %>

The problem seems to be that it doesn't recognize the base class from the Inherits tag. I thought this should work from reading around on the internet. Has anyone else tried this or have any idea why this isn't working?

A: 

You need to set the base type in the web.config to get around this. Go to

/Views/Web.config

and change the

configuration/system.web/pages

and change the attribute pageBaseType to your class.

<pages pageBaseType="Web.Helpers.Views.BaseViewPage" {your other attributes here} />
Nick Berardi
I have two different base pages. One is a generic BaseViewPage<TModel> that derives from ViewPage<TModel> and the other is BaseViewPage that derives from ViewPage. I guess I could change BaseViewPage<TModel> to derive from BaseViewPage. But then I would have to duplicate the code in the generic version of the ViewPage<TModel>. Is there a better way to solve this when you have a generic and a non-generic base view page?
Jeff
Actually, I tried the above. It doesn't appear to work. I am not sure that does anything different from the Inherits attribute in the page directive itself.
Jeff
@Jeff please see my response. This is partially supported, but not with generic types.
Eilon
+2  A: 

This is unfortunately not supported in ASP.NET MVC 1.0 or ASP.NET MVC 2.

The reason for this is an implementation detail of some MVC-specific parser logic that is used in ASPX/ASCX/MASTER files. If the view page's (or view master page's or view user control's) base type is a generic type there is logic that hard-codes the base class for the ASP.NET parser's sake to be just regular ViewPage (or ViewMasterPage or ViewUserControl).

Because the ASP.NET parser looks at the base class that MVC tells is, it will only ever be ViewPage, and thus it doesn't recognize the new property that you added, and thus it reports an error.

It is worth mentioning that this applies only if the base class you specify in the view page is generic. If you use a non-generic type then it should work just fine and you should be able to set values on custom properties.

I can think of two workarounds:

1) Create custom page base types for every type you need. This solution is rather easy, though cumbersome:

public class MyBasePage<TModel> : ViewPage<TModel> {
    ...
}

public class CustomerPage : MyBasePage<Customer> { }

public class ProductPage : MyBasePage<Product> { }

And then use only the non-generic derived types in the view pages' "inherits" attribute.

2) Copy the MVC source code (see links below) from the ViewTypeParserFilter into your project and make some small changes. The key method to change is the PreprocessDirective() method. Towards the bottom is an if() statement that overrides the "inherits" attribute to be one of a few hard-coded values. As you'll see, this code runs only if the declared base type is generic (hence my earlier comment).

It's up to you to decide exactly how you want to change this code. The key thing here is that the type name must be a type that .NET's Type.GetType() method can understand. That is, you have to use the CLR syntax for constructs such as generics and not the C# or VB syntax. For example, while in C# you can say:

System.Web.Mvc.ViewPage<Customer>

In the CLR syntax it's something like:

System.Web.Mvc.ViewPage`1[MyApp.Models.Customer]

Hopefully one of the two options above suits you.

Source code links:

Eilon
Thanks, I was looking at ViewTypeParserFilter and saw that. We ended up just setting up extra virtual directories so that the master pages worked both at compile time and design time.
Jeff