Reinoud van Dalen

February 16, 2016

Auto generated Glass Repositories and ValueProvider

I’ve been thinking this library is deserving a blog post on its own for a while now. I’m talking about the BoC.Persistence.SitecoreGlass library made by my colleague Chris van de Steeg. There is a lot more to talk about than what I will cover, especially since this library is part of a larger BoC collection, but I can assure you it’s worth getting to know.

A short demonstration

First let’s cut to the chase and show the result of using this framework. Let’s imagine you have to build a simple news section. You would probably need at least a few templates and components. This is what the controller could look like:

using System.Linq;
using System.Web.Mvc;
using BoC.Persistence;
using PersistenceGlassDemo.Models.Components;
using PersistenceGlassDemo.Models.Pages;

namespace PersistenceGlassDemo.Controllers
{
    public class NewsController : Controller
    {
        private readonly IRepository<NewsPage> _newsRepository;

        public NewsController(IRepository<NewsPage> newsRepository)
        {
            _newsRepository = newsRepository;
        }

        public ActionResult Index(NewsList datasource, int currentPage = 1)
        {
            var newsItems = _newsRepository.Query()
                                           .Where(news => news.ParentIds.Contains(datasource.NewsRootId))
                                           .OrderByDescending(news => news.PublicationDate) //If you uncomment the NewsRepositories class then you can comment out or remove this line
                                           .Skip(currentPage - 1)
                                           .Take(datasource.PageSize)
                                           .ToList();

            return View(newsItems);
        }

        public ActionResult Detail(NewsPage contextItem)
        {
            return View(contextItem);
        }
    }
}

Omg the abstractions!

Yes, have you noticed? The controller knows nothing about Sitecore. If you take a look at the usings you can see that there is no reference to Sitecore at all.

Now there are a few questions you might have here:

Where does IRepository come from?

The BoC.Persistence.SitecoreGlass library will, on application start, generate a SitecoreRepository for every class that implements IBaseEntity in your assemblies. Then it registers it in your DI container so you can request it anywhere you want. All I had to do was create a News class and let it inherit from SitecoreItem (available in the library). SitecoreItem implements IBaseEntity, therefore a Repository was generated for me.

Can I have my own IRepository implementation?

If you create your own IRepository implementation then that implementation will automatically get registered and no repository will be generated. In the demo project I added an NewsRepository implementation which will sort by publication date (descending) by default when calling the Query method. You can uncomment that implementation and comment out the orderby in the controller, the result will be the same.

namespace PersistenceGlassDemo.Repositories
{
	/// <summary>
	/// My own implementation of IRepository which will prevent a generated repository getting registered for NewsPage.
	/// Uncomment to start using this repo. It removes the need for sorting on publication date in the NewsController.
	/// </summary>
	public class NewsRepository : SitecoreRepository<NewsPage>, IRepository<NewsPage>
	{
		private readonly IProviderSearchContextProvider _providerSearchContextProvider;
		private readonly IDatabaseProvider _databaseProvider;

		public NewsRepository(IDatabaseProvider dbProvider, ISitecoreServiceProvider sitecoreServiceProvider, IProviderSearchContextProvider searchContextProvider, ILogger logger) : base(dbProvider, sitecoreServiceProvider, searchContextProvider, logger)
		{
			_databaseProvider = dbProvider;
			_providerSearchContextProvider = searchContextProvider;
		}

		public IQueryable<NewsPage> Query()
		{
			using (Profiler.StartContext("NewsRepository.Query()"))
			{
				var query = _providerSearchContextProvider.GetProviderSearchContext()
									  .GetQueryable<NewsPage>(new CultureExecutionContext(GetLanguage(_databaseProvider).CultureInfo));
				query = AddStandardQueries(query);
				return AddStandardSorting(query);
			}
		}

		private IQueryable<NewsPage> AddStandardSorting(IQueryable<NewsPage> query)
		{
			return query.OrderByDescending(news => news.PublicationDate);
		}
	}
}

What does the Query method do?

I’m glad you asked. The Query method uses Sitecore ContentSearch to return an IQueryable. It will try to decorate the query with a baseTemplateId check and also language, but that only works if you have them as property on your GlassType class. Then I add a where expression plus paging and that will be translated to a Lucene query. The result, obviously, is a list of News type items.

What are these datasource and contextItem parameters?

Another great question. Let me tell you: the BoC.Sitecore.Mvc library registers the SitecoreValueProvider at application start. This implementation will try to provide a value if the parameter’s name is either contextItem, renderingItem, pageContextItem or datasource. It then eventually uses IRepository.Get (remember these are generated at application start) to set the value.

So this valueprovider will go through the hassle of getting the correct Item and creating a Type for you. Just remember the naming convention, it will make your life so much easier. There is another ValueProvider for handeling rendering parameters. So if you have a Glass Type parameter named ‘renderingParameters’ then this ValueProvider will automatically create the type for you.

One more thing, how does it know my DI container?

In short: the BoC libarary also provides an abstract interface for using a DI container. The only thing you need to do is install an implementation. Currently SimpleInjector, Unity, Ninject and DryIoC are available: https://www.nuget.org/packages?q=BoC.InversionOfControl

It is not hard to create an implementation, should you prefer another DI framework. This way none of your applications are dependent on a specific DI container. You want another? That’s cool, just swap it. It’s like injecting a Dependency Injection Framework ;-)

Conclusion, got any more questions?

I think this is a great way to develop Sitecore applications. It’s easy, strongly typed, delivers clean and unit-testable code and a unified way to access Sitecore data. It might take a little bit of time to get used to, or a bit more if you want to know what’s happening under the hood, but once you do get used to…

Go on, give it a try! If you run into any problems you can let me or Chris know, always happy to help and the project is open source. Though it’s also great to hear something if you do not run into any problems.

I have a Git repo with the News demo here: https://github.com/RvanDalen/PersistenceGlassDemo
and here's the BoC source: https://github.com/csteeg/BoC

TAGS: sitecore glass boc