Copied to clipboard

Flag this post as spam?

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


  • Chester Campbell 98 posts 209 karma points
    Mar 05, 2021 @ 21:33
    Chester Campbell
    0

    Custom FieldProvider for Umbraco.MultiNodeTreePicker is not setting the value in the CMS

    I'm trying my hand at writing a custom FieldProvider; in this case for the Umbraco.MultiNodeTreePicker property editor. If I set a breakpoint I can see that my code is being executed (I have pasted it into this post below).

    My code has a debug logging statement and I can see the results in the Umbraco CMS log. And it shows that my input value is being converted properly into the output value that I expect.

    BTW, I'm basing my work on what I read here: https://our.umbraco.com/documentation/Getting-Started/Backoffice/Property-Editors/Built-in-Property-Editors/Multinode-Treepicker/

    Also, during my import the "Auto publish" option is un-checked and the "Enable content updates" option is un-checked.

    I'm running Umbraco CMS 8.11.1 and CMSImport 4.1.0.

    There are no errors or warnings in the Umbraco Log. The content being imported does get created, however the MNTP properties have no values.

    Hopefully, I'm missing something obvious. Can you tell me what it is? What am I doing wrong?

    Thanks!

    Here's my code:

    using CMSImport.Extensions.Providers.FieldProviders;
    using CMSImport.Extensions.Providers.ImportProviders;
    using CMSImport.Providers.AdvancedSettings.MNTPSettings;
    using Newtonsoft.Json;
    using System.Collections.Generic;
    using System.Linq;
    using Umbraco.Core;
    using Umbraco.Core.Logging;
    using Umbraco.Core.Models.PublishedContent;
    using Umbraco.Web;
    
    namespace MyProject.CMSImport.Providers.FieldProviders
    {
        [FieldProvider(PropertyEditorAlias = "Umbraco.MultiNodeTreePicker")]
        public class MntpFieldProvider : IFieldProvider
        {
            private readonly IUmbracoContextFactory _umbracoContextFactory;
            private readonly ILogger _logger;
    
        public MntpFieldProvider(IUmbracoContextFactory umbracoContextFactory, ILogger logger)
        {
            _umbracoContextFactory = umbracoContextFactory;
            _logger = logger;
        }
    
        #region IFieldProvider
    
        public object Parse(object value, ImportPropertyInfo property, FieldProviderOptions fieldProviderOptions)
        {
            if (value == null)
            {
                return value;
            }
    
            if (string.IsNullOrEmpty(value.ToString()))
            {
                return value;
            }
    
            IPublishedContent parentNode = GetParentNode((AdvancedMNTPSettingsOptions)property.ProviderOptions);
    
            List<string> results = new List<string>();
    
            IEnumerable<string> listOfValues = JsonConvert.DeserializeObject<IEnumerable<string>>(value.ToString());
    
            if (listOfValues != null && listOfValues.Any())
            {
                foreach (string val in listOfValues)
                {
                    IPublishedContent node = GetContentNode(val);
    
                    if (node != null)
                    {
                        if (IsChildOfParentNode(parentNode, node))
                        {
                            results.Add(Udi.Create(Constants.UdiEntityType.Document, node.Key).ToString());
                        }
                    }
                }
            }
    
            if (!results.Any())
            {
                return string.Empty;
            }
    
            string csv = string.Join(",", results);
    
            _logger.Debug<MntpFieldProvider>("Converted MNTP values from {value} to {csv}", value, csv);
    
            return csv;
        }
    
        #endregion IFieldProvider
    
        private IPublishedContent GetContentNode(string id)
        {
            int nodeId;
    
            if (int.TryParse(id, out nodeId))
            {
                using (UmbracoContextReference umbracoContext = _umbracoContextFactory.EnsureUmbracoContext())
                {
                    return umbracoContext.UmbracoContext.Content.GetById(nodeId);
                }
            }
    
            return null;
        }
    
        private bool IsChildOfParentNode(IPublishedContent parentNode, IPublishedContent node)
        {
            if (parentNode == null)
            {
                return true;
            }
    
            if (node.IsDescendantOrSelf(parentNode))
            {
                return true;
            }
    
            return false;
        }
    
        private IPublishedContent GetParentNode(AdvancedMNTPSettingsOptions providerOptions)
        {
            Udi udi;
    
            if (Udi.TryParse(providerOptions.ContentRootId, out udi))
            {
                using (UmbracoContextReference umbracoContext = _umbracoContextFactory.EnsureUmbracoContext())
                {
                    return umbracoContext.UmbracoContext.Content.GetById(udi);
                }
            }
    
            return null;
        }
    }
    }
    
  • Chester Campbell 98 posts 209 karma points
    Mar 09, 2021 @ 15:11
    Chester Campbell
    0

    I have confirmed, by looking in the database, that MNTP data is indeed saved as a comma-delimited list of UDIs. Like this:

    umb://document/a602fa4c356348329a7c97a0c2612d3d,umb://document/a8cee19d39944688a7ce2a646f22e4af,umb://document/fd58f6377e554d2ebecaeaae14eea9ed
    

    And that's definitely what my FieldProvider is outputting.

  • Chester Campbell 98 posts 209 karma points
    Mar 09, 2021 @ 19:40
    Chester Campbell
    0

    More information: When I run the import with the "auto publish" checkbox checked I get the following error in the UI:

    Could not publish the document, property alias:'categories' has no value or is invalid
    

    The property with alias 'categories' is the property using the MNTP in the new CMS.

    In the Umbraco Log I find this:

    System.ArgumentException: Could not publish the document, property alias:'categories' has no value or is invalid
     at CMSImport.Providers.ImportProviders.ContentImport.ContentImportProvider.(IContent , Int32 )
     at CMSImport.Providers.ImportProviders.ContentImport.ContentImportProvider.Import(ImportState state)
    

    As you can see the method and parameter names are not coming through. In the string they're expressed as unicode u+0002, which means "Start of Text" and unicode u+0003, "end of text". Though I don't know the method name it appears to be expecting an IContent object and an int as parameters. If my custom FieldProvider value is being passed in to the int parameter I can see why it would throw an error.

    So the question is ... why is the import of a string being handed off to a method that requires an int parameter?

  • Chester Campbell 98 posts 209 karma points
    Mar 09, 2021 @ 21:38
    Chester Campbell
    0

    More Info: Just to make absolutely sure that nothing in my custom FieldProvider was erroring out silently I commented everything out and hard coded the return string value.

    Even with that I still get the same errors during the import.

  • Richard Soeteman 4035 posts 12842 karma points MVP
    Mar 10, 2021 @ 11:03
    Richard Soeteman
    0

    Hi Chester,

    Sorry for the delay in response. The reason you got this error was because after fieldprovider parsing it went through the advanced field provider. I've just released version 4.1.1. of CMSImport that respects the Break property in the Fieldprovider. If you set it to true in your code after parsing the values it will never go through the advanced field provider.

    This is my test code

     [FieldProvider(PropertyEditorAlias = "Umbraco.MultiNodeTreePicker")]
    public class MntpCustomProvider : IFieldProvider
    {
        public object Parse(object value, ImportPropertyInfo property, FieldProviderOptions fieldProviderOptions)
        {
            fieldProviderOptions.Break = true;
            return "umb://document/ce625e805b7a450d8240f688417ed6e6,umb://document/79a07efddb9e4097941fa3bbfedd0b3d";
        }
    }
    

    Hope this helps,

    Richard

  • Chester Campbell 98 posts 209 karma points
    Mar 10, 2021 @ 15:05
    Chester Campbell
    100

    Hi Richard,

    This solution worked perfectly! Thank you.

    I have a couple of questions. I am also going to be building a custom FieldProvider for my Nested Content properties in the new CMS. Will I need to set the fieldProviderOptions.Break property there as well?

    And can you explain what role the FieldProviderAttribute.Priority setting plays? Do I ever need to use it? And do I set my priority to a higher number or a lower number?

    Thanks! chester

  • Chester Campbell 98 posts 209 karma points
    Mar 10, 2021 @ 16:32
    Chester Campbell
    0

    Sigh ... I marked the wrong post as the solution. The post by Richard, above, is actually the solution!

  • Richard Soeteman 4035 posts 12842 karma points MVP
    Mar 10, 2021 @ 15:12
    Richard Soeteman
    0

    Hi Chester,

    Great it works. Nested Content is not yet supported (yet) so you don't need to set the Break property.

    The priority can be set to make sure your provider is called before or after the default ones. My providers are always set to medium.

    Hope this helps,

    Richard

  • Chester Campbell 98 posts 209 karma points
    Mar 10, 2021 @ 16:30
    Chester Campbell
    0

    Thanks!!

Please Sign in or register to post replies

Write your reply to:

Draft