November Happy Hour will be moved to Thursday December 5th.

Quan Mai
Jun 5, 2018
  3953
(7 votes)

A breaking change regarding IShippingPlugin/IShippingGateway in Commerce 12

As you might already know, we reserve the major versions for breaking changes - when you upgrade to a major version, expect to have to change your code to make it compile and work.

Our latest major version is Commerce 12, which was released almost two months ago, and the full list of breaking changes can be seen here https://world.episerver.com/documentation/upgrading/episerver-commerce/commerce-12/breaking-changes-commerce-12/

However one breaking change is easier to miss than the other, that's why I think it should get more attention.

If you only fix your code to build, then when you run it, you will likely run into this exception

<Your super cool shipping gateway> does not implement IShippingPlugin nor IShippingGateway. 

Why is that and how to fix it?

In a Commerce implementation you might have multiple gateways, for example free shipping for customers who can wait and express shipping for ones who can't. For each and every shipment you would need to get the gateway assigned to it and use it to calculate the shipping rate. Previously, the instance of the shipping gateway is created by Activator, and it requires the implementation to have a constructor which takes an IMarket parameter. That is quite obsecure and hard to know before hand. Also if you are a seasoned Episerver developer, you might be like "Activator, seriously?". Well, those code are probably one of the oldest parts in our repository, so it's less "modern".

In Commerce 12 we changed the way to get the implementation of a shipping gateway (and a minor change to the signature of the interfaces themselves. Now you need to pass an IMarket to the method, not to create a constructor which takes one. In fact, you must remove that constructor because there is no default implementation registered for IMarket). And you might have guess it - via dependency injection. We now rely on the Inversion of control framework to give us an implementation of the shipping gateway being used. While that gives us much more flexibility, it also comes at a cost: because the shipping gateways are implementations of IShippingPlugin or IShippingGateway, or both, the IoC framework can't just detect it, unless you register specifically.

So the only extra work you need is to add this attribute to your implementation

    [ServiceConfiguration(ServiceType = typeof(IShippingPlugin))]

or

    [ServiceConfiguration(ServiceType = typeof(IShippingGateway))]

or both.

And that's it. Your shipping gateways are now ready!

Jun 05, 2018

Comments

Maris Krivtezs
Maris Krivtezs Jun 14, 2018 02:52 PM

Registering service with ServiceConfiguration is a bad practice. Episerver should not promote its usage.

I wrote a blog post about it: http://marisks.net/2018/01/31/serviceconfiguration-attribute-considered-harmful/

Instead, register services in your DI container's registration point - configurable module, DI registry, pure DI composition root etc.

Quan Mai
Quan Mai Jun 14, 2018 03:03 PM

I don't really consider ServiceConfiguration is a bad practice. Yes having unexpected lifecycle is bad, but that is not a problem with ServiceConfiguration. https://vimvq1987.com/watch-out-for-singletons/

The upside of ServiceConfiguration is that you can quickly check what type your class is registered for, and with which lifecycle. IConfigurableModule is more useful (or even a must) for complicated registration like interceptor, or if you want to override a default implementation. 

Jun 25, 2018 02:52 PM

Personally I also do not like ServiceConfiguration, I like to have all of the configuration in an Initialization module and separated in to classes relating to the different areas of the project so I can see all of the DI across the project easily without having to go in to the concrete classes or search for usages of ServiceConfiguration. I also agree with the blog post of Māris's about not liking mixing the DI code inside the class code, it just feels dirty to me.

Also as far as being about to see what the type that class is registered easuky if a class is implementing an interface or class it will be in the inheritance defininition of the class file so that's usually pretty easy.

I guess it's preference but I thought I'd throw in my 2 cents

Sujit Senapati
Sujit Senapati Sep 29, 2018 04:44 PM

Hi,

The solution to inject the type during DI registry also works just fine. I agree I do not prefer ServiceConfiguration either, but registering through structuremap just does the exact thing what is required.

public class ShippingImplementationBootstrapper : Registry
    {
        public ShippingImplementationBootstrapper()
        {
            For<IShippingPlugin>().Use<CustomRateShippingPlugin>();
            For<IShippingGateway>().Use<CustomRateShippingPlugin>();
        }
    }

Feb 5, 2020 06:54 PM

If you have multiple Shipping Gateways you will need use IConfigurableModule. 

.For<IShippingGateway>().Add<CustomShippingGateway1>().Named("CustomShippingGateway1"));

.For<IShippingGateway>().Add<CustomShippingGateway2>().Named("CustomShippingGateway2"));

ServiceConfiguration didn't seem to be smart enough to handle that scenario, it simply registers the last instance it finds. Even if you start with one instance, it's not difficult to fall into this trap. I'd recommend going with IConfigurableModule from the start to save some head scratching when you enevitably do add aditonal instances.

Please login to comment.
Latest blogs
Optimizely SaaS CMS + Coveo Search Page

Short on time but need a listing feature with filters, pagination, and sorting? Create a fully functional Coveo-powered search page driven by data...

Damian Smutek | Nov 21, 2024 | Syndicated blog

Optimizely SaaS CMS DAM Picker (Interim)

Simplify your Optimizely SaaS CMS workflow with the Interim DAM Picker Chrome extension. Seamlessly integrate your DAM system, streamlining asset...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Optimizely CMS Roadmap

Explore Optimizely CMS's latest roadmap, packed with developer-focused updates. From SaaS speed to Visual Builder enhancements, developer tooling...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Set Default Culture in Optimizely CMS 12

Take control over culture-specific operations like date and time formatting.

Tomas Hensrud Gulla | Nov 15, 2024 | Syndicated blog

I'm running Optimizely CMS on .NET 9!

It works 🎉

Tomas Hensrud Gulla | Nov 12, 2024 | Syndicated blog

Recraft's image generation with AI-Assistant for Optimizely

Recraft V3 model is outperforming all other models in the image generation space and we are happy to share: Recraft's new model is now available fo...

Luc Gosso (MVP) | Nov 8, 2024 | Syndicated blog