Try Now
More in this section
Blogs RSS feed

Sample pluggable module: Contacts pluggable module - Using embedded templates

by Ivan Osmak
[This post is part of the developer's manual preview published on this blog. You can find temporary TOC here.]


In our Sample Contacts Pluggable Module we have demonstrated how you too can use embedded templates when building your pluggable modules. Before we dissect the approach, we should first consider the two biggest benefits that come with embedding templates:
  • Simplicity of deployment
  • Simplified upgrade process
If you embed all your templates with the module, you will be able to deploy your module with one single file (the assembly or .dll file). This will simplify your own development, but it will also allow you to distribute or sell your module to other Sitefinity implementers with the utmost ease.


Secondly, if you do not distribute the templates as external files, there is no danger that on the module update you will overwrite the modifications made by the developers that use your module.


All in all, you get all the benefits as a module developer, which Sitefinity team gained with this new feature. It is also important to note, that you can effortlessly take advantage of Sitefinity ControlsConfig file to map your embedded templates to external ones. The mapping is a built-in feature of ViewModeControl and SimpleControl base controls.


How to embed a template into the assembly

The process of embedding a template is trivially simple. Here are the steps that you need to perform.
  • Locate the folder in which you wish to place the template. By convention, we at Sitefinity, generally place it in Resources.ControlTemplates.Backend for the administration side templates and in Resources.ControlTemplates.Frontend for the public side templates.
  • Right-click on the folder, select “Add” and then click on “New item…”
  • Visual Studio will not offer you to place a User Control into the assembly, so select “Text File” from the Add New Item dialog, name the template as you wish and change the .txt extension to .ascx
  • The new file has opened and you can declare your template here by placing the markup and controls (same as you would for the User Control)
  • The final and important step is to set the Build Action of the template file to Embedded Resource. To do this right click on your template file, click on “Properties” from the context menu and in the Property Grid, select “Embedded Resource” for Build Action. By default it will probably say “Content”
By following these steps you have completed everything you need to do in order to embed a template.


How to use embedded template in a control

While there are various ways in which you can do this, we will cover the two preferred ways. If you are creating a View you will inherit from the ViewModeControl, on the other hand if you are just creating any control that is not a View you can inherit from a SimpleControl class (both are located in Telerik.Cms.Web.UI namespace). The implemention for both controls is same and looks like follows from this example:


        /// <summary> 
        /// Gets or sets the path to a custom layout template for the control. 
        /// </summary> 
        /// <value></value> 
        [WebSysTemplate(BlogCommentsEditView.BlogCommentsEditViewTemplateName, "BlogCommentsEdit_Desc""/Blogs"false"2009-01-30")] 
        public override string LayoutTemplatePath 
            get { return base.LayoutTemplatePath; } 
            set { base.LayoutTemplatePath = value; } 
        /// <summary> 
        /// Gets the name of the embedded layout template. This property must be overridden to provide the path (key) to an embedded resource file. 
        /// </summary> 
        /// <value></value> 
        protected override string LayoutTemplateName 
            get { return BlogCommentsEditView.BlogCommentsEditViewTemplateName; } 
        private const string BlogCommentsEditViewTemplateName = "Telerik.Blogs.Resources.ControlTemplates.Backend.CommentsEdit.ascx"
There are two properties that we have to implement in order to take advantage of the embedded templates:
  • LayoutTemplatePath and
  • LayoutTemplateName
The constant in the sample is a matter of coding style.


So, let us now examine the decision process of the ViewModeControl and UserControl when they decide how will they load the template:
  • The control will first look for the inline declarative template and if it exists it will use that template (in the example below “LayoutTemplate” is the inline template). You will often declare templates like this, if you use control inside of another template.
    <test:MyControl id="myControl1" runat="server"
            This is my template. 
  • After that, the control will try to see if the LayoutTemplatePath property has been set. This brings us to the first property that we have used in our class. If you wish to use embedded templates you should leave this property to work with base.LayoutTemplatePath and not set it explicitly. The reason why we declare it anyway will be discussed towards the end of this article.
  • The third in the list of priorities is the configuration declaration. So, if there is no inline template and LayoutTemplatePath property has not been set, the base controls will look into the ControlsConfig file to see if the template for this control has been declared.
  • Finally, if none of the three conditions have been met, base controls will call the LayoutTemplateName to retrieve the name of the embedded template (resource) and load the template from that location.
The name of the embedded template is simply its full name including the namespace. In Visual Studio, by default settings, folders respond to the namespaces.

The given priorities ladder ensures for maximum flexibility.


Overriding the LayoutTemplatePath and WebSysTemplate attribute

Looking at the implementation of LayoutTemplatePath one may ask onself why do it, when it apparently does not do anything. The reason for the implementation lays in the WebSysTemplate attribute declared on the property.


WebSysTemplate attribute class needs to be implemented in every assembly that will use embedded templates. The implementation is always same and can be directly pasted from the following example:
/// <summary> 
/// This class defines the attribute for specifying embedded templates 
/// </summary> 
internal class WebSysTemplate : EmbeddedTemplateAttribute 
        public WebSysTemplate(string resourceName, string description 
            , string defaultExtPaht, bool isFrontEnd, string lastModified) 
            : base(resourceName, description, defaultExtPaht, isFrontEnd, lastModified) 
        /// <summary> 
        /// Gets the description. 
        /// </summary> 
        /// <value>The description.</value> 
        public override string Description 
                return Messages.ResourceManager.GetString(base.Description); 
        /// <summary> 
        /// When implemented in a derived class, gets a unique identifier for this <see cref="T:System.Attribute"/>. 
        /// </summary> 
        /// <value></value> 
        /// <returns>An <see cref="T:System.Object"/> that is a unique identifier for the attribute.</returns> 
        public override object TypeId 
                return typeof(EmbeddedTemplateAttribute); 
The reason for this requirement lays in the specifics of the ASP.NET ResourceManager class which is declared as internal.


Now, let us go back to the attribute and its meaning. In Sitefinity 3.6 this attribute does not serve any purpose, but it has been placed here so that your Views and controls can be ready for Sitefinity 4.0 which will feature Template management tool. Let us examine the sample attribute implementation once again:

[WebSysTemplate(BlogCommentsEditView.BlogCommentsEditViewTemplateName, "BlogCommentsEdit_Desc""/Blogs"false"2009-01-30")] 
The first argument is the name (key) of the template, for which it is convenient to use the resource name since it has to be unique for each embedded template. Second attribute is the localization key for the string which describes the purpose of the template. Third argument is the name of default folder to which the upcoming template manager tool will export embedded template and thus make it external. Fourth argument is the Boolean value which determines if the template is used on the backend or the frontend; true means that template is used on frontend. Finally, the last argument is the date when template has been created.


All these information, will be used by our template manager tool to enable users to browse through template, export them and modify them.


Leave a comment
  1. Romi Apr 05, 2009
    Hi Team,
    Some question :
    - Could you use one internal cms page as content for Modules View?. I would use the features of cms to build not only users pages but also admin pages or helping views. I understand that this sol is not for distribute (depending of pages built) but can help building custom solutions. If possible, some tips.
    - Could you use one external page as content for Views and.
     -Could imagine one usercontrol in toolbox that implement basical classes to be abble to work as View and make my second question possible? 
    Many thanks for this new architecture.
  2. Seth Apr 06, 2009
    Hi, I have some questions too:
    - I have a pluggable generic content module based on the new architecture. When someone creates a new product I want to a) check for the existence of a image library called "products" and automatically create a tag in the Images module the same as the SKU of the new product. I know how to do that programmatically but I just don't know where to do it eg. is there a "onSave" method I can override for new content and edit content that I can hook into?
    - In my module I want to have a thumbnail for each product like news. I noticed now that the thumbnail picker is now different to the old one and I want to have a pick which allows picking a image from Libraries not file system and also returns a guid not a url. Is there one already created for this?
    - Once someone picks a thumbnail I think the user should see the thumbnail not the guid or url so I am going to build this functionality.

    Leave a comment