Tuesday, June 18, 2013

How to use services in a NopCommerce Plugin that it doesn’t use by default

Suppose you want to override some behavior in a NopCommerce service via a plugin. You would start by subclassing the service that has the behavior you want to override. But what if your new code requires access to something that the existing service doesn’t know about?

The answer turns out to be pretty simple: just add it to your constructor, and the dependency resolver will figure it out for you. (You don’t need to worry about it.)

Here’s an example. I want to override the PictureService. So I started with this:

    public class MyPictureService : PictureService
    {
        // constructor
        public MyPictureService(
            IRepository<Picture> pictureRepository, 
            IRepository<ProductPicture> productPictureRepository,
            ISettingService settingService, 
            IWebHelper webHelper, 
            ILogger logger, 
            IEventPublisher eventPublisher, 
            MediaSettings mediaSettings,
            : base(pictureRepository, productPictureRepository, settingService, 
                webHelper, logger, eventPublisher, mediaSettings)
        {
        }

        // my overrides
    }

So you can see that we get a lot of stuff by default. If we want to use any of those services, we need to create class variables for them (the base class marks them private), like so:

    public class MyPictureService : PictureService
    {
        protected readonly ILoggerService Logger;

        // constructor
        public MyPictureService(
            IRepository<Picture> pictureRepository, 
            IRepository<ProductPicture> productPictureRepository,
            ISettingService settingService, 
            IWebHelper webHelper, 
            ILogger logger, 
            IEventPublisher eventPublisher, 
            MediaSettings mediaSettings,
            : base(pictureRepository, productPictureRepository, settingService, 
                webHelper, logger, eventPublisher, mediaSettings)
        {
            Logger = logger;
        }

        // my overrides
    }

And if I want to add a service or repo that’s not there already? Just add it:

    public class MyPictureService : PictureService
    {
        protected readonly ILoggerService Logger;
        protected readonly ISpecificationAttributeService SpecificationAttributeService;

        // constructor
        public MyPictureService(
            IRepository<Picture> pictureRepository, 
            IRepository<ProductPicture> productPictureRepository,
            ISettingService settingService, 
            IWebHelper webHelper, 
            ILogger logger, 
            IEventPublisher eventPublisher, 
            MediaSettings mediaSettings,
            // just add it to the constructor!
            ISpecificationAttributeService specificationAttributeService)
            : base(pictureRepository, productPictureRepository, settingService, 
                webHelper, logger, eventPublisher, mediaSettings)
        {
            Logger = logger;

            // and use it
            SpecificationAttributeService = specificationAttributeService;
        }

        // my overrides
    }

Have fun!

Friday, June 14, 2013

Chef: Cannot find a resource for powershell on windows version 6.1.7600 (solved)

While working on some deployment stuff I ran into this error:

Cannot find a resource for powershell on windows version 6.1.7600

The solution turned out to be pretty obvious, and easy: include the powershell cookbook. For some reason I assumed it came in as part of the windows cookbook, but no. So just include it in your metadata.rb file like so:

name             '...'
maintainer       '...'
maintainer_email '...'
description      '...'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version          '0.1.0'
depends          'windows'
depends          'powershell'

Of course, if you’re using Chef Solo, you’ll want to download your dependent cookbooks, too.