Copied to clipboard

Flag this post as spam?

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


  • Francis 23 posts 123 karma points
    Jun 14, 2022 @ 18:22
    Francis
    0

    IComponent Initialize() Not Working as Expected

    Hello,

    I'm wondering if you can help me out. I've setup an IComponent that does some simple tasks on initialize. In this example, I'm simply adding pre-values on a dropdown datatype:

    public class ContentNodes : IComponent
    {
        private readonly IContentService _contentService;
        private readonly IDataTypeService _dataTypeService;
        private readonly IUmbracoContextFactory _umbracoContextFactory;
        public ContentNodes(IContentService contentService, 
            IDataTypeService dataTypeService, 
            IUmbracoContextFactory umbracoContextFactory)
        {
            _contentService = contentService;
            _dataTypeService = dataTypeService;
            _umbracoContextFactory = umbracoContextFactory;
        }
    
        public void Initialize()
        {
    
            //populate dropdown
            var sampList = new List<ValueListConfiguration.ValueListItem>();
            sampList.Add(new ValueListConfiguration.ValueListItem
            {
                Id = 1,
                Value = "TEST VAL ONE"
            });
            sampList.Add(new ValueListConfiguration.ValueListItem
            {
                Id = 2,
                Value = "TEST VAL TWO"
            });
    
            var dropDownTest = _dataTypeService.GetDataType(1515);
            ((ValueListConfiguration)dropDownTest.Configuration).Items.AddRange(sampList);
            _dataTypeService.Save(dropDownTest);
    
        }
    
        public void Terminate()
        {
    
        }
    
    }
    

    This gets fired but nothing is happing. Meaning, the test values doesn't get added on my dropdown.

    What's strange is that I have another IComponent that extends Content Service Publish and this code works over there:

        public void Initialize()
        {
            ContentService.Published += ContentService_Published;
        }
    
        private void ContentService_Published(IContentService sender, ContentPublishedEventArgs contentPublishingEventArgs)
        {
    
            //populate dropdown
            var sampList = new List<ValueListConfiguration.ValueListItem>();
            sampList.Add(new ValueListConfiguration.ValueListItem
            {
                Id = 1,
                Value = "TEST VAL ONE"
            });
            sampList.Add(new ValueListConfiguration.ValueListItem
            {
                Id = 2,
                Value = "TEST VAL TWO"
            });
    
            var dropDownTest = _dataTypeService.GetDataType(1515);
            ((ValueListConfiguration)dropDownTest.Configuration).Items.AddRange(sampList);
            _dataTypeService.Save(dropDownTest);
    

    It works on my ServerVariable.Parsing IComponent too:

        public void Initialize()
        {
            ServerVariablesParser.Parsing += Variables_Parsing;
        }
    
        private void Variables_Parsing(IContentService sender, ContentPublishedEventArgs contentPublishingEventArgs)
        {
    
            //populate dropdown
            var sampList = new List<ValueListConfiguration.ValueListItem>();
            sampList.Add(new ValueListConfiguration.ValueListItem
            {
                Id = 1,
                Value = "TEST VAL ONE"
            });
            sampList.Add(new ValueListConfiguration.ValueListItem
            {
                Id = 2,
                Value = "TEST VAL TWO"
            });
    
            var dropDownTest = _dataTypeService.GetDataType(1515);
            ((ValueListConfiguration)dropDownTest.Configuration).Items.AddRange(sampList);
            _dataTypeService.Save(dropDownTest);
    

    So I'm not sure what I'm missing here. I cannot map this task to a service because I just need the pre-values to be populated on startup. I'm not sure if there is a service that does just that, load.

    I wonder if you can help.

    Thanks in advance

    Francis

  • Ronald Barendse 39 posts 218 karma points hq c-trib
    Jun 23, 2022 @ 07:32
    Ronald Barendse
    0

    Hi Francis,

    The biggest difference between IComponent.Initialize and the event handlers is whether it's executed within a request or background context. Every request will automatically create a scope, but IComponents aren't executed in a request, but at application startup, so you'll have to manually create that scope.

    You can do this by injecting the IScopeProvider and wrapping your existing code with:

    using IScope scope = _scopeProvider.CreateScope();
    
    // Existing code
    
    scope.Complete();
    

    The event handlers in your example only happen to work when the event is fired withing a request, so if content is published from a background thread, the ContentService_Published also wouldn't work. Also, the scope ensures all write-operations are committed when you complete it (it starts a database transaction behind the scenes).

    TL;DR Make sure to create (and complete!) a scope when doing write operations.

  • Francis 23 posts 123 karma points
    Jun 23, 2022 @ 10:59
    Francis
    0

    Hello Ronald,

    Thank you for the response. I've tried you're suggestion but still did not work. Here's how I added the scope provider:

        private readonly IContentService _contentService;
        private readonly IDataTypeService _dataTypeService;
        private readonly IUmbracoContextFactory _umbracoContextFactory;
        private readonly ILogger _logger;
        private readonly IScopeProvider _scopeProvider;
    
        public SampleComponent(IContentService contentService, 
            IDataTypeService dataTypeService, 
            IUmbracoContextFactory umbracoContextFactory, 
            ILogger logger,
            IScopeProvider scopeProvider)
        {
            _contentService = contentService;
            _dataTypeService = dataTypeService;
            _umbracoContextFactory = umbracoContextFactory;
            _logger = logger;
            _scopeProvider = scopeProvider;
        }
    

    Here's how I used it:

            using (IScope scope = _scopeProvider.CreateScope())
            {
                //populate dropdown - NOT WORKING
                var newValueList = new List<ValueListConfiguration.ValueListItem>();
                newValueList.Add(new ValueListConfiguration.ValueListItem
                {
                    Id = 1,
                    Value = "TEST VAL ONE111"
                });
                newValueList.Add(new ValueListConfiguration.ValueListItem
                {
                    Id = 2,
                    Value = "TEST VAL TWO222"
                });
    
                var dropDownTest = _dataTypeService.GetDataType(1515); //target dropdown datatype
                ((ValueListConfiguration)dropDownTest.Configuration).Items.AddRange(newValueList);
                _dataTypeService.Save(dropDownTest);
    
                scope.Complete();
                _logger.Info<ContentNodes>($"Dropdown Entries Added");
            }
    

    Breakpoint hits it and logs displays the logger message so I know this is being hit. However, the two values are still not being added to my target dropdown data type.

    Thank you again.

  • Ronald Barendse 39 posts 218 karma points hq c-trib
    Jun 24, 2022 @ 08:59
    Ronald Barendse
    1

    I've just tested this out on a clean Umbraco 8.18 site and looks like the data type service already creates its own scope, so that's not even required.

    The following code correctly replaces all existing items of the default dropdown data type:

    using System.Collections.Generic;
    using Umbraco.Core;
    using Umbraco.Core.Composing;
    using Umbraco.Core.Models;
    using Umbraco.Core.PropertyEditors;
    using Umbraco.Core.Services;
    
    public class ApplicationComposer : ComponentComposer<ApplicationComponent>, IUserComposer
    { }
    
    public class ApplicationComponent : IComponent
    {
        private readonly IDataTypeService _dataTypeService;
    
        public ApplicationComponent(IDataTypeService dataTypeService) => _dataTypeService = dataTypeService;
    
        public void Initialize()
        {
            var dataType = _dataTypeService.GetDataType(Constants.DataTypes.DropDownSingle);
    
            var items = new List<ValueListConfiguration.ValueListItem>()
                {
                    new ValueListConfiguration.ValueListItem
                    {
                        Id = 1,
                        Value = "TEST VAL ONE111"
                    },
                    new ValueListConfiguration.ValueListItem
                    {
                        Id = 2,
                        Value = "TEST VAL TWO222"
                    }
                };
    
            dataType.ConfigurationAs<ValueListConfiguration>().Items = items;
            _dataTypeService.Save(dataType);
        }
    
        public void Terminate()
        { }
    }
    

    It might be timing (hence the IUserComposer, so it runs after all core ones), custom logic cancelling save or some other issue, so make sure to check your logs and audit trail.

  • Francis 23 posts 123 karma points
    Jun 24, 2022 @ 10:48
    Francis
    0

    Hi Ronald,

    Thank you again for the response. I just tried this again using the code that you shared but it still did not work. I have 2 follow-up questions:

    1. I'm using version 8.14.1 for this, would this have an effect?
    2. For the logs I'm only able to check it using Settings--> logs ---> All logs and see my logger info there. Is there any other place I could be checking for the audit trail?

    Regards,

    Francis

  • Ronald Barendse 39 posts 218 karma points hq c-trib
    Jul 11, 2022 @ 12:20
    Ronald Barendse
    0

    Hi Francis,

    I've tested the above sample code on a clean 8.14.1 install and it updated the data type configuration without any issues, so it must be something else in your code (e.g. not completing a scope, causing all changes to rollback).

    You can indeed check the logs in Settings > Logs (or on-disk in App_Data\Logs). I checked the audit log and it data type saves aren't audited (they don't cause a row being added to umbracoAudit).

    My advise would be to start debugging code and try to isolate what's causing this to not work, either by stripping out/disabling code from your existing solution or adding bits to a clean install and seeing when it starts/stops working...

  • Francis 23 posts 123 karma points
    Jul 12, 2022 @ 08:43
    Francis
    0

    Thanks Ronald. I'll be sure to take a look and let you know.

Please Sign in or register to post replies

Write your reply to:

Draft