Sitecore and SimpleInjector issues with WFFM

I am using Simple Injector as an IoC framework on my Sitecore pojects. And what I faced recently is that Sitecore modules like FXM, WFFM do not work properly.
The reason of that is the default Simple Injector implementation regarding constructor resolution behavior. Lots of Sitecore classes like Controllers implemented the way that they have multiple constructors.
Out of the box, Simple Injector only allows the creation of classes that contain a single public constructor. They explain this as having multiple constructors is an anti-pattern and I agree.

While creating a container and registering types in it I usually register MVC controllers as well to be able to inject dependencies into them by setting the resolver to the default MVC DependencyResolver class.
This means that Sitecore controllers within my solution now are being instantiated by IoC container. When any of them have multiple constructors the Simple Injector throws exception as it can’t instantiate those.
It was quite confusing situation when I installed few Sitecore modules and they just didn’t work as expected and took a while to figure out.

Fortunately there is a solution for that. We can implement a custom constrctor resolution behavior. There are more ways to do that but here is what I use. This class will try to find the most resolvable constructor in the class that is being instantiated. If anything wrong it will just fallback to default “single constructor behavior”.

using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using SimpleInjector;
using SimpleInjector.Advanced;

public class MostResolvableConstructorBehavior : IConstructorResolutionBehavior
{
	private readonly Container container;
	private readonly IConstructorResolutionBehavior fallbackBehavior;

	public MostResolvableConstructorBehavior(Container container)
	{
		this.container = container;
		this.fallbackBehavior = container.Options.ConstructorResolutionBehavior;
	}

	private bool IsCalledDuringRegistrationPhase
	{
		get { return !this.container.IsLocked(); }
	}

	public ConstructorInfo GetConstructor(Type service, Type implementation)
	{
		var constructors = implementation.GetConstructors();

		if (!constructors.Any())
		{
			return this.fallbackBehavior.GetConstructor(service, implementation);
		}

		return constructors.Select(ctor => new { ctor, parameters = ctor.GetParameters() })
				.Where(type => this.IsCalledDuringRegistrationPhase
					|| constructors.Length == 1
					|| type.parameters.All(p => this.CanBeResolved(p, service, implementation)))
				.OrderByDescending(type => type.parameters.Length)
				.Select(type => type.ctor)
			.First();
	}

	private bool CanBeResolved(ParameterInfo p, Type service, Type implementation)
	{
		return this.container.GetRegistration(p.ParameterType) != null || this.CanBuildType(p, service, implementation);
	}

	private bool CanBuildType(ParameterInfo p, Type service, Type implementation)
	{
		try
		{
			this.container.Options.DependencyInjectionBehavior.BuildExpression(new InjectionConsumerInfo(service, implementation, p));
			return true;
		}
		catch (ActivationException)
		{
			return false;
		}
	}
}

And now we just need to do this while initializing the container:

container.Options.ConstructorResolutionBehavior = new MostResolvableConstructorBehavior(container);

So my initializer class looks like this:

using System.Web.Mvc;
using SimpleInjector;
using SimpleInjector.Integration.Web.Mvc;
using Sitecore.Pipelines;

namespace Website
{
	public class DependencyInjectionInitializer
	{
		public void Process(PipelineArgs args)
		{
			Initialize();
		}

		public static void Initialize()
		{
			var container = new Container();
			
			// Change the consturctor resolution behavior here
			container.Options.ConstructorResolutionBehavior = new MostResolvableConstructorBehavior(container);
			
			// Register all solution related types
			RegisterWebsiteTypes(container);
			
			container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
			container.RegisterMvcIntegratedFilterProvider();

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

		private static void RegisterWebsiteTypes(Container container)
	    {
            // container.Register<ISitecoreContext, SitecoreContext>(Lifestyle.Transient);
			// ...
		}
	}
}

If that’s unclear, I initialize the container in the ‘initialize’ Sitecore pipeline by having next config:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <initialize>
        <processor type="Website.DependencyInjectionInitializer, Website" />
      </initialize>
    </pipelines>
  </sitecore>
</configuration>

This solution works for me now, all modules came back to normal working, but still need to test that more lol🙂
Hope it was helpful🙂

Sitecore Cache Key Profiling

Not sure what’s the problem with your Sitecore rendering cache setup?
Since Sitecore 8 version has been released I have been experiencing issues with caching. First is that one I described earlier, then I figured out that one of my renderings is being placed inside of another and it applies caching from the parent rendering and that was wrong apparently🙂

In result I came up with idea that I need to see what cache keys are being generated for each of my renderings on the page.
Just wrapped that into a nuget package to share with you guys! So that is just another Helpfulcore module for your Sitecore solution.

If you go to your nuget Package Manager Console and install this to your website project

Install-Package Helpfulcore.CacheKeyProfiling

You will be able to see something like this at your page source html:

<!-- Site name: website -->
<!-- Database: web -->
<!-- Language: da -->

<!-- Cache Key list: -->
<!-- controller::Seo#Metadata_#lang:DA_#area:Seo_#data:/sitecore/content/sites/website/Home_#parm:_#qs:  -->
<!-- view::/Views/Layouts/_Partials/Stylesheets.cshtml_#lang:DA  -->
<!-- view::/Views/Layouts/_Partials/Icons.cshtml_#lang:DA  -->
<!-- view::/Views/Layouts/_Partials/Fonts.cshtml_#lang:DA  -->
<!-- view::/Views/Layouts/_Partials/HeadExtras.cshtml_#lang:DA  -->
<!-- view::/Views/Layouts/_Partials/BrowserUpgrade.cshtml_#lang:DA  -->
<!-- view::/Views/Layouts/_Partials/GlobalCookieMessage.cshtml_#lang:DA  -->
<!-- view::/Views/Layouts/_Partials/SiteLogos.cshtml_#lang:DA  -->
<!-- controller::Navigation#MainNavigation_#lang:DA_#area:Navigation_#data:/sitecore/content/sites/website/Home_#login:True_#parm:_#qs:  -->
<!-- controller::Navigation#MainSideNavigation_#lang:DA_#area:Navigation_#data:/sitecore/content/sites/website/Home_#login:True_#parm:_#qs:  -->
<!-- view::/Views/SimpleContent/Hero.cshtml_#lang:DA_#data:/sitecore/content/sites/website/website-content/heros/hero-test_#parm:_#qs:  -->
<!-- view::/Views/LiveFeeds/JackpotsNow.cshtml_#lang:DA_#data:/sitecore/content/sites/website/website-content/sidebar/website-jackpot-boxes/jackpotter-nu_#parm:_#qs:  -->
<!-- view::/Views/LiveFeeds/NewWinners.cshtml_#lang:DA_#data:/sitecore/content/sites/website/website-content/sidebar/website-winner-boxes/nye-vindere_#parm:_#qs:  -->
<!-- view::/Views/SimpleContent/BoxLink.cshtml_#lang:DA_#data:/sitecore/content/sites/website/website-content/sidebar/website-link-boxes/box-link-test_#parm:_#qs:  -->
<!-- controller::Games#GameList_#lang:DA_#area:Games_#data:/sitecore/content/sites/website/Home_#dev:Default#isMobile:False_#login:True_#parm:Hide Title=1&amp;Associated Tags={EA74A9BD-38C4-4012-80AE-95D443479470}|{2CCE6B9C-398A-457A-B86E-8F7D1B57B369}&amp;Page Size=17&amp;Hide Pagination=1&amp;Autocomplete Page Size=50_#qs:  -->
<!-- view::/Views/SimpleContent/BoxImage.cshtml_#lang:DA_#data:/sitecore/content/sites/website/website-content/sidebar/website-image-boxes/box-image-test-motiejus_#parm:_#qs:  -->
<!-- view::/Views/SimpleContent/BoxText.cshtml_#lang:DA_#data:/sitecore/content/sites/website/website-content/sidebar/website-text-boxes/box_#parm:_#qs:  -->
<!-- controller::Footer#Footer_#lang:DA_#area:Footer_#data:/sitecore/content/sites/website/Home_#parm:_#qs:  -->
<!-- view::/Views/Layouts/_Partials/BottomScripts.cshtml_#lang:DA  -->

This way you can see what cache keys are being generated during the pipeline for each of rendering on your page.
Personally for me that helped a lot to resolve my rendering caching issues on the website.

Will describe the module a bit:

Package contents:

– /bin/Helpfulcore.CacheKeyProfiling.dll
– /App_Config/Include/Helpfulcore/Helpfulcore.CacheKeyProfiling.config
– /Views/Shared/CacheKeyProfiling/CacheKeys.cshtml

Pipeline injection

In the include config file Helpfulcore.CacheKeyProfiling.config I am injecting into pipeline and saving generated cache keys into current request.

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <mvc.renderRendering>
        <processor type="Helpfulcore.CacheKeyProfiling.Pipelines.RenderRendering.GatherCacheKeys, Helpfulcore.CacheKeyProfiling" patch:before="*[@type='Sitecore.Mvc.Pipelines.Response.RenderRendering.RenderFromCache, Sitecore.Mvc']" />
      </mvc.renderRendering>
    </pipelines>
  </sitecore>
</configuration>

Usage

And then I have a view /Views/Shared/CacheKeyProfiling/CacheKeys.cshtml which reads previously saved collection and outputs it as HTML comments.
In order to render it you will need to write one extra line of code on your layout file. Render it at the bottom of the page for convenience.

	@Html.RenderCacheKeys()

And that’s it folks!

The source code for the package is at GitHub here

Inversion of Control and dependency management with Sitecore configuration factory

Today, when we talk about modern software application development, its quite obvious that using Inversion of Control (IoC) design principle is a must have. Having ability to change dependencies of the component without changing the component itself is very important for any kind of application I think.

When you creating a Sitecore website you still can use one of the IoC frameworks and there are an amazing number of them today available. First link in google gives me this post with the list and that is only a small part of existing frameworks.

Having them in your solution is great, but what if you are creating a Sitecore module or a nuget package? That is the case where you need to provide a decent level of extensibility so your module can be re-used, extended, and changed on client side if needed (by client side I mean the solution which uses your module).

In the same time it needs to be de-coupled enough so the IoC principle is still a must have here but there are some limitations:

  • You can’t really use one of those frameworks because you don’t want solution which uses your module to depend on a specific IoC framework
  • Actually you don’t really want your module to depend on any specific IoC framework
  • You need to declare a list of dependencies and instructions on how to register them in the IoC container so your module runs properly

Using Sitecore configuration factory to handle dependencies

This is not a new feature or approach but recently I found out for myself a nice out-of-the-box feature of Sitecore which helps with the dependency management. And that is a default Sitecore.Configuration.Factory.
Here are some links about it:

For start will bring an example of configuring one of my Helpfulcore modules – the logging service.
I have an abstracted logging service which can contain a number of logging providers to write to and they are being injected via constructor:

// source from https://github.com/vhil/helpfulcore-logging/blob/master/Sources/Helpfulcore.Logging/LoggingService.cs
public class LoggingService : ILoggingService
{
	private readonly ILoggingProvider[] loggingProviders;

	public LoggingService(ILoggingProvider provider)
		:this(new []{provider})
	{
	}

	public LoggingService(ILoggingProvider provider1, ILoggingProvider provider2)
		:this(new[] { provider1, provider2 })
	{
	}

	public LoggingService(params ILoggingProvider [] providers)
	{
		this.loggingProviders = providers;
	}
	...
}

And there are two implementations of ILoggingProviders

And now I want to configure a global logging service for my website to use both logging providers. I create a configuration inside default configuration node using include config files so resulting config looks like this:

<sitecore>
  <helpfulcore>
    <logging>
      <loggingService type="Helpfulcore.Logging.LoggingService, Helpfulcore.Logging" singleInstance="true">
        <param name="provider1" ref="helpfulcore/logging/providers/scLoggingProvider"/>
		<param name="provider2" ref="helpfulcore/logging/providers/nlogLoggingProvider"/>
      </loggingService>
      <providers>
	    <scLoggingProvider type="Helpfulcore.Logging.Sc.ScLoggingProvider, Helpfulcore.Logging.Sc" singleInstance="true"/>
        <nlogLoggingProvider type="Helpfulcore.Logging.NLog.NLogLoggingProvider, Helpfulcore.Logging.NLog" filePath="$(dataFolder)/logs/Website.log.${date:format=yyyyMMdd}.txt" singleInstance="true">
          <param name="filePath">$(filePath)</param>
        </nlogLoggingProvider>
      </providers>
    </logging>
  </helpfulcore>
</sitecore>

So there are two providers configured in the section and they are being passed as “ref” attributes into the loggingService as constructor parameters. Im my code now I can get the instance of the logging service just by calling the configuration factory method:

var loggingService = Factory.CreateObject("helpfulcore/logging/loggingService", true) as ILoggingService;

This call will resolve all related dependencies as described in the config and create all configured instances including “singleInstance” lifestyle if declared. Also I can register this instance in my IoC container for my Sitecore website;

container.Register(
		typeof(ILoggingService),
		() => Factory.CreateObject("helpfulcore/logging/loggingService", true) as ILoggingService,
	Lifestyle.Singleton);

Okay. Now I want to implement a service which uses the logging service and injects it as a dependency.  so it can write to log about its actions. So I create a service

public class MyService : IMyService
{
	protected readonly ILoggingService Logger;

	public MyService(ILoggingService logger)
	{
		this.Logger = logger;
	}
	...
}

The key point in all of that is having control under your dependency injections. I am used to inject everything via constructor and MyService implementation here has a constructor dependency on ILoggingService. What I do next is I am creating configuration for it in the sitecore include file:

<sitecore>
  <myFeature>
	  <myService type="MyNamespace.MyService, MyAssembly">
		<param name="logger" ref="helpfulcore/logging/loggingService"/>
	  </myService>
  </myFeature>
</sitecore>

And now I can get an instance of it from the factory method with default logging service being injected:

var myService = Factory.CreateObject("myFeature/myService", true) as IMyService;

That’s it. It all looks and works great now. But at some point I can decide that ok, I want my service to write to its own log file so I can monitor its actions in a more readable way. So what I can do now is to just change the config file by configuring new instance of logging service with one dedicated provider which writes to MyService.log.${date:format=yyyyMMdd}.txt log file and changing the logger reference in myService configuration node.

<sitecore>
  <myFeature>
    <myService type="MyNamespace.MyService, MyAssembly">
      <param name="logger" ref="myFeature/logging/loggingService"/>
    </myService>
    <logging>
      <loggingService type="Helpfulcore.Logging.LoggingService, Helpfulcore.Logging" singleInstance="true">
        <param name="provider1" ref="myFeature/logging/providers/nlogLoggingProvider"/>
      </loggingService>
      <providers>
        <nlogLoggingProvider type="Helpfulcore.Logging.NLog.NLogLoggingProvider, Helpfulcore.Logging.NLog" filePath="$(dataFolder)/logs/MyService.log.${date:format=yyyyMMdd}.txt" singleInstance="true">
          <param name="filePath">$(filePath)</param>
        </nlogLoggingProvider>
      </providers>
    </logging>
  </myFeature>
</sitecore>

No code changes required, all dependencies are controlled in config files and its really simple to use.

Configure Fortis as an example

As a separate example I can configure the Fortis framework  in the include config file. Fortis framework is all built on constructor dependency injection approach so that will be quite simple for me now.

<sitecore>
  <fortis>
    <itemFactory type="Fortis.Model.ItemFactory, Fortis" singleInstance="true">
      <param name="contextProvider" ref="fortis/dependencies/contextProvider" />
      <param name="spawnProvider" ref="fortis/dependencies/spawnProvider" />
    </itemFactory>
    <spawnProvider type="Fortis.Providers.SpawnProvider, Fortis" singleInstance="true">
      <param name="templateMapProvider" ref="fortis/dependencies/templateMapProvider" />
    </spawnProvider>
    <templateMapProvider type="Fortis.Providers.TemplateMapProvider, Fortis" singleInstance="true">
      <param name="modelAssemblyProvider" ref="fortis/dependencies/modelAssemblyProvider" />
    </templateMapProvider>
    <modelAssemblyProvider type="Fortis.Providers.ModelAssemblyProvider, Fortis" singleInstance="true"/>
    <itemSearchFactory type="Fortis.Search.ItemSearchFactory, Fortis" singleInstance="true">
      <param name="templateMapProvider" ref="fortis/dependencies/templateMapProvider" />
      <param name="searchResultsAdapter" ref="fortis/dependencies/searchResultsAdapter" />
    </itemSearchFactory>
    <searchResultsAdapter type="Fortis.Search.SearchResultsAdapter, Fortis" singleInstance="true"/>
    <contextProvider type="Fortis.Mvc.Providers.ContextProvider, Fortis.Mvc" singleInstance="true"/>
  </fortis>
</sitecore>

As described in documentation I need to initialize the Fortis.Global factory class on the application start with three instances so I do it like this:

Global.Initialise(
	Factory.CreateObject("fortis/spawnProvider", true) as ISpawnProvider,
	Factory.CreateObject("fortis/itemFactory", true) as IItemFactory,
	Factory.CreateObject("fortis/itemSearchFactory", true) as IItemSearchFactory
);

And I still can do the same for my IoC if I use one.
Pretty amazing feature and its all a default Sitecore functionality.

Helpfulcore

Talking about “helpfulcore” term referenced above – it became my “pet” project collection for small features that I use from project to project. They all are nuget packages except the Wildcard module.
Will share the list in case you may be interested in using them, for me they are just helpful (read from the name lol :))

Will keep you updated if any new helpful module appears in my collection.
Thanks for reading, now go and implement something amazing!🙂

Fortis & Sitecore Tutorial 3 – using Sitecore ContentSearch API

Sitecore ContentSearch API is a rather powerful functionality that gives you pretty much unlimited capabilities in retrieving sets of items in your Sitecore installation using Lucene or SOLR search engines which Sitecore currently supports.
Using Fortis framework in your Sitecore solution gives you auto-generated model (using TDS or any other way of to generate it) and would be logical if we can query the search index using typed ItemWrapper based models.
Yes, Fortis supports these features out of the box and this topic is about how to use them.
All code mentioned in this post can be found on GitHub here.

Simple query example

Let’s imagine I have a product repository as a Sitecore Bucket item where I store my product items.

products-bucket

And I want to create a rendering which will list them all on the page.

fortis-demo-product-list

So I implement a ProductService class with a method for retrieving my product items

using System;
using System.Collections.Generic;
using System.Linq;
using Fortis.Search;
using FortisDemo.Model.Templates.UserDefined;
using Sitecore;
using Sitecore.ContentSearch;

namespace FortisDemo.Products
{
	public class ProductService : IProductService
	{
		protected readonly IItemSearchFactory ItemSearchFactory;

		public ProductService(IItemSearchFactory itemSearchFactory)
		{
			this.ItemSearchFactory = itemSearchFactory;
		}

		public IEnumerable<IProductPageItem> GetAlProducts()
		{
			var productRepositoryID = new Guid("{C1F3F0A1-145D-44A8-B2A3-2F395F10A653}");
			using (var searchContext = ContentSearchManager.CreateSearchContext((SitecoreIndexableItem)Context.Item))
			{
				var queryable = searchContext.GetQueryable<IProductPageItem>();

				return this.ItemSearchFactory.FilteredSearch(queryable)
					.Where(x => x.Paths.Contains(productRepositoryID))
					.ToList();
			}
		}
	}
}

Yes, as simple as that!
As we can see, the method returns us typed items wrapped into the IProductPageItem. And these item wrappers still have an instance of Sitecore.Data.Items.Item inside of them and when using these objects in the rendering we can access actual values from the Sitecore (and not from the index).

And this method is being called in my ProductController to fill the product list property of my view model:

using System.Web.Mvc;
using Fortis.Model;
using FortisDemo.Model.Templates.UserDefined;
using FortisDemo.Products;
using FortisDemo.Web.Mvc.Controllers;
using FortisDemo.Website.Areas.Product.Models;

namespace FortisDemo.Website.Areas.Product.Controllers
{
	public class ProductController : WebsiteController
	{
		protected readonly IProductService ProductService;

		public ProductController(IItemFactory itemFactory, IProductService productService) 
			: base(itemFactory)
		{
			this.ProductService = productService;
		}

		public ActionResult ProductList()
		{
			var renderingModel = new ProductListRenderingModel(this.ItemFactory.GetRenderingContextItems<IContentPageItem, IContentPageItem>())
			{
				Products = this.ProductService.GetAlProducts()
			};

			return View(renderingModel);
		}
	}
}

Installation & Configuration

In order to be able to use that you will need to install the respective nuget package to your website project depending on which search provider your Sitecore instance uses.

And that will be either


Install-Package Fortis.Search.Lucene

or


Install-Package Fortis.Search.Solr

These packages will install required Fortis dlls and a configuration files.
For Lucene there will be

  • Fortis.Search.Lucene.dll
  • /App_Config/Include/Fortis/Fortis.Search.Lucene.config

and for SOLR

  • Fortis.Search.Solr.dll
  • /App_Config/Include/Fortis/Fortis.Search.Solr.config

Config files will include configuration for index document property mapper so Sitecore can map indexed items to the Fortis ItemWrapper classes. Also there is a declaration of several computed search fields.

Fortis.Search.Lucene.config:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
	<sitecore>
		<contentSearch>
			<indexConfigurations>
				<defaultLuceneIndexConfiguration>
					<indexDocumentPropertyMapper>
						<patch:attribute name="type">Fortis.Search.LuceneDocumentTypeMapper, Fortis.Search.Lucene</patch:attribute>
						<objectFactory>
							<patch:attribute name="type">Fortis.Search.DefaultDocumentMapperObjectFactory, Fortis</patch:attribute>
						</objectFactory>
					</indexDocumentPropertyMapper>
					<fields hint="raw:AddComputedIndexField">
						<field fieldName="_isstandardvalues">Fortis.Search.ComputedFields.IsStandardValues, Fortis</field>
						<field fieldName="_templates">Fortis.Search.ComputedFields.InheritedTemplates, Fortis</field>
					</fields>
				</defaultLuceneIndexConfiguration>
			</indexConfigurations>
		</contentSearch>
	</sitecore>
</configuration>

Fortis.Search.Solr.config:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
	<sitecore>
		<contentSearch>
			<indexConfigurations>
				<defaultSolrIndexConfiguration>
					<indexDocumentPropertyMapper>
						<patch:attribute name="type">Fortis.Search.SolrDocumentTypeMapper, Fortis.Search.Solr</patch:attribute>
						<objectFactory>
							<patch:attribute name="type">Fortis.Search.DefaultDocumentMapperObjectFactory, Fortis</patch:attribute>
						</objectFactory>
					</indexDocumentPropertyMapper>
					<fields hint="raw:AddComputedIndexField">
						<field fieldName="_isstandardvalues" returnType="bool">Fortis.Search.ComputedFields.IsStandardValues, Fortis</field>
						<field fieldName="_templates" returnType="string">Fortis.Search.ComputedFields.InheritedTemplates, Fortis</field>
					</fields>
				</defaultSolrIndexConfiguration>
			</indexConfigurations>
		</contentSearch>
	</sitecore>
</configuration>

How it works

So there is no magic really and Fortis uses default Sitecore attributes to map the properties to the indexed fields in the auto-generated model classes:
For example for the ContentTitle field we will see two properties:


[IndexField(IndexFieldNames.ContentTitle)]
public virtual ITextFieldWrapper ContentTitle
{
	get { return GetField<TextFieldWrapper>(FieldNames.ContentTitle, IndexFieldNames.ContentTitle); }
}

[IndexField(IndexFieldNames.ContentTitle)]
public string ContentTitleValue
{
	get { return ContentTitle.Value; }
}

The second one ends with “Value” and these properties are intended to be used in LINQ expressions syntax for the IQueryable. This is done because in Fortis each property is an ItemWrapper and expressions not always work properly when writing nested property calls like item.ContentTitle.Value.

ItemSearchFactory

There are few examples on using the ItemSearchFactory here.
Basically there are several options you can use:

  • .Search(IQueryable qyeryable) method. In result you will have an IQueryable and you can do anything with it. Just call .ToList() on it to execute your query.
  • .FilteredSearch(IQueryable qyeryable) – this method will add into your queryable filters so StandardValues items will be skipped, the search will be only in the context language and in the latest item versions. Returns the IQueryable.
  • .GetResults(IQueryable qyeryable) – this method will execute your queryable and return the instance of ISearchResults where you can get some extended search result data.

ISearchResults interface:

public interface ISearchResults<TSource> : IEnumerable<ISearchHit<TSource>>, IEnumerable
{
	FacetResults Facets { get; set; }

	IEnumerable<ISearchHit<TSource>> Hits { get; set; }

	int TotalHits { get; set; }
}

IQueryable extensions

Fortis framework comes with number of IQueryable extension methods to help you writing your queries. They are mostly self-explanatory:

  • .WhereContextLanguage()
  • .WhereLatestVersion()
  • .WhereNotStandardValues()
  • .ApplyFilters() – this extension just calls all three methods above
  • .ContainsAnd(x => x.TagsValue, guidEnumerable) – select items where multilist field “Tags” contain all items in the guidEnumerable
  • .ContainsOr(x => x.TagsValue, guidEnumerable) – select items where multilist field “Tags” contain at least one item in the guidEnumerable

What are you waiting for? Go and try it!🙂

Helpfulcore.RenderingExceptions styling updated!

Recently I wrote about handling the rendering exceptions in Sitecore in the post from Novemver 15th.
Last week I have updated the styling for them:

  • Now error messages should look the same way on any website you install the package
  • The css classes became more unique now so won’t conflict with any classes of your website
  • The “expand” button finally well-styled!
  • Exception types are moved to separate assembly and package so you can use them in any project of your solution without adding Sitecore website specific files.

I have attached new screen-shots to the original blog post.
If you are using this package, you can simply run


Update-Package Helpfulcore.RenderingExceptions

Say “yes” if nuget prompts you to override the .cshtml files (if you didn’t style them completely your way).

Enjoy!

@Html.Sitecore().Rendering(pathOrId) does not apply “VaryBy” settings

This week I have faced with one unexpected issue in Sitecore 8.1.
We are declaring few renderings on the layout using the Rendering method of the SitecoreHelper class in Sitecore.Mvc.dll.


@Html.Sitecore().Rendering("/sitecore/layout/Renderings/MyRendering")

The issue can be reproduced by setting the “Cacheable” to true and applying the “VaryBy” settings. In result I can see that the “Cacheable” is set but the rendering does not vary by anything I am trying to set there. And my rendering looks the same on all pages.
After some de-compiling and digging around I found that the CacheKey is not being properly generated due to wrong code in the Sitecore.Mvc.Helpers.SitecoreHelper class of Sitecore.Mvc dll.
The issue is that by some reason this method tries to read fields from the rendering item with these field names:

"Cache_Timeout"
"Cache_VaryByData"
"Cache_VaryByDevice"
"Cache_VaryByLogin"
"CacheKey"
"Cache_VaryByParameters"
"Cache_VaryByQueryString"
"Cache_VaryByUser"
"DataSource"

And yes, the rendering item does not have these fields. Correct names for some of them are:

"VaryByData"
"VaryByDevice"
"VaryByLogin"
"VaryByParm"
"VaryByQueryString"
"VaryByUser"
"Data Source"

And “Cache_Timeout” and “CacheKey” does not exist at all.

I have reported a bug to Sitecore support and they promised to investigate the issue. Meanwhile I have implemented my own helper class to render the Rendering from markup and the code is below.

using System.IO;
using System.Web;
using Sitecore.Data.Items;
using Sitecore.Mvc.Extensions;
using Sitecore.Mvc.Helpers;
using Sitecore.Mvc.Pipelines;
using Sitecore.Mvc.Pipelines.Response.RenderRendering;
using Sitecore.Mvc.Presentation;

namespace Helpers
{
	public class SitecoreHelper
	{
		public static HtmlString Rendering(string renderingItemPathOrId)
		{
			return Rendering(renderingItemPathOrId, null);
		}

		public static HtmlString Rendering(string renderingItemPathOrId, object parameters)
		{
			return RenderRendering(GetRendering(string.Empty, parameters, "RenderingItemPath", renderingItemPathOrId));
		}

		protected static Rendering GetRendering(string renderingType, object parameters, params string[] defaultValues)
		{
			var rendering = new Rendering
			{
				RenderingType = renderingType
			};

			var index = 0;
			while (index < defaultValues.Length - 1)
			{
				rendering[defaultValues[index]] = defaultValues[index + 1];
				index += 2;
			}

			if (rendering.RenderingItem != null)
			{
				// Changed field names
				var innerItem = rendering.RenderingItem.InnerItem;
				CopyPropertyFromDefinitionItem(rendering, innerItem, "Cacheable");
				CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByData", "Cache_VaryByData");
				CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByDevice", "Cache_VaryByDevice");
				CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByLogin", "Cache_VaryByLogin");
				CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByParm", "Cache_VaryByParameters");
				CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByQueryString", "Cache_VaryByQueryString");
				CopyPropertyFromDefinitionItem(rendering, innerItem, "VaryByUser", "Cache_VaryByUser");
				CopyPropertyFromDefinitionItem(rendering, innerItem, "ClearOnIndexUpdate", "Cache_ClearOnIndexUpdate");
				CopyPropertyFromDefinitionItem(rendering, innerItem, "Data Source", "DataSource");
				CopyPropertyFromDefinitionItem(rendering, innerItem, "Model");
			}

			if (parameters != null)
			{
				TypeHelper.GetProperties(parameters)
					.Each(pair => rendering.Properties[pair.Key] = pair.Value.ValueOrDefault(o => o.ToString()));
			}

			return rendering;
		}

		protected static void CopyPropertyFromDefinitionItem(
			Rendering rendering, 
			BaseItem definitionItem, 
			string fieldName, 
			string propertyName = null)
		{
			var field = definitionItem.Fields[fieldName];
			propertyName = propertyName ?? fieldName;

			if (field == null || field.Value.IsWhiteSpaceOrNull())
			{
				return;
			}

			rendering[propertyName] = definitionItem[fieldName];
		}

		protected static HtmlString RenderRendering(Rendering rendering)
		{
			var stringWriter = new StringWriter();
			PipelineService.Get().RunPipeline("mvc.renderRendering", new RenderRenderingArgs(rendering, stringWriter));
			return new HtmlString(stringWriter.ToString());
		}
	}
}

And then I replaced all usages of


@Html.Sitecore().Rendering("/sitecore/layout/Renderings/MyRendering")

to


@SitecoreHelper.Rendering("/sitecore/layout/Renderings/MyRendering")

If you using this method please double check that the caching settings are being properly set, otherwise use the code above.

That’s it Folks.🙂

Wildcards Module for Sitecore 7+ using Content Search API

Will share the alternative implementation of Wildcards module of Adam Conn’s original idea.

The problem is that when it comes to Sitecore 7 or later this module appears not to be working out of the box due to changed Sitecore Rules Engine. And to be honest, working with rules may be a bit confusing and I found it hard to debug. However there is still a way to fix the original module https://github.com/madoibito/revised-sitecore-wildcard-module-for-sitecore7.1orlater/wiki/How-to-change-wildcard-module-items-for-Sitecore-7.1-or-later-step-by-step for Sitecore 7+, but I needed some more flexibility.
So decided to implement something alternative.

So the task is as before – supporting data-driven URLs via Sitecore Wildcard (*) items.

All source code can be found here: https://github.com/vhil/helpfulcore-wildcards
The packed Sitecore module is in the same repository in its root.

Feature overview:

  • Not using Rules Engine anymore
  • Built in page item resolving and URL generation
  • Separate configuration for Item Resolving using ContentSearch API
  • Separate configuration for item URL generation
  • Single place for configuring the wildcards route
  • Fully configurable, extendable, easy to be changed and debuged.

I am going to play around with my ‘Fortis Demo’ solution and all project-relalted code and items can be found here: https://github.com/vhil/fortis-demo

So lets imagine,  I want to implement a product page in my solution, but will keep all my products in the item bucket outside of the website tree.
I have created a new page type template ‘Product Page’ which contains few fields and made it bucketable:

  • Product ID
  • Content Title
  • Content Image
  • Content Body

And created an item bucket under the shared content folder outside the website tree:

products-bucket

And on the site I want to show my products under /products item and my url for example has to be like this:


http://fortis.demo/products/[product-id]/[product-item-name]

So I created item tree under the website with wildcards in their names


/sitecore/content/Sites/fortis-demo/products/*/*

products-wildcard-item

Ok. Now I will implement a rendering that will list me my products on the product overview page


/sitecore/content/Sites/fortis-demo/products.

products-overview

Currently my rendering generated product detail URLs which contain bucket item paths:


http://fortis.demo/sitecore/content/shared-content/products-repository/2016/02/21/20/03/product-a
http://fortis.demo/sitecore/content/shared-content/products-repository/2016/02/21/20/11/product-b

But I want my urls to match the format mentioned above.
So I install a “Helpfulcore Wildcards Module-1.0.0” module.

All I need to do now is to register and configure a ‘wildcard route’ for my project page. I go to /sitecore/system/Modules/Wildcards/Routes item and create a new ‘Wildcard Route’ item under it.

wildcard-route
‘Wildcard Route’ template has fields for two main sections which reflect the module behavior:

  • Url Generation
  • Item Resolving

Url Generation:

url-generation

  • Wildcard Items – here I am referencing my endpoint wildcard item (in my case /sitecore/content/Sites/fortis-demo/products/*/*). Note that this is a TreelistEx field – this is done for multisite support. In case of multiple sites on your sitecore instance  just add all wildcard items from each site here and the module will resolve the most suitable one while url generation.
  • Url Generation Rules – this is a ‘Name Value List’ field and here we configure which wildcard should be replaces with which value related to the item.

For this field I have implemented a custom item reader which accepts its own syntax. It is actually pretty simple:

  • Prefix your fields with ‘@’. For example: @__Display Name
  • Prefix your properties with ‘@@. For example: @@Name
  • Use ‘.’ delimiter for creating a chain

Examples

  • @@Name
  • @__Display Name
  • @@Paths.@@Path
  • @@Parent.@@Name
  • @Custom Link Field.@@Name
  • @@Template.@@InnerItem.@__Standard values.@@Paths.@@Path

Notes:

  • Property names ARE case sensitive
  • Field names are NOT case sensitive

So in my case I set two values for each wildcard item:


{0, @Product ID}
{1, @@Name}

Which means

  • the wildcard at position [0] will be replaced with ‘Product ID’ field value of the item
  • the wildcard at position [1] will be replaced with ‘Name’ property value of the sitecore Item class.

In order to help to debug this syntax I have created an admin page which you can access by clicking on the ‘Url Generation Rules’ field title. It will lead you to /sitecore/admin/wildcardtokenextractor.aspx?sc_site=website page.

wildcard-tokenextractor

Here you can type the path or ID of testing item and write your query for concrete wildcard replacement. And then when you are sure your query gives correct result, just copy it into the field.

Item resolving:

I am hooking into the presentation layer and not the Item Resolving process by adding the processor into the <mvc.getPageItem> pipeline.


<pipelines>
      <mvc.getPageItem>
        <processor type="Helpfulcore.Wildcards.Pipelines.Response.GetPageItem.GetFromWildcard, Helpfulcore.Wildcards"
                   patch:after="processor[@type='Sitecore.Mvc.Pipelines.Response.GetPageItem.GetFromOldContext, Sitecore.Mvc']" />
      </mvc.getPageItem>
    </pipelines>

The item resolving is being implemented using the content search API and there is few more fields in the ‘Wildcard Route’ template for Item Resolving:

item-resolving

  • Item Search Root Node – specify here the root item of your item repository so the content search looks into items only inside of this item.
  • Item Templates – specify templates that the content search should filter by
  • Item Resolving Rules – and here in the same manner specify field for each wildcard. But now each value should represent the content search index field name. Note that not all wildcards are required to be participating in the item resolving, you can simply skip some of them and leave required ones only.

in my case that will be:


{0, product_id}
{1, _name}

Thats it!

Now if I refresh the product overview page I will see next urls being generated for my product items:

And when I click them I can see all the content taken from the resolved page item.

Configuration

The module installs an include config file /App_Config/Include/Helpfulcore/Helpfulcore.Wildcards.config


<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <settings>
      <setting name="WildcardWrapSearchTermsInEncodedQuotes" value="false" />
      <setting name="WildcardTokenizedString" value=",-w-," />
      <setting name="WildcardProvider.RoutesPath" value="/sitecore/system/modules/wildcards/routes" />
    </settings>
	<wildcardManager defaultProvider="wildcardResolver">
      <providers>
        <add name="wildcardResolver" type="Helpfulcore.Wildcards.WildcardRouteResolver, Helpfulcore.Wildcards" />
      </providers>
    </wildcardManager>
	<wildcardItemResolver defaultProvider="contentSearch">
      <providers>
        <add name="contentSearch" type="Helpfulcore.Wildcards.ItemResolving.ContentSearchWildcardItemResolver, Helpfulcore.Wildcards" />
      </providers>
    </wildcardItemResolver>
    <urlGenerationTokenValueExtractor defaultProvider="itemReader">
      <providers>
        <add name="itemReader" type="Helpfulcore.Wildcards.UrlGeneration.TokenValueExtraction.ItemReaderTokenValueExtractor, Helpfulcore.Wildcards" />
      </providers>
    </urlGenerationTokenValueExtractor>
    <pipelines>
      <mvc.getPageItem>
        <processor type="Helpfulcore.Wildcards.Pipelines.Response.GetPageItem.GetFromWildcard, Helpfulcore.Wildcards"
                   patch:after="processor[@type='Sitecore.Mvc.Pipelines.Response.GetPageItem.GetFromOldContext, Sitecore.Mvc']" />
      </mvc.getPageItem>
    </pipelines>
    <linkManager defaultProvider="sitecore">
      <providers>
        <add name="sitecore">
          <patch:attribute name="type">Helpfulcore.Wildcards.UrlGeneration.WildcardLinkProvider, Helpfulcore.Wildcards</patch:attribute>
        </add>
      </providers>
    </linkManager>
    <events>
      <event name="publish:end">
        <handler type="Helpfulcore.Wildcards.Events.PublishEnd.WildcardsCachePurgeProcessor, Helpfulcore.Wildcards" method="ClearCache" />
      </event>
      <event name="publish:end:remote">
        <handler type="Helpfulcore.Wildcards.Events.PublishEnd.WildcardsCachePurgeProcessor, Helpfulcore.Wildcards" method="ClearCache" />
      </event>
    </events>
  </sitecore>
</configuration>

As you can see I have moved to the configuration pretty much everything. And in every class I implemented I tried to write virtual methods and members only so you can override whatever you want if you need some customization.
Also feel free to fork the repo and suggest a fix or improvement.

Module Contents:

Files:

  • /App_Config/Include/Helpfulcore/Helpfulcore.Wildcards.config
  • /sitecore/admin/WildcardTokenExtractor.aspx
  • /bin/Helpfulcore.Wildcards.dll

Items:

  • /sitecore/templates/Wildcards/Wildcard Route
  • /sitecore/system/Modules/Wildcards/Routes

Hope this will be helpful🙂