+1-888-365-2779
Try Now
More in this section
Categories
Bloggers
Blogs RSS feed

Designing extensible modules - best practices: Host ambivalence

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

 

Throughout the documentation of the new Sitefinity 3.6 backend architecture, many times it has been said that Views should be self contained units of functionality that could function in any given place in the hierarchy. While this claim sounds reasonable, once we start developing real world modules, one may find it not so simple to achieve. Yet, by following some simple rules, we can achieve this host ambivalence and design Views that can function anywhere in the hierarchy of Views.

 

Making host generic


In many examples so far, we have defined the host of a View with an actual type. For example in the Contacts module:
public class ContactsItemsView : ViewModeControl<ContactsControlPanel> 
Here, we have defined the Host of the ContactsItemsView to be ContactsControlPanel. This means that we cannot add ContactsItemsView anywhere else in the hierarchy, except as a child view of the ContactsControlPanel View. While in many cases this may be fine (if a View is specialized enough not to make sense as anything else than child of a particular View), lots of times we may want to keep the freedom to move the View in different places of the hierarchy. For example, we may want to create a CRM module, where the contacts will be only a small part of the functionality of this big module and we’d like to add ContactsItemsView as a child of CrmContactsView. In order to allow for this kind of flexibility, we should change the declaration of our View to allow for generic hosts, as follows:
public class ContactsItemsView<THost> : ViewModeControl<THost> where THost : Control 
It is a requirement of the Sitefinity that every host is a Control, so we are restricting the host to be a Control (where THost : Control).

 

Now, that we have defined the View this way, we will not be able to add the View as we used to:

AddView<ContactsItemsView>(null"AllContacts""CommandPanel_ContactsItems_Desc""all", Messages.ResourceManager); 
But instead we’ll need to define the host for the View we are adding as well, making the statement for adding this new View looking like this:
AddView<ContactsItemsView<ContactsControlPanel>>(null"AllContacts""CommandPanel_ContactsItems_Desc""all", Messages.ResourceManager); 
Now, it becomes clear that if we are to add ContactsItemsView to the CRM module, we could do it very simply by altering the generic host type in the AddView statement:
AddView<ContactsItemsView<CrmContactsView>>(null"AllContacts""CommandPanel_ContactsItems_Desc""all", Messages.ResourceManager); 

 

Specializing generic host


In the previous section we’ve seen how to make the host generic. However, by making host too generic (e.g making it of a type Control) we lose the ability to work with the hierarchy through the this.Host property. Since we don’t know anything about the host, we cannot access its properties.

 

Seemingly, we have to choose between two evils: having crude Views which can only work in a predefined place of the hierarchy or having no access to the members of the hierarchy. Fortunately, we can use the generic constraints to overcome these obstacles and get the best of the both world.

 

Let us suppose that we want to have a View which can be placed anywhere in the hierarchy, but at the same time we wish that whichever View hosts our View, must provide us with the access to the instance of ContactsManager class, so that we can always call this.Host.ContactsManager.

 

Instead of hardcoding the host, we can do following:

 

Create an interface and call it IContactsView - an interface to be implemented by all contact views. The implementation would look like this:
namespace Sample.Contacts.WebControls.Admin 
    public interface IContactsView 
    { 
        ContactsManager ContactsManager { get; } 
    } 
 
Then, we implement this interface on all the Views in the Contacts module. Finally, when we declare the new View we add one more constraint to our generic host type:
public class ContactsItemsView<THost> : ViewModeControl<THost> where THost : Control, IContactsView 
Effectively saying that any View can be a host to ContactsItemsView as long as it is a Control and implements IContactsView interface. So we have been able to keep flexibility, but also introduce some minimal rules in order to allow ourselves to work with the hierarchy.   

 

 

 

Leave a comment