Inheriting from ViewPage - asp.net-mvc

Is it possible to inherit from both ViewPage and ViewPage<T>?? Or do I have to implement both. Currently this is what I have for ViewPage. Do i need to repeat myself and do the same for ViewPage<T>??
public class BaseViewPage : ViewPage
{
public bool LoggedIn
{
get
{
if (ViewContext.Controller is BaseController)
return ((BaseController)ViewContext.Controller).LoggedOn;
else
return false;
}
}
}

Create both versions:
public class BaseViewPage : ViewPage
{
// put your custom code here
}
public class BaseViewPage<TModel> : BaseViewPage where TModel : class
{
// code borrowed from MVC source
private ViewDataDictionary<TModel> _viewData;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public new ViewDataDictionary<TModel> ViewData {
get {
if (_viewData == null) {
SetViewData(new ViewDataDictionary<TModel>());
}
return _viewData;
}
set {
SetViewData(value);
}
}
protected override void SetViewData(ViewDataDictionary viewData) {
_viewData = new ViewDataDictionary<TModel>(viewData);
base.SetViewData(_viewData);
}
}
then
public class MyCustomView : BaseViewPage
{
}
or
public class MyCustomView : BaseViewPage<MyCustomViewData>
{
}

Depending on how you are doing things you might want to look at
ViewContext.HttpContext.Request.IsAuthenticated
it might save you some time instead of extending the ViewPage class.
If there is some other data that you are after you could maybe write an extension method to one of the classes that provides the data. E.g. if LoggedIn was stored in the session you could extend the context to give you an IsLoggedIn() in method.
Edit:
As your extending a class that is already available in the both the base and strongly typed view it will be available in both. The only other way around is to reimplement the strongly typed version as above.

I wouldn't put this in the View, instead I'd have it as a property on the ViewModel (have a BaseViewModel). It will be easier to test as well as ensuring you're not going down the slope of putting business logic into the views.

Related

ViewBag in static method of controller

I am new to mvc and I load ViewBag in a method of controller as,
HomeController: Controller
{
Public ActionResult Index()
{
loadViewBag();
return View();
}
public void loadViewBag()
{
ViewBag.aaa = "something";
}
}
It works fine.
What is my problem is, Now I want to call loadViewBag() method form another controller( say Account) so that I can reuse same method and need to make loadViewBag() method static due to some static variables as:
public static void loadViewBag()
If I make loadViewBag method static, there appear error on ViewBag " An object reference is required for the non-static field, method, or property 'System.Web.Mvc.ControllerBase.ViewBag.get' ".
Is there any solution/suggestion.
Thank You.
Just make it an extension method of ControllerBase e.g.
public static void ControllerExt
{
public static void LoadViewBag(this ControllerBase controller)
{
controller.ViewBag.aaa = "something";
...
}
}
That way you can use it in any controller
public class HomeController : Controller
{
public ActionResult Index()
{
this.LoadViewBag();
return View();
}
}
public class AccountController : Controller
{
public ActionResult Index()
{
this.LoadViewBag();
return View();
}
}
If its only specific to some controllers then it would be more flexible to pass the ViewBag property in e.g.
public static class ControllerHelper
{
public static void LoadViewBag(dynamic viewBag)
{
viewBag.aaa = "something";
}
}
public class HomeController : Controller
{
public ActionResult Index()
{
ControllerHelper.LoadViewBag(ViewBag);
return View();
}
}
ViewBag is a property of your controller (more specifically of ControllerBase), and since a static method has no knowledge of a class instance, you can't access it.
You could pass the controller instance to the method if you want to use a static method or even make it an extension method, but depending on your problem, this solution could be sub-optimal. You may be able to get a better answer if you add more details to your question.
Public ActionResult Index()
{
this.loadViewBag();
return View();
}
public static void loadViewBag(this ControllerBase target)
{
target.ViewBag.aaa = "something";
}
Do you need that to allow different controllers/views to use some common properties?
Then I'd rather recommend a common base controller, while also wrapping ViewBag code into type safe properties (to let the compiler control the data consistency - as you know, ViewBag is not type safe, so any typos and data mismatches won't be noticed until the code gets executed).
1. Introduce a common controller with those wrapper properties
public abstract class MyBaseController : Controller
{
internal long CurrentUserId
{
get { return ViewBag.CurrentUserId; }
set { ViewBag.CurrentUserId = value; }
}
internal Role CurrentUserRole
{
get { return ViewBag.CurrentUserRole; }
set { ViewBag.CurrentUserRole = value; }
}
...
}
Thus, your inherited controllers could simply set the properties - or, with lots of common code just introduce a method in your base controller - similar to what you already have.
2. Introduce a common view class with those wrapper properties
public abstract class MyBaseViewPage<T> : WebViewPage<T>
{
public string Title
{
get { return (string)ViewBag.Title; }
set { ViewBag.Title = value; }
}
public long CurrentUserId
{
get { return (long)ViewBag.CurrentUserId; }
}
public Role CurrentUserRole
{
get { return ViewBag.CurrentUserRole; }
}
}
public abstract class MyBaseViewPage : MyBaseViewPage<dynamic>
{
}
and update web.config to let MVC know you're using a custom base view:
<configuration>
...
<system.web.webPages.razor>
...
<pages pageBaseType="MyRootNamespace.Views.MyBaseViewPage">
...
</pages>
</system.web.webPages.razor>
Now you can use them as normal properties in your controllers and views.

Ninject constructor argument

I have this interface:
public interface IUserProfileService
{
// stuff
}
Implemented by:
public class UserProfileService : IUserProfileService
{
private readonly string m_userName;
public UserProfileService(string userName)
{
m_userName = userName;
}
}
I need this injected into a controller like this:
public class ProfilesController : BaseController
{
private readonly IUserProfileService m_profileService;
public ProfilesController(IUserProfileService profileService)
{
m_profileService = profileService;
}
}
I don't know how I can register this interface and its implementation into Ninject container so that userName param is passed in when the Ninject inits an instance of this service.
Any ideas how I can achieve this?
The technical ninject answer is to use constructor arguments like so:
Bind<IUserProfileService>().To<UserProfileService>().WithConstructorArgument("userName", "karl");
Of course you need to figure out where "karl" comes from. It really depends on your app. Maybe its a web app and it's on the HttpContex? I don't know. If it gets rather complicated then you might want to write a IProvider rather than doing a regular binding.
One alternative is to inject a factory and create your dependency using Create(string userName).
public class UserProfileServiceFactory
{
public IUserProfileService Create(string userName)
{
return new UserProfileService(userName);
}
}
It might seem off to have to create another class but the benefits mostly comes when UserProfileService takes in additional dependencies.
The trick is to not inject the username in that class. You call this class a service so it would probably work transparantly with multiple users. I see two solutions:
Inject an abstraction into the service that represents the current user:
public class UserProfileService : IUserProfileService
{
private readonly IPrincipal currentUser;
public UserProfileService(IPrincipal currentUser)
{
this.currentUser = currentUser;
}
void IUserProfileService.SomeOperation()
{
var user = this.currentUser;
// Do some nice stuff with user
}
}
Create an implementation that is specific to the technology you are working with, for instance:
public class AspNetUserProfileService : IUserProfileService
{
public AspNetUserProfileService()
{
}
void IUserProfileService.SomeOperation()
{
var user = this.CurrentUser;
// Do some nice stuff with user
}
private IPrincipal CurrentUser
{
get { return HttpContext.Current.User; }
}
}
If you can, go with option one.

Custom IIdentity and passing data from an attribute to a controller

Here's my scenario:
I've successfully created a custom IIdentity that I pass to a GenericPrincipal. When I access that IIdentity in my controller I have to cast the IIdentity in order to use the custom properties. example:
public ActionResult Test()
{
MyCustomIdentity identity = (MyCustomIdentity)User.Identity;
int userID = identity.UserID;
...etc...
}
Since I need to do this casting for nearly every action I would like to wrap this functionality in an ActionFilterAttribute. I can't do it in the controller's constructor because the context isn't initialized yet. My thought would be to have the ActionFilterAttribute populate a private property on the controller that I can use in each action method. example:
public class TestController : Controller
{
private MyCustomIdentity identity;
[CastCustomIdentity]
public ActionResult()
{
int userID = identity.UserID;
...etc...
}
}
Question: Is this possible and how? Is there a better solution? I've racked my brain trying to figure out how to pass public properties that are populated in an attribute to the controller and I can't get it.
All you have to do is access the ActionExecutingContext of an overloaded OnActionExecuting() method and make identity public instead of private so your actionfilter can access it.
public class CastCustomIdentity : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
((TestController) filterContext.Controller).Identity = (MyCustomIdentity)filterContext.HttpContext.User;
base.OnActionExecuting(filterContext);
}
}
This could be even easier by using a custom base controller class that all of your controllers would inherit from:
public class MyCustomController
{
protected MyCustomIdentity Identity { get{ return (MyCustomIdentity)User.Identity; } }
}
and then:
public class TestController : MyCustomController
{
public ActionResult()
{
int userID = Identity.UserId
...etc...
}
}
You could use a custom model binder...
I can't remember why I used this method over the base controller method #jfar mentions (which is also a good option), but it works well for me and I actually kinda like it because my actions are more self describing through their parameters.
MyCustomIdentityModelBinder.cs
public class MyCustomIdentityModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.Model != null)
throw new InvalidOperationException("Cannot update instances");
//If the user isn't logged in, return null
if (!controllerContext.HttpContext.User.Identity.IsAuthenticated)
return null;
return controllerContext.HttpContext.User as MyCustomIdentity;
}
}
Inside your application start event in Global.asax.cs
System.Web.Mvc.ModelBinders.Binders.Add(typeof(MyCustomIdentity), new MyCustomIdentityModelBinder());
Then whenever you have a type of MyCustomIdentity as an action parameter, it'll automatically use the MyCustomIdentityModelBinder.
Eg.
public class TestController : Controller
{
public ActionResult Index(MyCustomIdentity identity)
{
int userID = identity.UserID;
...etc...
}
}
HTHs,
Charles

ASP.NET MVC dependency injection and helpers

In asp.net MVC, dependency injection with controllers is simple and straightforward. Now, I'd like to remove most of the logic from views by using helpers. The problem is that these helpers use some of the objects that are injected.
Let me write an example:
public interface ISessionData
{
List<string> IdList {get;}
}
public MyController : Controller
{
public MyController(ISessionData sessionData)
{
...
}
}
session data is injected into controller. So far so good. But now I have a helper. Let's say it looks like this:
public class MyHelper
{
private readonly ISessionData sessionData;
public MyHelper(ISessionData sessionData)
{
this.sessionData = sessionData;
}
public bool CheckSomethingExistsInSession(string id)
{
return sessionData.IdList.Any(x => x.Id.Equals(id));
}
}
Now what? I'd like MyHelper to be injected into view. Only way I can see is adding this helper to model and passing it to view every time. Any other ideas?
In MVC it is better to pass ISessionData data from Controller to View (using ViewModel or ViewData):
ViewData["Session"] = sessionData.IdList.ToList();
And remove ISessionData dependency from the helper. Something like this:
public class MyHelper
{
//private readonly ISessionData sessionData;
public MyHelper(/*ISessionData sessionData*/)
{
//this.sessionData = sessionData;
}
public bool CheckSomethingExistsInSession(string id, IList<...> sessionData)
{
return sessionData.Any(x => x.Id.Equals(id));
}
}
In View:
<% var somethingExists = new MyHelper().CheckSomethingExistsInSession(
1, ViewData["Session"] as IList<...>); %>
UPDATED:
public static class MyHelper
{
public static bool CheckSomethingExistsInSession(string id, IList<...> sessionData)
{
return sessionData.Any(x => x.Id.Equals(id));
}
}
<% var somethingExists = MyHelper.CheckSomethingExistsInSession(
1, ViewData["Session"] as IList<...>); %>
You should remove session logic from your controller's constructor and insert it into the controllers action method by using an IModelBinder. See below:
public class SessionDataModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Get/create session data implementating ISeesionData or whatever here. This will be return to the controller action method.
return new SessionData()
}
}
On you controller you would do something like:
public MyController : Controller
{
public MyController()
{
....
}
public ActionResult Index(ISessionData sessionData)
{
// do stuff with ISessionData.
// Redirect or whatever.
return this.RedirectToAction("Index");
}
}
You need to add your IModelBinder like below for it to be called. You can do this in the http application's startup.
System.Web.Mvc.ModelBinders.Binders[typeof(ISessionData)] = new SessionDataModelBinder();

Generic Inherited ViewPage<> and new Property

Setup:
CustomViewEngine
CustomController Base
CustomViewPage Base (in this base, a new property is added "MyCustomProperty")
Problem:
When a view is strongly typed such as: <# Page Inherits="CustomViewPage<MyCustomObject" MyCustomProperty="Hello">, I get a compiler "Parser" error stating that MyCustomProperty is not a public property of System.Web.Mvc.ViewPage
I have done numerous trial and errors (see below) to see whats causing this error and have come to the following conclusions:
The error only occurs when I declare "MyCustomProperty" or any other property in the #Page directive of the view.
The error will always display "System.Web.Mvc.ViewPage" rather than the declared inherits=".." class.
Update: Looks like Technitium found another way to do this that looks much easier, at least on newer versions of ASP.NET MVC. (copied his comment below)
I'm not sure if this is new in ASP.NET MVC 3, but when I swapped the
Inherits attribute from referencing the generic in C# syntax to CLR
syntax, the standard ViewPageParserFilter parsed generics correctly --
no CustomViewTypeParserFilter required. Using Justin's examples, this
means swapping
<%# Page Language="C#" MyNewProperty="From #Page directive!"
Inherits="JG.ParserFilter.CustomViewPage<MvcApplication1.Models.FooModel>
to
<%# Page Language="C#" MyNewProperty="From #Page directive!"`
Inherits="JG.ParserFilter.CustomViewPage`1[MvcApplication1.Models.FooModel]>
Original answer below:
OK, I solved this. Was a fascinating exercise, and the solution is non-trivial but not too hard once you get it working the first time.
Here's the underlying issue: the ASP.NET page parser does not support generics as a page type.
The way ASP.NET MVC worked around this was by fooling the underlying page parser into thinking that the page is not generic. They did this by building a custom PageParserFilter and a custom FileLevelPageControlBuilder. The parser filter looks for a generic type, and if it finds one, swaps it out for the non-generic ViewPage type so that the ASP.NET parser doesn't choke. Then, much later in the page compilation lifecycle, their custom page builder class swaps the generic type back in.
This works because the generic ViewPage type derives from the non-generic ViewPage, and all the interesting properties that are set in a #Page directive exist on the (non-generic) base class. So what's really happening when properties are set in the #Page directive is that those property names are being validated against the non-generic ViewPage base class.
Anyway, this works great in most cases, but not in yours because they hardcode ViewPage as the non-generic base type in their page filter implementation and don't provide an easy way to change it. This is why you kept seeing ViewPage in your error message, since the error happens in between when ASP.NET swaps in the ViewPage placeholder and when it swaps back the generic ViewPage right before compilation.
The fix is to create your own version of the following:
page parser filter - this is almost an exact copy of ViewTypeParserFilter.cs in the MVC source, with the only difference being that it refers to your custom ViewPage and page builder types instead of MVC's
page builder - this is identical to ViewPageControlBuilder.cs in the MVC source, but it puts the class in your own namespace as opposed to theirs.
Derive your custom viewpage class directly from System.Web.Mvc.ViewPage (the non-generic version). Stick any custom properties on this new non-generic class.
derive a generic class from #3, copying the code from the ASP.NET MVC source's implementation of ViewPage.
repeat #2, #3, and #4 for user controls (#Control) if you also need custom properties on user control directives too.
Then you need to change the web.config in your views directory (not the main app's web.config) to use these new types instead of MVC's default ones.
I've enclosed some code samples illustrating how this works. Many thanks to Phil Haack's article to help me understand this, although I had to do a lot of poking around the MVC and ASP.NET source code too to really understand it.
First, I'll start with the web.config changes needed in your web.config:
<pages
validateRequest="false"
pageParserFilterType="JG.ParserFilter.CustomViewTypeParserFilter"
pageBaseType="JG.ParserFilter.CustomViewPage"
userControlBaseType="JG.ParserFilter.CustomViewUserControl">
Now, here's the page parser filter (#1 above):
namespace JG.ParserFilter {
using System;
using System.Collections;
using System.Web.UI;
using System.Web.Mvc;
internal class CustomViewTypeParserFilter : PageParserFilter
{
private string _viewBaseType;
private DirectiveType _directiveType = DirectiveType.Unknown;
private bool _viewTypeControlAdded;
public override void PreprocessDirective(string directiveName, IDictionary attributes) {
base.PreprocessDirective(directiveName, attributes);
string defaultBaseType = null;
// If we recognize the directive, keep track of what it was. If we don't recognize
// the directive then just stop.
switch (directiveName) {
case "page":
_directiveType = DirectiveType.Page;
defaultBaseType = typeof(JG.ParserFilter.CustomViewPage).FullName; // JG: inject custom types here
break;
case "control":
_directiveType = DirectiveType.UserControl;
defaultBaseType = typeof(JG.ParserFilter.CustomViewUserControl).FullName; // JG: inject custom types here
break;
case "master":
_directiveType = DirectiveType.Master;
defaultBaseType = typeof(System.Web.Mvc.ViewMasterPage).FullName;
break;
}
if (_directiveType == DirectiveType.Unknown) {
// If we're processing an unknown directive (e.g. a register directive), stop processing
return;
}
// Look for an inherit attribute
string inherits = (string)attributes["inherits"];
if (!String.IsNullOrEmpty(inherits)) {
// If it doesn't look like a generic type, don't do anything special,
// and let the parser do its normal processing
if (IsGenericTypeString(inherits)) {
// Remove the inherits attribute so the parser doesn't blow up
attributes["inherits"] = defaultBaseType;
// Remember the full type string so we can later give it to the ControlBuilder
_viewBaseType = inherits;
}
}
}
private static bool IsGenericTypeString(string typeName) {
// Detect C# and VB generic syntax
// REVIEW: what about other languages?
return typeName.IndexOfAny(new char[] { '<', '(' }) >= 0;
}
public override void ParseComplete(ControlBuilder rootBuilder) {
base.ParseComplete(rootBuilder);
// If it's our page ControlBuilder, give it the base type string
CustomViewPageControlBuilder pageBuilder = rootBuilder as JG.ParserFilter.CustomViewPageControlBuilder; // JG: inject custom types here
if (pageBuilder != null) {
pageBuilder.PageBaseType = _viewBaseType;
}
CustomViewUserControlControlBuilder userControlBuilder = rootBuilder as JG.ParserFilter.CustomViewUserControlControlBuilder; // JG: inject custom types here
if (userControlBuilder != null) {
userControlBuilder.UserControlBaseType = _viewBaseType;
}
}
public override bool ProcessCodeConstruct(CodeConstructType codeType, string code) {
if (codeType == CodeConstructType.ExpressionSnippet &&
!_viewTypeControlAdded &&
_viewBaseType != null &&
_directiveType == DirectiveType.Master) {
// If we're dealing with a master page that needs to have its base type set, do it here.
// It's done by adding the ViewType control, which has a builder that sets the base type.
// The code currently assumes that the file in question contains a code snippet, since
// that's the item we key off of in order to know when to add the ViewType control.
Hashtable attribs = new Hashtable();
attribs["typename"] = _viewBaseType;
AddControl(typeof(System.Web.Mvc.ViewType), attribs);
_viewTypeControlAdded = true;
}
return base.ProcessCodeConstruct(codeType, code);
}
// Everything else in this class is unrelated to our 'inherits' handling.
// Since PageParserFilter blocks everything by default, we need to unblock it
public override bool AllowCode {
get {
return true;
}
}
public override bool AllowBaseType(Type baseType) {
return true;
}
public override bool AllowControl(Type controlType, ControlBuilder builder) {
return true;
}
public override bool AllowVirtualReference(string referenceVirtualPath, VirtualReferenceType referenceType) {
return true;
}
public override bool AllowServerSideInclude(string includeVirtualPath) {
return true;
}
public override int NumberOfControlsAllowed {
get {
return -1;
}
}
public override int NumberOfDirectDependenciesAllowed {
get {
return -1;
}
}
public override int TotalNumberOfDependenciesAllowed {
get {
return -1;
}
}
private enum DirectiveType {
Unknown,
Page,
UserControl,
Master,
}
}
}
Here's the page builder class (#2 above):
namespace JG.ParserFilter {
using System.CodeDom;
using System.Web.UI;
internal sealed class CustomViewPageControlBuilder : FileLevelPageControlBuilder {
public string PageBaseType {
get;
set;
}
public override void ProcessGeneratedCode(
CodeCompileUnit codeCompileUnit,
CodeTypeDeclaration baseType,
CodeTypeDeclaration derivedType,
CodeMemberMethod buildMethod,
CodeMemberMethod dataBindingMethod) {
// If we find got a base class string, use it
if (PageBaseType != null) {
derivedType.BaseTypes[0] = new CodeTypeReference(PageBaseType);
}
}
}
}
And here's the custom view page classes: the non-generic base (#3 above) and the generic derived class (#4 above):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Diagnostics.CodeAnalysis;
using System.Web.Mvc;
namespace JG.ParserFilter
{
[FileLevelControlBuilder(typeof(JG.ParserFilter.CustomViewPageControlBuilder))]
public class CustomViewPage : System.Web.Mvc.ViewPage //, IAttributeAccessor
{
public string MyNewProperty { get; set; }
}
[FileLevelControlBuilder(typeof(JG.ParserFilter.CustomViewPageControlBuilder))]
public class CustomViewPage<TModel> : CustomViewPage
where TModel : class
{
// code copied from source of ViewPage<T>
private ViewDataDictionary<TModel> _viewData;
public new AjaxHelper<TModel> Ajax
{
get;
set;
}
public new HtmlHelper<TModel> Html
{
get;
set;
}
public new TModel Model
{
get
{
return ViewData.Model;
}
}
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public new ViewDataDictionary<TModel> ViewData
{
get
{
if (_viewData == null)
{
SetViewData(new ViewDataDictionary<TModel>());
}
return _viewData;
}
set
{
SetViewData(value);
}
}
public override void InitHelpers()
{
base.InitHelpers();
Ajax = new AjaxHelper<TModel>(ViewContext, this);
Html = new HtmlHelper<TModel>(ViewContext, this);
}
protected override void SetViewData(ViewDataDictionary viewData)
{
_viewData = new ViewDataDictionary<TModel>(viewData);
base.SetViewData(_viewData);
}
}
}
And here are the corresponding classes for user controls (#5 above) :
namespace JG.ParserFilter
{
using System.Diagnostics.CodeAnalysis;
using System.Web.Mvc;
using System.Web.UI;
[FileLevelControlBuilder(typeof(JG.ParserFilter.CustomViewUserControlControlBuilder))]
public class CustomViewUserControl : System.Web.Mvc.ViewUserControl
{
public string MyNewProperty { get; set; }
}
public class CustomViewUserControl<TModel> : CustomViewUserControl where TModel : class
{
private AjaxHelper<TModel> _ajaxHelper;
private HtmlHelper<TModel> _htmlHelper;
private ViewDataDictionary<TModel> _viewData;
public new AjaxHelper<TModel> Ajax {
get {
if (_ajaxHelper == null) {
_ajaxHelper = new AjaxHelper<TModel>(ViewContext, this);
}
return _ajaxHelper;
}
}
public new HtmlHelper<TModel> Html {
get {
if (_htmlHelper == null) {
_htmlHelper = new HtmlHelper<TModel>(ViewContext, this);
}
return _htmlHelper;
}
}
public new TModel Model {
get {
return ViewData.Model;
}
}
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public new ViewDataDictionary<TModel> ViewData {
get {
EnsureViewData();
return _viewData;
}
set {
SetViewData(value);
}
}
protected override void SetViewData(ViewDataDictionary viewData) {
_viewData = new ViewDataDictionary<TModel>(viewData);
base.SetViewData(_viewData);
}
}
}
namespace JG.ParserFilter {
using System.CodeDom;
using System.Web.UI;
internal sealed class CustomViewUserControlControlBuilder : FileLevelUserControlBuilder {
internal string UserControlBaseType {
get;
set;
}
public override void ProcessGeneratedCode(
CodeCompileUnit codeCompileUnit,
CodeTypeDeclaration baseType,
CodeTypeDeclaration derivedType,
CodeMemberMethod buildMethod,
CodeMemberMethod dataBindingMethod) {
// If we find got a base class string, use it
if (UserControlBaseType != null) {
derivedType.BaseTypes[0] = new CodeTypeReference(UserControlBaseType);
}
}
}
}
Finally, here's a sample View which shows this in action:
<%# Page Language="C#" MyNewProperty="From #Page directive!" Inherits="JG.ParserFilter.CustomViewPage<MvcApplication1.Models.FooModel>" %>
<%=Model.SomeString %>
<br /><br />this.MyNewPrroperty = <%=MyNewProperty%>
</asp:Content>

Resources