HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideLegal TermsGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Alloy demonstration templates

Describes the Alloy sample site which you can install for demonstration and testing purposes.

Alloy is an Optimizely Content Management System (CMS) demonstration template package that contains a site for a fictional company, Alloy Technologies, and to demonstrate the most important features of CMS and give you a site that is ready to explore or to start with.

Optimizely builds the Alloy templates on the latest CMS platform. If you are new to CMS, start by installing a sample site and exploring it in detail to introduce you to the user interface, project structure, and programming patterns.

Tech summary

  • Based on the latest releases
  • Built on ASP.NET MVC 5
  • Based on the responsive Bootstrap by Twitter HTML framework

CMS distributes the templates as a dotnet template. See install a sample site.

Design philosophy

Template development with ASP.NET MVC has been supported since version 7. Optimizely created the Alloy templates as an example of how to build a CMS site with good characteristics in terms of maintainability and performance. They also show an example of how conventions in MVC can be tuned to suit a website like Alloy.

Optimizely built the Alloy templates after discussions with developers who worked with ongoing CMS and MVC development projects. The discussions, prototyping, and unique characteristics of the Alloy site were distilled into design decisions to make extending the Alloy site with new content types and functionality easy. Since then, the templates were continually updated and extended.

Alloy uses MVC (Model-View-Controller), but CMS also supports Razor Pages and templates built into client-side frameworks.

Models

Non-partial views and layouts in the MVC templates use a model of type IPageViewModel<T> where T must be a descendent of PageData. The IPageViewModel interface defines a CurrentPage property and a couple of properties geared towards layouts and framework components. This way, views, including layout files, can rely on some common characteristics of the view model.

To free controllers from having to populate these common properties on the view model, an action filter named PageContextActionFilter is registered globally at startup. This filter inspects the view model which is about to be passed to the view and, given that it is of type IPageViewModel, sets the common properties required by the site's framework.

Should a specific controller or action want to influence the common properties of the view model, it can do so by populating them on the view model as the filter then will not modify them. Alternatively, a controller can implement an interface named IModifyLayout that tells the filter to pass the Layout property of the view model to the controller after having populated it with default values.

An example of a controller that implements IModifyLayout is the controller for the preview page, PreviewController. It modifies the view model to instruct the view to hide the site's header and footer.

View locations and a default controller

The Alloy templates have a controller named DefaultPageController, which can handle page types and returns a view result with a view location set to /Views/<page_type_name>/Index.cshtml.

You can add views for page types by following the above convention for view locations. For page types requiring a controller, create one that is more specific regarding the page type it handles.

A custom view location expander

There are different ways to create partial renderers, templates for pages and blocks in content areas, and such when using ASP.NET MVC Core. Like:

  • create a view component
  • create a partial view in the /Views/Shared folder whose name matches the type name of the content type or,
  • create a partial view that is registered at startup using a class that implements the IViewTemplateModelRegistrator interface (see the TemplateCoordinator class)

The Alloy templates use the two latter approaches extensively, partly because you do not need a view component for many of the blocks in Alloy. As a result, the /Views/Shared folder contains many views, making it difficult to find a specific one. The templates feature a custom view location expander, SiteViewLocationExpander, which adds two additional folders in which you can store the partial views for CMS content – /Views/Shared/PagePartials and /Views/Shared/Blocks.

Content area rendering

The Alloy templates feature a customized rendering of content areas.

To support the design requirements for the Alloy website, implement a class called AlloyContentAreaRenderer for custom rendering of content areas. See the CustomizedRenderingInitialization class to see how you make CMS use a custom renderer for all content areas.

Error handling

The Alloy templates contain a bonus feature in the form of the ErrorHandlingContentRenderer class, which is registered as the default type for the IContentRenderer interface during the site's initialization. It wraps the CMS default implementation and extends it to provide error handling while rendering partial content.

This means that an exception of a number of non-critical types thrown while rendering a block or page in a content area will not crash the entire page. Instead, it will hide the failing partial content. If an editor makes the HTTP request, it renders an error message that you can report to a developer.

598

📘

Note

The error handling is only in place if the application is not attached to a debugger. When attached to a debugger, the request is probably made by a developer and then the standard error handling is used instead, allowing developers to more easily see the error message and stack trace.

Beyond making the site more robust, this functionality also illustrates the flexibility of CMS API.

Navigation components

The Alloy templates feature a single extension method for the HtmlHelper class named MenuList which you use to build the three navigation components on the Alloy site – the top menu, the sub-navigation, and the breadcrumbs.

598

While there are many possible ways to build each of those navigation elements for an MVC site, the MenuList method is specially designed for flexibility through the use of Razor helpers.

The method takes a root page and a Razor helper as an argument. It fetches the children of the root page and filters them based on whether the current visitor can see them and display them in navigation. Finally, it invokes the Razor helper once for each page.

As Razor helpers are essentially C# code, you can use it for many different things, especially because the Razor helpers can recursively invoke themselves.

Dependency resolving

ASP.NET MVC is designed for testability and flexibility, and CMS features the abstractions necessary to use that. Almost all communication with the API is kept out of the view and placed in separate classes and, to a lesser extent, in the controllers.

Dependencies in controllers are injected through their constructors to let you switch out components without modifying controllers and to make the code practical for writing unit tests. ASP.NET MVC resolves dependencies for controllers and other components using a DependencyResolver. ASP.NET MVC sets the ServiceLocatorDependencyResolver class that as the default dependency resolver through the DependencyResolverInitialization initialization module

The dependency resolver wraps the IoC container the CMS uses, meaning you do not have to register implementations for the CMS API. Custom classes in the templates generally do not have corresponding interfaces but instead, have virtual methods, so you do not have to register them while maintaining the ability to write unit tests for code that relies on such types.