Documentation

Ucommerce includes full API reference documentation and lots of helpful articles to help you build your e-commerce site as effortlessly as possible.

Topics Payment Providers
v7.18

Register a Custom Component

This article will explain how you can register your own implementations of various interfaces to change the behavior of the platform. You most likely ended up here after reading another article on a common extension point. This article is for you if you've already made some code you want to register, or you are interested in learning how extension in Ucommerce works in a basic way.

The behavior of the platform can be changed in any way you'd like. This means that if you are not happy with how a piece of business logic works - for example pricing, tax or similar, you can change the behavior of the platform so it behaves the way you want. This is possible throughout the entire platform. And to make things even easier, the recipe is more or less always the same.

The recipe starts with an IOC container (powered by Castle Windsor) where all business logic is encapsulated in a .NET type and registered via configuration files. We refer to this concept as components, and should be considered building blocks to the platform. So you need to think of this concept as you changing the behavior via code, rather than re-compiling the platform. An example of this could for example be how tax is calculated.

Once you have written your desired change to the platform, it is time to register it. Your code ended up in a dll file output in the bin folder, and will be encapsulated in a .NET type which has 3 pieces of information:

  • Assembly (dll file)
  • Namespace
  • Type name

So consider this dummy extension really quick to get an idea. In this

    using Ucommerce;
    using Ucommerce.EntitiesV2;
    
    namespace UcommerceCodeSamples.ExtendingUcommerce
    {
        public class MyTaxService : Ucommerce.Catalog.ITaxService
        {
            public Money CalculateTax(Product product, PriceGroup priceGroup, Money unitPrice)
            {
                return new Money(0, "EUR");
            }
    
            public Money CalculateTax(PriceGroup priceGroup, Money amount)
            {
                return new Money(0, "EUR");
    
            }
    
            public decimal CalculateTax(decimal amount, decimal taxRate)
            {
                return 0;
            }
        }
    }

In the example above we have:

  • Namespace is UcommerceCodeSamples.ExtendingUcommerce
  • Type name (class name) is MyTaxService
  • Assembly we can't see from the example above but typically the first section of your namespace unless you explic changed it when you created the class library so in this case UcommerceCodeSamples

This makes up the actual type we want to register, and referenced in .NET it will look like this:

Namespace.Typename, Assemblyname

which in our example above becomes

UcommerceCodeSamples.ExtendingUcommerce.MyTaxService, UcommerceCodeSamples

Component registration 101

When you register a component you do it in an XML file placed under the apps folder in Ucommerce. If you haven't created one before, take a look at the structure under Ucommerce/Apps. Here you'll find lots of examples of foldername\configuration\configuration.config

Create your own folder with your own configuration.config file placed in it. Ucommerce will load them up recursively in alphabetic order. The order of the files are important, but more of that later.

Once you have created one, it should be empty looking like this:

    
        <configuration>
          <components>
    
          </components>
        </configuration>
    

We are now ready to create an actual component.

To do so, You'll need to specify 3 things:

  • An Id of your component
  • The service that your component exposes - usually an interface, but can also be a class
  • The specific type of the implementation of your component - always a class like the example above

When registering a component, use the following format:

    
    <component
    	id="Id of your component"
    	service="interface you are implementing"
    	type="the type you created" />
    

This would end up with the following component for our example above. You need to put that in your configuration file under the components tag.

    
    <component
    	id="TaxService"
    	service="Ucommerce.Catalog.ITaxService, Ucommerce"
    	type="UcommerceCodeSamples.ExtendingUcommerce.MyTaxService, UcommerceCodeSamples" />
    

The final content of your config file looks like this:

    
        <configuration>
          <components>
            <component
                id="TaxService"
                service="Ucommerce.Catalog.ITaxService, Ucommerce"
                type="UcommerceCodeSamples.ExtendingUcommerce.MyTaxService, UcommerceCodeSamples" />
          </components>
        </configuration>
    

Once you have done this, restart the application and your type is now active in the IOC container. But we are not done understanding this just yet.

Overriding a Default Component

When you register a component like we just did, we typically change the behavior of the platform which means that there's also a default implementation in place somewhere that we need to replace. For the ITaxService implementation it happens to look like this:

    
        <component
                id="TaxService"
                service="Ucommerce.Catalog.ITaxService, Ucommerce"
                type="Ucommerce.Catalog.TaxService, Ucommerce"/>
    

All we have to do to replace this component is reuse the id of the component - in this case TaxService. There can only be one component with the same Id which means it is unique. If the IOC container stumble upon a component with the same ID, the last component wins. So in this case the order of which the configuration files are loaded is very important.

Notice that the ID is the same as the default registration, but the type now points to UcommerceCodeSamples.ExtendingUcommerce.MyTaxService, UcommerceCodeSamples and thus we have changed how tax is calculated in the platform.

This effectively redirects all calls to your implementation and can be done for any components in Ucommerce that ships out of the box.

Please note that if you do not reuse the same id, the two implementations of ITaxService will live side by side, but your component will never be picked up, as the IOC container picks the first implementation it finds, which will always be the OOTB components.

Constructor Injected Components

Components can be composed using other components. What this means is that you can create highly focused components, which do just one thing and later on "click" them together to solve a task together.

Constructor injection is a way to achieve this without the components knowing that they're operating in an injected environment.

Consider a pipeline task: The task is part of the overall framework of Ucommerce and as such is injected into the pipeline executing it.

The pipeline task might need other components to complete its job; these can be injected just like the pipeline task itself is. You might need access to other components shipped with Ucommerce such as the ITaxService discussed above or entirely new ones created just for the occasion:

    public class MyPipelineTask : IPipelineTask<PurchaseOrder>
    {
    	private readonly ITaxService _taxService;
    	private readonly IMyNewComponent _myNewComponent;
    
    	public MyPipelineTask(
    		ITaxService taxService, 
    		IMyNewComponent myNewComponent)
    	{
    		// priceService is provided automatically to MyPipelineTask
    		// because it's registered with Ucommerce
    		_taxService = taxService;
    		
    		// Works for entirely new components too
    		_myNewComponent = myNewComponent;
    	}
    
    	public PipelineExecutionResult Execute(PurchaseOrder subject)
    	{
    		// Do some price calculation
    		return PipelineExecutionResult.Success;
    	}
    }
    
    

As you can see from the example MyPipelineTaskreceives both the existing ITaxService and the completely new component IMyNewComponent and can use the instances to perform its job.

You can read more about Constructor Injection, Property Injection, and more advanced injection in this article

Getting and Using Registered Components

Typically when you are writing your components you just have to constructor inject your components into your code. But this only counts for classes that you already inject. If you are working in Web API or in your MNVC controllers or similar, you have to ask the IOC to give it to you.

When you need to use any given service in Ucommerce you can resolve them from ObjectFactory - either by Id for an exact implementation of a service or by service/interface for any given implementation.

You can also get a list of all implementations for a specific service/interface.

Fetching services is possible by using the static methods on ObjectFactory. To use it, you'll need a reference to UCommerce.Infrastructure.dll in your solution.

Ucommerce.Infrastructure.ObjectFactory

Description

Object factory class.

Methods


AddChildContainer

  • Description
    Adds a child container to the current Castle Windsor container. Components registered in the child container will override the ones from the parent.
  • Arguments
    • Castle.Windsor.IWindsorContainer childContainer
  • Return type Void

Resolve

  • Arguments
    • This method is called without any arguments
  • Return type Ucommerce.Infrastructure.T

Resolve

  • Arguments
    • Type type
  • Return type Object

GetServiceIdsFor

  • Arguments
    • This method is called without any arguments
  • Return type IEnumerable<string>

RegisteredServicesFor

  • Description
    Gets ids for the registered services.
  • Arguments
    • Type serviceType
  • Return type IEnumerable<string>

GetRegisteredComponentsFor

  • Description
    Gets full information for the registered components of a single service.
  • Arguments
    • Type serviceType
  • Return type List<Castle.Core.ComponentModel>

Resolve

  • Arguments
    • string id
  • Return type Ucommerce.Infrastructure.T

Resolve

  • Arguments
    • Type type
    • string id
  • Return type Object

ResolveAll

  • Arguments
    • This method is called without any arguments
  • Return type IList<Ucommerce.Infrastructure.T>

ResolveAll

  • Arguments
    • Type type
  • Return type IList<Object>

Instance

  • Return type Ucommerce.Infrastructure.ObjectFactory

Quick Note on Pipelines

If you are looking to modify a pipeline component, please refer to the "Configure the Pipeline" section in Create Pipeline Task article.