Copied to clipboard

Flag this post as spam?

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


  • Bojan 16 posts 131 karma points
    Oct 18, 2016 @ 13:11
    Bojan
    0

    Custom umbraco property converter for Models Builder - dependency injection issue (DI)

    Hi guys,

    I'm using the latest Umbraco and Models Builder, and I'm creating custom property value converter in order to extend Models Builder generator to recognise data types like RadioButton, Dropdown, Tags etc.

    Here I will stick to the DropdownConverter implementation. The problem I want to solve is using DI (Autofac) in places other that controllers where it works fine.

    This is my implementation of the Dropdown Converter

     public class DropdownConverter : PropertyValueConverterBase, IPropertyValueConverterMeta
    {
        private readonly UmbracoHelper _umbracoHelper;
    
        public DropdownConverter(UmbracoHelper umbracoHelper)
        {
            _umbracoHelper = umbracoHelper;
        }
    
        public override bool IsConverter(PublishedPropertyType propertyType)
        {
            return "Umbraco.DropDown".InvariantEquals(propertyType.PropertyEditorAlias);
        }
    
        public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
        {
            return source != null ? _umbracoHelper.GetPreValueAsString((int)source) : string.Empty;
        }
    
        public Type GetPropertyValueType(PublishedPropertyType propertyType)
        {
            return typeof(string);
        }
    
        public PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType, PropertyCacheValue cacheValue)
        {
            return PropertyCacheLevel.Content;
        }
    }
    

    Generated property type

    ///<summary>
        /// Category: Set blog category
        ///</summary>
        [ImplementPropertyType("category")]
        public object Category
        {
            get { return this.GetPropertyValue("category"); }
        }
    

    Here you can see that I'm using constructor injection for one dependency that I need to use in my converter (UmbracoHelper).

    When I leave converter like this, MB won't recognise property value type and will generate 'object' as a previous default value. But if you ask for the result of this property somewhere in the code, you will get proper string value because converter works as expected and DI works also.

    Otherwise, If I write the code with another empty constructor, MB will successfully recognise return type, but now DI won't work and my UmbracoHelper will be null (CastException is thrown).

     public class DropdownConverter : PropertyValueConverterBase, IPropertyValueConverterMeta
    {
        private readonly UmbracoHelper _umbracoHelper;
    
        public DropdownConverter()
        {
    
        }
    
        public DropdownConverter(UmbracoHelper umbracoHelper)
        {
            _umbracoHelper = umbracoHelper;
        }
    
        public override bool IsConverter(PublishedPropertyType propertyType)
        {
            return "Umbraco.DropDown".InvariantEquals(propertyType.PropertyEditorAlias);
        }
    
        public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
        {
            return source != null ? _umbracoHelper.GetPreValueAsString((int)source) : string.Empty;
        }
    
        public Type GetPropertyValueType(PublishedPropertyType propertyType)
        {
            return typeof(string);
        }
    
        public PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType, PropertyCacheValue cacheValue)
        {
            return PropertyCacheLevel.Content;
        }
    }
    

    Generated property type

    ///<summary>
        /// Category: Set blog category
        ///</summary>
        [ImplementPropertyType("category")]
        public string Category
        {
            get { return this.GetPropertyValue<string>("category"); }
        }
    

    It seems that MB needs an empty constructor in a property converter. My question is, given that I want to use DI all over the project, how I can do it in this place and is it possible anyway? I also tried property injection principle but still no luck.

    Thanks, Bojan

  • marcelh 171 posts 471 karma points
    Oct 31, 2017 @ 19:51
    marcelh
    0

    And, did you manage to find a solution to this? Running into this too...

  • Brad McDavid 11 posts 123 karma points
    Oct 31, 2017 @ 20:07
    Brad McDavid
    100

    Hi Bojan,

    The simplest solution would be to create a

    static Func<UmbracoHelper> GetUmbracoHelper {get;set;} 
    

    then assign the GetUmbracoHelper to a static function that creates UmbracoHelper instances with no function arguments in an ApplicationEventHandler.

    Then in your constructor you can fallback to it with something like

    _umbracoHelper = umbracoHelper ?? GetUmbracoHelper.Invoke();
    

    The bigger question I'm not sure of, do property converters have a single instance in the application. If so, you'll want to refactor the implementation to not assign in the constructor as the context would be stale after first request.

    Hope this helps,

    Brad

  • Brad McDavid 11 posts 123 karma points
    Oct 31, 2017 @ 20:14
    Brad McDavid
    1

    Also, if you like using DI in Umbraco, you should look into a NuGet package I made called Renderings, noted here.

Please Sign in or register to post replies

Write your reply to:

Draft