MVC3 View Inheritance not possible?

10,435

Solution 1

I believe you would be better off using Helper methods than trying for an inheritance model on views. Use Scott Gu's blog for an introduction:

http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx

http://www.asp.net/mvc/tutorials/creating-custom-html-helpers-cs

Solution 2

It doesn't quite work like that out of the box, although I'm sure with some effort you could get that to work.

Instead, you create Layouts with defined Sections and then derive other Layouts from those adding new sections if you need to. Then, a view will declare which layout it is using via

@{
    Layout = "_Layout.cshtml" // app relative path to layout
}

and can provide markup for any sections as needed using

@section SectionName {
    <p>I'm markup to go into a section in the layout this view is using</p>
}

You can pass data via ViewData and/or ViewBag, so you could use them to pass delegates if you wanted to do that.

Alternatively, you might decide add extension methods to HtmlHelper, UrlHelper or even create a WebViewPage derived from System.Web.Mvc.WebViewPage and add any additional properties/methods onto your derived type then set it as the pageBaseType in the <system.web.webPages.razor> in the web.config used by the views.

Solution 3

The cleanest way I found is to use a @helper declared in App_Code which takes delegates as arguments:

@helper Example(Func<int, HelperResult> fn1, Func<int, HelperResult> fn2) {
 <div>@fn1(100)</div>
 <div>@fn2(200)</div>
}

and then create a view with helper functions:

@helper Custom1(int x) { <span class="small">@x</span> }
@helper Custom2(int x) { <span class="big">@x</span> }

and then invoke shared helper like this:

@Example(Custom1, Custom2)

and, if required, the shared helper can implement a default behaviour if the delegate is null

this is much messier than simply implementing a derived view with a few overriden virtual helpers - but at least it works, is strongly typed, and doesn't use dynamic

Solution 4

Simply use sections and layouts. You would define a layout containing some default contents into sections which could be overridden in child views. You could use the IsSectionDefined method in the layout to test whether a child view overrides this section and if not provide default content.

Share:
10,435

Related videos on Youtube

Jack
Author by

Jack

Updated on June 04, 2022

Comments

  • Jack
    Jack about 2 years

    I want to create an abstract base view (with lots of virtual methods with cshtml) and then create a derived view that optionally overrides these methods to customise the view:

    for example:

    override void Header(string title) {
     <div class="massive">@title</div>
    }
    

    How can this be achieved with razor?

    (doesn't everybody want/need to do this?)

  • Jack
    Jack almost 13 years
    I can't see anyway to override a @helper ?
  • Jack
    Jack almost 13 years
    thanks for the idea - but using @section is too chaotic for serious web apps
  • Jack
    Jack almost 13 years
    why doesn't @helper work in the same way? who thinks up this rubbish?
  • marcind
    marcind almost 13 years
    @Jack I am one of those people who think this up. We designed Razor views to be biult up using composition, not inheritance.
  • Darin Dimitrov
    Darin Dimitrov almost 13 years
    @marcind, thank you very much for this decision. Razor is a really wonderful view engine.
  • Jack
    Jack almost 13 years
    in 2 hours I wrote a custom tool that converts cshtml-like syntax into cs files (either ashx, App_Code, or in a DLL) This basic approach can do everything MVC3 and Razor can do by just using the existing csharp language features. If you hadn't realised OOP was designed to solve these very problems! You don't need "sections" and "layouts" when you have classes and methods! I hoped you guys had learnt from the ASPX webform fiasco, but clearly not. Ivory tower bs.
  • Darin Dimitrov
    Darin Dimitrov almost 13 years
    @Jack, that's really good for you. I hope your issues are solved now and you enjoy a nice drink. At least that's what I did for the past 2 hours :-)
  • AdamCrawford
    AdamCrawford almost 13 years
    The point was really that there isn't a need for inheritance for Views in the MVC model if you have the ability to define methods that are available to all your views anyway. Add the App_Code folder, put a .cshtml file in it that contains your helpers and call those to give you your shared helper functions. You could mentally model this as single layer inheritance if it makes you feel more comfortable. Really, anything complex that isn't rendering - the sort of stuff that would actually require a complex inheritance model, should be done in the model (which can have inheritance).
  • Jack
    Jack almost 13 years
    I will be drinking beer when you are paying the "stupid tax" dealing with out-of-band updates, missing features appearing in the extension gallery, problems with next version of VS, etc. whilst my system carries on working just fine - to be honest I wrote it 6 years ago - when I first saw ASPX - just laughing at how "new" approach from ms is still almost as bad as that kludge. Pro devs do not use this stuff.