Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Remko 104 posts 257 karma points
    Mar 27, 2020 @ 15:55
    Remko
    0

    How to get custom service injected into custom component?

    Hi,

    At the moment I am rewriting a lot of code.

    I created a SiteService, like in all of the examples on the Umbraco site. Like this:

     public class SiteService : ISiteService
    {
        private readonly IPublishedContentQuery _contentQuery;
    
        public SiteService(IPublishedContentQuery contentQuery)
        {
            _contentQuery = contentQuery;
        }
    }
    

    It is registered this way:

        [RuntimeLevel(MinLevel = RuntimeLevel.Run)]
    public class UmbracoCustomComposer : IUserComposer 
    {
        public void Compose(Composition composition)
        {
            composition.Register<ISiteService, SiteService>(Lifetime.Request);
        }
    }
    

    I can easily inject this into my Surface controllers, this works fine just by adding ISiteService in constructor of controller.

    By now my problem.. I've also created a component:

    public class ShoppingApplicationComposer : IUserComposer
    {
        public void Compose(Composition composition)
        {
            composition.Components().Append<ShoppingApplicationComponent>();  
        }
    }
    
    public class ShoppingApplicationComponent : IComponent
    {
        private readonly ISiteService _siteService;
    
        public ShoppingApplicationComponent(IContentService contentService, IUmbracoContextFactory context, ISiteService siteService)
        {
            _siteService = siteService;
        }
        public void Terminate()
        {
        }
    
        public void Initialize()
        {
        }
    }
    

    I can't get this to work. As soon as I add ISiteService to the constructor it leads to a BootFailed Exception:enter image description here

    What should I do to make it possible to inject my custom service into my custom component? Can anyone please help me with this one?

    Thanks in advance!

    Remko

  • Chris Norwood 101 posts 547 karma points
    Mar 27, 2020 @ 16:30
    Chris Norwood
    0

    Have you tried putting both of the compositions in the same function to make sure they're done in the right order?

    E.g.

        [RuntimeLevel(MinLevel = RuntimeLevel.Run)]
        public class UmbracoCustomComposer : IUserComposer 
        {
            public void Compose(Composition composition)
            {
                composition.Register<ISiteService, SiteService>(Lifetime.Request);            
    composition.Components().Append<ShoppingApplicationComponent>();  
            }
        }
    

    Just to make sure that they're registered in the correct order?

  • Alan Mitchell 54 posts 270 karma points c-trib
    Apr 22, 2020 @ 16:12
    Alan Mitchell
    0

    I came across this thread whilst battling a similar issue. Specifically, the upgrade to 8.6.1 (from 8.5.5) caused a boot error due to compositions.

    For future Googlers:

    Umbraco.Core.Exceptions.BootFailedException: Boot failed. ---> System.InvalidOperationException: Unable to resolve type: Umbraco.Core.Composing.ComponentCollection, service name:
    ---> System.InvalidOperationException: Unable to resolve type: MyCustomComponent, service name:
    ---> System.InvalidOperationException: Unresolved dependency [Target Type: MyCustomComponent], [Parameter: myCustomService( ImyCustomService)], [Requested dependency: ServiceType:ImyCustomService, ServiceName:] at LightInject.ServiceContainer.GetEmitMethodForDependency(Dependency dependency)

    My error was that one composer class could not resolve the type of another custom class (service). This thread helped me realise that during composition it is necessary to boot things in the right order so that dependent types are added in the right sequence. I must have been lucky before that!

    Adding a [ComposeAfter] attribute to reference the dependent service was enough to fix the issue. There is some pretty decent documentation here: https://our.umbraco.com/documentation/Implementation/Composing/#attributes

  • Remko 104 posts 257 karma points
    Mar 27, 2020 @ 18:35
    Remko
    0

    Yes, when I simply add the SiteService in same Composer, before adding ShoppingApplicationComponent, I get the same Exception.

  • Chris Norwood 101 posts 547 karma points
    Mar 27, 2020 @ 19:17
    Chris Norwood
    0

    Come to think of it I actually have a similar structure set up for a spell check index in Examine, which looks like this:

    public class SpellCheckIndexComponent : IComponent
        {
            private readonly IExamineManager _examineManager;
            private readonly SpellCheckIndexCreator _SpellCheckIndexCreator;
    
            public SpellCheckIndexComponent(IExamineManager examineManager, SpellCheckIndexCreator spellCheckIndexCreator)
            {
                _examineManager = examineManager;
                _SpellCheckIndexCreator = spellCheckIndexCreator;
            }
    
            public void Initialize()
            {
                foreach (var index in _SpellCheckIndexCreator.Create())
                {
                    _examineManager.AddIndex(index);
                }
            }
    
    
            public void Terminate() { }
        }
    

    And the SpellCheckIndexCreator:

    public class SpellCheckIndexCreator: LuceneIndexCreator
    {
        private readonly IProfilingLogger _profilingLogger;
        private readonly ILocalizationService _localizationService;
        private readonly IPublicAccessService _publicAccessService;
    
        // Since Umbraco 8 has dependency injection out of the box, we can use it to inject
        // the different services that we need.
        public SpellCheckIndexCreator(IProfilingLogger profilingLogger,
            ILocalizationService localizationService,
            IPublicAccessService publicAccessService)
        {
            _profilingLogger = profilingLogger;
            _localizationService = localizationService;
            _publicAccessService = publicAccessService;
        }
    
        //is this where we actually create the index?
        //how do we populate it?
        public override IEnumerable<IIndex> Create()
        {
            var index = new UmbracoContentIndex("SpellCheckIndex", 
                CreateFileSystemLuceneDirectory("SpellCheckIndex"),
                new FieldDefinitionCollection(new FieldDefinition("word", FieldDefinitionTypes.FullText)),
                new SpellCheckAnalyzer(Lucene.Net.Util.Version.LUCENE_30),
                _profilingLogger,
                _localizationService,
                // We can use the ContentValueSetValidator to set up rules for the content we
                // want to have indexed. 
                new ContentValueSetValidator(true, true, _publicAccessService));
    
            return new[] { index };
        }
    
    
    }
    

    They're registered like this:

    [RuntimeLevel(MinLevel =RuntimeLevel.Run)]
        public class RegisterIndexesComposer : IUserComposer
        {
            public void Compose(Composition composition)
            {
                composition.Components().Append<SpellCheckIndexComponent>();
                composition.Components().Append<ExamineEventComponent>();
                composition.RegisterUnique<SpellCheckIndexValueSetBuilder>();
                composition.Register<SpellCheckIndexPopulator>(Lifetime.Singleton);
                composition.RegisterUnique<SpellCheckIndexCreator>();
            }
        }
    

    The only difference I can see is that I'm directly registering the class rather than an implementation of an Interface - could you try that? :)

  • Marc Goodson 1628 posts 10771 karma points MVP 6x c-trib
    Mar 28, 2020 @ 00:29
    Marc Goodson
    100

    Hi Remko

    The problem is not your SiteService, it is the injecting of IPublishedContentQuery into your service, and then using the Service in a location where an UmbracoContext is not guaranteed to exist, eg in a component.

    There is some really detailed information on this page in the docs:

    https://our.umbraco.com/Documentation/Implementation/Services/#implementing-the-service

    where you can access the cache using the UmbracoContextFactory... and this will avoid your boot errors.

    regards

    Marc

  • Comment author was deleted

    Mar 28, 2020 @ 11:57

    If you need an example check out https://github.com/skttl/Our.Umbraco.FullTextSearch

  • Remko 104 posts 257 karma points
    Apr 06, 2020 @ 07:10
    Remko
    0

    Thank you all. This really helped me. Ran into using IPublishedContentQuery by examples on our.umbraco. But didn't realize it couldn't be used in constructor of my own service. Now it's working all like I intended to, thanks.

Please Sign in or register to post replies

Write your reply to:

Draft