Fortis & Sitecore Tutorial 1 – Setting up.

I feel like I have to do this. I am going to create set of tutorials about using Fortis framework together with Sitecore. Will walk you through how to create a site using it and show how Fortis makes developers life easier. I have suggested several people to try using it but they complained about lacking of documentation and tutorials. Its time to change it!

Installing and using Fortis to your project is actually very simple, but I will try to make it as detailed as I can (some things would be really obvious, sorry).

All code mentioned in this post is available here https://github.com/vhil/fortis-demo – you can fork the repository and try it.

Let’s get started!

Installing Sitecore

I have installed one of the latest CMS versions (for today) – Sitecore.NET 8.1 (rev. 151003) from downloaded .zip file. My file system tree structure looks like this:

disk-folder-structure

Source code for my project resides inside ‘fortis-demo’ folder and the Sitecore instance lives outside – in ‘Deploy/Website’ folder. As you may guessed ‘Deploy/Data’ is Sitecore data folder and ‘Deploy/Databases’ – sitecore databases. As long as you reading it, you probably know how to install Sitecore instance so that’s about it.

In my setup I have created few templates that are probably very common to any Sitecore website:

sitecore-templates

Few words about them:

‘Content Templates’ – list of templates that are going to be inherited by ‘Content Page’ template and some of them are intended to be inherited in any content templates like ‘Content Title’, ‘Content Body’ and ‘Content Image’. I do it like that in order to minimize my template count and reuse same fields in different templates – that helps if you need to change any existing item to another template you won’t lose data if fields are inherited from same templates.

‘Content Page’ – inherits all templates in Content Templates folder

‘Site Root’ is going to be the root node of the website. It is not a content page and is not supposed to contain any presentation. Its not necessarily to have the home page on the site root node. This template will hold settings for the website.

My content tree looks like this:

demo-content-tree

my SiteDefinitions.config defines that my ‘Site Root’ is not the homepage:


<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
	<sites>
	  <site patch:before="site[@name='website']"  			name="demo"  			hostName="fortis.demo" 			rootPath="/sitecore/content/sites/fortis demo" 			language="en" 			startItem="/home" 			database="web" 			inherits="website" />
	</sites>
  </sitecore>
</configuration>

Thank you Jason Bert, for “inherits” attribute in your post.

As you may have noticed, I do namings of templates and fields using spaces. Fortis is completely okay with that as well as Sitecore and I think it is more editor friendly so in any place where he needs to insert a page or rendering he sees “human friendly” namings. From the other side, as a developer, I don’t need to care about display names. It adds consistency as well so all Sitecore items look the same way.

Creating your website solution and installing Fortis

It would be really silly if I explain how to create a solution in the Visual Studio here 🙂 so there is solution that I have created:

demo-solution

Basically we need 2 projects:

  • .Website
  • .Model

.Website project was created from “ASP.NET MVC Application” project teplate and .Model is just a class library project.

We are going to need an IoC container as it is really preferrable with using Fortis. I am used to SimpleInjector as one of the fastest (together with WebActivatorEx to run DI registration on app start) so have installed those but you are absolutely free to use any other IoC/DI frameworks.

Here are nuget packages and references for those two projects:

Website project:

  • Install-Package Microsoft.AspNet.Mvc
  • Install-Package Fortis
  • Install-Package Fortis.Mvc-5
  • Install-Package SimpleInjector.Integration.Web.Mvc
  • Install-Package WebActivatorEx
  • reference to Sitecore.Kernel.dll
  • reference to Sitecore.Mvc.dll
  • reference to .Model project

Model project:

  • Install-Package Fortis
  • reference to System.Web.dll
  • reference to Sitecore.Kernel.dll
  • reference to Sitecore.ContentSearch.dll
  • reference to Sitecore.ContentSearch.Linq.dll

There is a guideline on how to configure Fortis but will duplicate some of those.

So what we need now is to register Fortis objects to run within Dependency Injection. There is a file in the solution – FortisDemo.Website/App_Start/DependencyInjections.cs:

[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(DependencyInjections), "Initialize", Order = 100)]

namespace FortisDemo.Website
{
	public static class DependencyInjections
	{
		public static void Initialize()
		{
			var container = new Container();

			RegisterFortis(container);

			container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
			container.RegisterMvcIntegratedFilterProvider();

			// Register the container as MVC IDependencyResolver.
			DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));

			// Initialise fortis - this is required for places where we can't use DI
			Global.Initialise(
				container.GetInstance<ISpawnProvider>(),
				container.GetInstance<IItemFactory>(),
				container.GetInstance<IItemSearchFactory>()
			);
		}

		private static void RegisterFortis(Container container)
		{
			container.Register<IItemFactory, ItemFactory>(Lifestyle.Singleton);
			container.Register<IContextProvider, ContextProvider>(Lifestyle.Singleton);
			container.Register<ISpawnProvider, SpawnProvider>(Lifestyle.Singleton);
			container.Register<ITemplateMapProvider, TemplateMapProvider>(Lifestyle.Singleton);
			container.Register<IModelAssemblyProvider, ModelAssemblyProvider>(Lifestyle.Singleton);
			container.Register<ISearchResultsAdapter, SearchResultsAdapter>(Lifestyle.Singleton);
			container.Register<IItemSearchFactory, ItemSearchFactory>(Lifestyle.Singleton);
		}
	}
}

I also noticed that the ISearchResultsAdapter registration is missing here http://fortis.ws/quick-start/setup/. Guys, can you please update that? 🙂

That’s done, this file registers all required Fortis classes and in addition registers all Controllers to run within DI in our solution.

There is one more step we need to do – a slight change to the web.config – adding Fortis section and Website dll reference in it:

<configSections>
<section name="fortis" type="System.Configuration.NameValueSectionHandler" />
  </configSections>
  <fortis>
	<add key="assembly" value="FortisDemo.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </fortis>

And to be full set-up will add the optional thing for Fortis – FortisDemo.Website/App_Config/Include/Fortis/Fortis.Presentation.config:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
	<pipelines>
	  <renderField>
		<processor type="Fortis.Pipelines.RenderField.LinkRenderer, Fortis" patch:before="processor[@type='Sitecore.Pipelines.RenderField.AddBeforeAndAfterValues, Sitecore.Kernel']" />
	  </renderField>
	</pipelines>
  </sitecore>
</configuration>

Congratulations! Now we have everything set up to start using Fortis.

TDS and model generation

OK, now we need to create our model mapped to our Sitecore templates so Fortis can work with it. There is a guideline on how to do Model mappings  for Fortis. It would be crazy thing to do that manually so I will show you how to use Team Development for Sitecore code generation to actually generate model classes.

Please note that TDS is only one option on how to achieve that and there is more ways to generate the model:

  • You can read it from serialized sitecore templates
  • You can use Unicorn  for serialization and versioning your templates and generate model from those
  • You can still read it directly from Sitecore database
  • And you can use Fortis Transitus.

I am used to TDS as it has visual interface and seems to be the most convenient tool for me (as long as your company pays ton of money for its license :))

So FortisDemo solution has two TDS projects:

  • TDS.Content
  • TDS.Master

TDS.Master is the one which will generate us the code. This project is mapped to master database and is supposed to store items that are not editable for sitecore editors and are being updated only by developers:

  • Templates
  • Layouts and Renderings
  • Maybe some more project-specific items

TDS.Content project is intended to share content for development purposes. I have put there my content tree so you can install those items.

TDS.Master is configured next way:

  • Source Web Project is set to .Website project
  • Sitecore Database is set to master

demo-tdsmaster-general.png

Sitecore Deploy folder is set to relative destination which leads outside of git repository to my ‘Deploy/Website’ folder.

demo-tdsmaster-build

And now we need to set up the code generation. You can download T4 templates from Fortis repository here https://github.com/Fortis-Collection/fortis/tree/develop/TDS/Code%20Generation%20Templates . But I slightly modified those with few changes which I will describe below.

Once you added those to your solution you need to tell TDS to use them:

  • Set target project to your .Model project
  • set Code Generation Target File
  • and chose Header and Base transform templates

demo-tdsmaster-codegen

Thats it! Now add all templates to your TDS.Master project and the model will be generated to your file. In FortisDemo solution it is FortisDemo.Model/Autogenerated/Model.cs

My changes to Fortis TDS T4 templates:

I need a base class which I can extend so I have added partial SitecoreItem class and interface for it to be part of code generation and all model classes are now inherited from it. I can write same partial class outside of generated model and extend it. Also SitecoreItem class adds UpdatedDate and Created date fields that are not part of base Fortis.Model.ItemWrapper class. In FortisDemo solution I created that class and extended it with overriding .GetHashCode() and .Equals() methods so I can compare my items by ID and use them inside hash-table collections as a key if I need.

Also I added static classes to keep field names and template ids so we have that if for example we are writing the pipeline and need to access some fields using plain Sitecore API – we can use it like that:

var fieldValue = item.Fields[ContentPageItem.FieldNames.ContentTitle].Value;

That’s about the change and my t4 templates are still in the solution here: https://github.com/vhil/fortis-demo/tree/master/TDS.Master/Code%20Generation%20Templates.

More about Fortis model classes

Fortis model classes are part of domain model if we are talking about the onion architecture with 3 layers so please use them in right place.

All classes are inherited from Fortis.Model.ItemWrapper class which has next properties and methods:

Properties:

  • Original : object – instance of wrapped Sitecore.Data.Items.Item. You can simply do a cast and receive the Sitecore API item object.
  • ItemID : Guid – returns item.ID.Guid
  • ItemShortID: string – returns item.ID.ToShortID().ToString()
  • Name: string – returns item.Name
  • DatabaseName: string – returns item.Database.Name
  • LanguageName: string – returns item.Language.Name
  • ItemLocation: string – returns item.Paths.FullPath
  • DisplayName: string – returns item.DisplayName
  • ChildCount: int – returns item.Children.Count
  • HasChildren: bool – returns item.HasChildren
  • IsLatestVersion: bool – returns item.Versions.IsLatestVersion()
  • IsStandardValues: bool – has been done for content search filtering purposes.
  • SearchTitle: string, virtual – by default returns item.Name but can be overridden for project-specific needs.
  • TemplateIds: IEnumerable<Guid> – returns all inherited template ids including itself. Heavily used for content search purposes.

Methods:

  • Ancestor<T>() where T : IItemWrapper – gets exposed first ancestor item which can be casted to required type
  • T AncestorOrSelf<T>() where T : IItemWrapper
  • IEnumerable Children<T>(bool recursive = false) where T : IItemWrapper – gets exposed children items
  • Delete(): void – executes item.Delete()
  • Publish(bool children):void – publishes the item in current language
  • GenerateUrl():string – returns LinkManager.GenerateUrl(item)
  • T Parent<T>(bool ancestors = true) where T : IItemWrapper
  • T ParentOrSelf<T>() where T : IItemWrapper
  • Save():void – checks if the item in editing mode and executes item.Editing.EndEdit()
  • IEnumerable Siblings() where T : IItemWrapper

notes:

  1. All methods that requires generic type parameter expect the interface to be passed in. For example use myItem.Children<IContentPateItem>()
  2. All methods that returns IEnumerable<T> where T : IItemWrapper returns only items that could be casted to requested type, the rest are being skipped. For example myItem.Children<IContentPageItem>()  would skip all child items of templates that are not or not inherited from ‘Content Page’ template.

In addition to that, generated model adds list of fields of your templates. Those properties return FieldWrapper types – concrete implamentations for specific Sitecore field types.

Here is the list of available field wrappers and field types which they are covering:

  • Fortis.Model.Fields.TextFieldWrapper
    • text
    • single-line text
    • multi-line text
  • Fortis.Model.Fields.RichTextFieldWrapper
    • rich text
  • Fortis.Model.Fields.ListFieldWrapper
    • checklist
    • treelist
    • treelist with search
    • treelistex
    • multilist
    • multilist with search
    • tags
  • Fortis.Model.Fields.BooleanFieldWrapper
    • checkbox
  • Fortis.Model.Fields.DateTimeFieldWrapper
    • date
    • datetime
  • Fortis.Model.Fields.FileFieldWrapper
    • file
  • Fortis.Model.Fields.GeneralLinkFieldWrapper
    • general link
    • general link with search
  • Fortis.Model.Fields.ImageFieldWrapper
    • image
  • Fortis.Model.Fields.IntegerFieldWrapper
    • integer
  • Fortis.Model.Fields.NumberFieldWrapper
    • number
  • Fortis.Model.Fields.LinkFieldWrapper
    • droplink
    • droptree
  • Fortis.Model.Fields.NameValueListFieldWrapper
    • name value list

And here is the interface for base FieldWrapper class and all FieldWrappers implement it:


public interface IFieldWrapper : IWrapper, IHtmlString
	{
		string RawValue { get; set; }

		IHtmlString Render(string parameters = null, bool editing = true);
		IHtmlString Render(object parameters, bool editing = true);
		IHtmlString RenderBeginField(object parameters, bool editing = true);
		IHtmlString RenderBeginField(string parameters = null, bool editing = true);
		IHtmlString RenderEndField();
	}

	public interface IFieldWrapper<T> : IFieldWrapper
	{
		T Value { get; }
	}

All Render methods are implemented to execute the FieldRenderer so the Experience Editor is fully supported when rendering fields. Also the field wrapper implements the IHtmlString interface which allows you to render fields without calling the default Render method in the razor views.
Concrete FieldWrapper implementations adding required behavior to retrieve field type specific values.

ItemFactory

The entry point to Sitecore with Fortis framework is the ItemFactory class.

All methods of the ItemFactory that requires generic type parameter expect the interface to be passed in. For example


var contextItem = this.ItemFactory.GetContextItem<INavigationItem>();

In result the ItemFactory will return you the fully exposed object of the most concrete type even if you requested the very base template interface. In this case if my context item is a ‘Content Page’ I will get an instance of ContentPageItem but hidden by the interface I requested – INavigationItem and I am still able to cast returned object to IContentPageItem.

In addition to that, all methods that returns IEnumerable<T> where T : IItemWrapper returns only items that could be casted to requested type, the rest are being skipped. For example

var contextItem = this.ItemFactory.GetContextItem<INavigationItem>();
var siblings = this.ItemFactory.SelectSibling<INavigationItem>();

would skip all child items of templates that are not or not inherited from ‘Navigation’ template.

Available methods of ItemFactory:

  • Publish(IEnumerable wrappers):void
  • Publish(IEnumerable wrappers, bool children):void
  • T GetSiteHome<T>() where T : IItemWrapper – gets the home page item configured in SiteDefinitions.config
  • T GetSiteRoot<T>() where T : IItemWrapper – gets the site root item configured in SiteDefinitions.config
  • T GetContextItem<T>() where T : IItemWrapper – returns wrapper for Sitecore.Context.Item
  • T Create<T>(IItemWrapper parent, string itemName) where T : IItemWrapper – creates an item in master database and wraps it into generated model class
  • T Select<T>(string path) where T : IItemWrapper
  • T Select<T>(Guid id) where T : IItemWrapper
  • T Select<T>(string path, string database) where T : IItemWrapper
  • T Select<T>(Guid id, string database) where T : IItemWrapper
  • T Select<T>(Guid id, string database, string language) where T : IItemWrapper
  • IEnumerable SelectAll<T>(string path) where T : IItemWrapper
  • IEnumerable SelectAll<T>(string path, string database) where T : IItemWrapper
  • T SelectChild<T>(IItemWrapper item) where T : IItemWrapper
  • T SelectChild<T>(string path) where T : IItemWrapper
  • T SelectChild<T>(Guid id) where T : IItemWrapper
  • T SelectChildRecursive<T>(string path) where T : IItemWrapper
  • T SelectChildRecursive<T>(Guid id) where T : IItemWrapper
  • IEnumerable<T> SelectChildren<T>(IItemWrapper item) where T : IItemWrapper
  • IEnumerable<T> SelectChildren<T>(string path) where T : IItemWrapper
  • IEnumerable<T> SelectChildren<T>(Guid id) where T : IItemWrapper
  • IEnumerable<T> SelectChildrenRecursive<T>(IItemWrapper wrapper) where T : IItemWrapper
  • T SelectSibling<T>(IItemWrapper wrapper) where T : IItemWrapper
  • IEnumerable<T> SelectSiblings<T>(IItemWrapper wrapper) where T : IItemWrapper
  • T GetRenderingDataSource<T>(Control control) where T : IItemWrapper
  • IRenderingModel<TPageItem, TRenderingItem> GetRenderingContextItems<TPageItem, TRenderingItem>(IItemFactory factory = null) where TPageItem : IItemWrapper where TRenderingItem : IItemWrapper
  • IRenderingModel<TPageItem, TRenderingItem, TRenderingParametersItem> GetRenderingContextItems<TPageItem, TRenderingItem, TRenderingParametersItem>(IItemFactory factory = null) where TPageItem : IItemWrapper where TRenderingItem : IItemWrapper where TRenderingParametersItem : IRenderingParameterWrapper

Last two methods returns the RenderingModel instance which will be described in next post when we get to create our renderings.

That’s it! Now you have quite powerful model for your Sitecore templates. As long as we have registered all controllers to run within DI process we can simply inject the IItemFactory into the controller and call for example


var contextItem = this.ItemFactory.GetContextItem<IContentPageItem>();

and that will wrap context item into your ‘ContentPageItem’ generated model class.

Enjoy!

to be continued….

Advertisements

One thought on “Fortis & Sitecore Tutorial 1 – Setting up.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s