This is Chapter 4 of our series about implementing a "Real time catalogue" in Episerver commerce. In this post we dive deeper into the IOC container. If you like start reading from the start, start reading the series here and go to the previous chapter here.
IOC container
An IOC container or DI container if you want is a framework for implementing depencency injection. It manages object creation and it’s life-time, and also injects dependencies to the class. The IoC container creates an object of the specified class and also injects all the dependency objects through a constructor, a property or a method at run time and disposes it at the appropriate time. See TutorialsTeacher for more information.
The IConfigurableModule
as shown below is pretty straight forward, first it configures the container and afterwards Initialize
gets called, as you are used with when writing you own content providers. In the Initialize
method the CatalogContentProvider
gets configurated with the appropriate EntryPointString
, CapabilitiesString
and most important the ProviderKey
get’s assigned.
It’s important that the IConfigurableModule
gets executed after the Episerver Commerce initialization module. This is done by decorating the class with the correct ModuleDependency
attribute.
For more information about how DI works in Episerver you can read the article on World.
[ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))]
[InitializableModule]
public class ContentProviderInitialization : IConfigurableModule
{
public void Initialize(InitializationEngine context)
{
var providerManager = context.Locate.Advanced.GetInstance();
var catalogConnectContentProvider = context.Locate.Advanced.GetInstance();
var catalogConnectContentProviderValues = new NameValueCollection
{
{
ContentProviderElement.EntryPointString, "0"
},
{
ContentProviderElement.CapabilitiesString, "Search,MultiLanguage"
}
};
catalogConnectContentProvider.Initialize($"{Providers.CatalogConnectProviderPrefix}-{ConnectionSettings.ExternalCatalogRootNodeId}", catalogConnectContentProviderValues);
providerManager.ProviderMap.AddProvider(catalogConnectContentProvider);
}
public void Uninitialize(InitializationEngine context)
{
}
public void ConfigureContainer(ServiceConfigurationContext context)
{
context.StructureMap().Configure(c =>
{
c.For().Use(); // Overwrite the usage of the catalog content provider with our own catalog content provider, this one is used to hook into a specific node to show the catalog below.
c.For().Use().Singleton(); // The identity service parses identifiers to EpiServer content references and vice versa.
c.For().Use(); // Custom reference converter for the types.
c.For().Use(); // Use our own catalog content structure provider, with backwards compatibility.
c.For().Use().Singleton(); // Factory used to create category nodes.
c.For().Use().Singleton(); // Factory used to create products.
c.For().Use().Singleton(); // Factory used to create variants.
c.For().Use(s => new CatalogConnectClient(ConnectionSettings.BaseFolder)).Singleton();
c.For().Use(p => new CatalogConnectContentProvider(
p.GetInstance(),
p.GetInstance(),
p.GetInstance(),
p.GetInstance(),
p.GetInstance(),
p.GetInstance(),
p.GetInstance(),
p.GetInstance())).Singleton();
});
var services = context.Services;
services.Intercept((locator, defaultImplementation) => new CatalogConnectRelationRepository(
defaultImplementation,
locator.GetInstance(),
locator.GetInstance(),
locator.GetInstance())); // Service that determines the relations between nodes and it's children.
services.Intercept((locator, defaultImplementation) => new CatalogConnectInventoryService(
defaultImplementation,
locator.GetInstance(),
locator.GetInstance())); // Intercepted inventory service, done to be able to provide backwards compatibility.
services.Intercept((locator, defaultImplementation) => new CatalogConnectPriceService(
defaultImplementation,
locator.GetInstance(),
locator.GetInstance())); // Intercepted price service, done to be able to provide backwards compatibility.
}
}
Verdict
We have tried to be as complete in the simpelest way possible to explain this use case. You have also seen that’s not an easy 1,2,3. With that in mind you have to think twice when going down this road. There are a lot of other practices for optimizing a catalog experience. With this series of blogposts we hopefully can contribute to a discussion for the whole idea of Custom Catalog Providers. Technically it is possible, but practically it is definitely not for everyone. We do see the need in certain enterprise implementations.
One last thing; A very important thing to dive into when implementing a custom content provider and especially in the case of a catalog content provider is caching. A good caching strategy can make the difference of a succesfull implementation.
If you like to start playing around with this, or consider implementing this we are well willing to share a basic code base (based on the Episerver Foundation). The only thing we ask you to do when sharing this code is to write a blog post yourself about this subject and share us your findings, thoughts and considerations about this subject. By this we try to give this subject a little more attention and open up the conversation.