Modifying standard templates without touching ~/Templates folder content

Topics: Developer Forum
Dec 17, 2008 at 9:04 AM
Hello n-squared people !

Does anybody know any (hackfull?) way of altering a stadard templates for N2.Templates project items in a non-obtrusive manner without changing anything in code/markup, but, probably, only by configuration?

Say, i want to add a custom chrome/design to every BoxedText, but do not want either subclassing any content items (and change BoxedText.TemplateUrl), neither i want to touch anything (e.g.: BoxedText.ascx) inside ~/Templates folder (in fact, recently i use to use NTFS Link shell extension to link Templates and Edit folders inside every application to their originals inside n2cms/output/wwwroot/*, so changing them is strongly discouraging).

I guess something like that should be possible by means of [TemplateAttribute], but i only would like to apply it elsewhere, but in original *.cs. (Cool example of dynamically applying .aspx templates is a theming approach of BlogEngine.Net, which i've rediscovered recently)
Dec 17, 2008 at 1:30 PM
Edited Dec 17, 2008 at 2:23 PM
So far my own findings are these:
  • The only point in N2 pipeline where it is possibly to forge a template URL reliably is at ContentItem.FindPath(..), which, of course, require penetration of existing code :=(
  • A standard ASP.Net <urlMapping/> in web.config doesn't apply to user controls (.ascx), because they are served not via requests, but directly by their (virtual, sic!) path :=(
  • And finaly, we've reach an only viable solution: assembling a custom VirtualPathProvider :=)
If you happen to have the same problem and decide to tailor your own provider then of invaluable help will be the article ASP.NET: Reusing Web User Controls and Forms by Kurt Harriger. One warning, though: be carefull when overriding GetFile(string) -- you'll most probably be forced to create your own VirtualFile class to return from this method.

UPD: VPP doesn't work for precompiled applications. EpiServer folks have a remedy, but i could not get it working so far :=(
Dec 17, 2008 at 2:51 PM
Did you tried asp.net control adapters?
Coordinator
Dec 17, 2008 at 7:06 PM
Perhaps this calls for an configuration point. Perhaps like this:

<templates>
    <templatePaths>
        <remove name="BoxedText" />
        <add name="BoxedText" src="~/Templates/UI/Parts/BoxedText.ascx" />
Coordinator
Dec 17, 2008 at 7:36 PM
I peeked at blogengine. It looks very neat. Where should I go looking for the dynamic template theming?
Dec 17, 2008 at 7:52 PM
Mag, that's a good news, thank you for the idea ! ( If only ControlAdapter could support a UserControl class. Well, Reflector suggests that it should .. Cannot wait to investigate it :-)
Dec 17, 2008 at 8:08 PM
Where should I go looking for the dynamic template theming?

Cristian, sorry i've soon realized that BE's approach for theming is hardly applicable to N2. Mainly because BE is much more specific in it's content management tasks, while N2 is truly universal framework, thus, is much harder to generalise.

In particular, what BE is really doing -- is providing different equivalent sub-trees of .aspx/.ascx/.master called "themes", one of which sub-trees is then choosen by means of applying it's .master dynamically in a base page class: BlogBasePage.cs. In BE they have a great benefit to be able to statically link all constituent .aspx/.ascx/.master together within a single "theme". I think that doesn't make any sense in N2.
Dec 17, 2008 at 8:33 PM
Perhaps this calls for an configuration point.
Cristian, let's not be so quick :-) I think than it will happen rather sooner than later, that somebody ask: "but how can i change 'em dynamically?" -- that's, perhaps, why everybody knows a pair of sophisticated "url rewriting" solutions, but hardly had anybody heard about such a standard asp.net feature as <urlMapping/> via web.config.

Here's what comes to my mind on this. At present, N2's approach to architecture could be named something like M+V-C, that is: by all means there is a "View" (.aspx/.ascx), also, evidently there's a "Model" (a ContentItem descendant with a [Definition]), but what is actually missing is a "Controller". More precisely, "Model" can act as "Controller" to some extent, especially since your advance with GetPath/FindTemplate/[Template] stuff recently. What I think would be nice to have now -- is an option to decouple "Controller" from the "Model", or, at least, make their relation configurable, or even better: dynamic. I imagine some hypothetical "feature" so that i could write a sort of "partial" class with some customization to templating, design-time Edit support (ILink!), icon, and so on, but NOT Details/Collections definition. And then, somehow "bind" this "partial" class to an existing (and, well, already compiled) item, say in N2.Templates library.

Maybe there are some good approaches to the topic out there that would be worth reimplementing in N2? Maybe not neccessarily on .Net scene. Nothing comes to mind yet. I'll try to ask our Java guru..
Coordinator
Dec 17, 2008 at 9:32 PM
Hasty, who me? ;) You're very spot on in your analysis about the controller, and the various parts scrambling up to fill parts of it's role. Never so many declarative extension points may never be enough, especially when integrating with existing UI code.

What do you think about the MVC base controller? How about bringing in a similar concept with features such as:
  • Way to (re)define which controller handles a certain content item
  • Choice of the final CurrentItem and parts in zones
  • Choice of rewrite method and aspx template
Dec 19, 2008 at 12:51 PM
Some more bits on it (Model vs. Controller): I think it's remarkable that you've decided to introduce an option to move template-resolution logic from a class itself (TemplateUrl { get; }) to a meta-data ([Template] attribute). Next logical step would be do the same to an icon, zone, ILink, and so on, would it not? After that, to generalise this trend, it would be even more cool to move all this declarative stuff out of the entity class altogether and make it somehow loosely bound to an original entity. Want an example why would it be usefull right away? Just recall N2.Extensions::ContentController<T> class. If it would be possible to tear it off the entity, then it would be possible to reuse all the N2.Template entities for ASP.Net MVC-based solutions without modifying anything in N2.Templates.

On the other hand, it doesn't make sense to blindly copy the ASP.Net Mvc's approach of making no declarative relation between Controller and Model. Contrary to this, having a defined 1:1 relation from a hypothetical Controller to it's present Model/ContentItem could be a distinctive feature of N2.
Jan 23, 2009 at 10:02 AM
It's a long since i've posted this question. Just curious to know: is it now possible to define or override TemplateUrl with a N2.Web.BaseController ?

Intuitively, I'm trying go this way:

[Controls(MyItem), Template("~/MyProject/UI/Parts/MyTemplate.ascx")]
public class MyItemController: BaseController {}

But it doesn't seem to work :-/
Coordinator
Jan 23, 2009 at 8:53 PM
My thought was that this would be done at runtime in the controller:

        public override void RewriteRequest(IWebContext webContext)

The template attribute itself remains on the content item.

Perhaps this code can shed some light.