Try our conversational search powered by Generative AI!

Optional properties in objects used in PropertyList types must be nullable reference types?

Vote:
 

Hi,

I am currently migrating to CMS 12 and our code solution includes several PropertList properties in blocks and pages. One thing we noticed right away after migrating is that all of the previous optional properties are now marked as required by the CMS UI even though that is not the code definition. For example,

The code definition of this property looks like

public class InventorySearchSortFilter
    {
        [CultureSpecific]
        [Display(
            Name = "Title",
            Order = 10)]
        public string Title { get; set; }

        [Display(
            Name = "Order By",
            Order = 15)]
        [SelectOne(SelectionFactoryType = typeof(OrderByFactory))]
        public string OrderBy { get; set; }

        [Display(
            Name = "Field",
            Order = 20)]
        [SelectOne(SelectionFactoryType = typeof(InventorySearchSortFilterFieldFactory))]
        public string Field { get; set; }
    }
    
    /// <summary>
    ///     For registering the editing interface
    /// </summary>
    [PropertyDefinitionTypePlugIn]
    public class InventorySearchSortFilterProperty : PropertyList<InventorySearchSortFilter>
    {
    }

Normally I expect required fields to explicity have the Required decorator. Without it, they're considered optional by default.

I came to notice that by explicity setting the properties as a nullable reference type, the UI gets fixed. For example, the previous class would be rewritten as

public class InventorySearchSortFilter
    {
        [CultureSpecific]
        [Display(
            Name = "Title",
            Order = 10)]
        public string? Title { get; set; }

        [Display(
            Name = "Order By",
            Order = 15)]
        [SelectOne(SelectionFactoryType = typeof(OrderByFactory))]
        public string? OrderBy { get; set; }

        [Display(
            Name = "Field",
            Order = 20)]
        [SelectOne(SelectionFactoryType = typeof(InventorySearchSortFilterFieldFactory))]
        public string? Field { get; set; }
    }
    
    /// <summary>
    ///     For registering the editing interface
    /// </summary>
    [PropertyDefinitionTypePlugIn]
    public class InventorySearchSortFilterProperty : PropertyList<InventorySearchSortFilter>
    {
    }

Interestingly, even after fixing the class definition. The IList property that makes use of it seems to behave the same way, for example

[CultureSpecific]
        [Display(
            Name = "Sort Options",
            Order = 50,
            GroupName = SiteTabs.InventorySearchResults)]
        [EditorDescriptor(EditorDescriptorType = typeof(CollectionEditorDescriptor<InventorySearchSortFilter>))]
        [JsonIgnore]
        public virtual IList<InventorySearchSortFilter> SortOptions { get; set; }

SortOptions becomes required from a UI perspective when creating a new block/page with this property even though it's optional. Adding ? fixes the problem too but you can see how this becomes more and more complex and more refactoring is required. For example

[CultureSpecific]
        [Display(
            Name = "Sort Options",
            Order = 50,
            GroupName = SiteTabs.InventorySearchResults)]
        [EditorDescriptor(EditorDescriptorType = typeof(CollectionEditorDescriptor<InventorySearchSortFilter>))]
        [JsonIgnore]
        public virtual IList<InventorySearchSortFilter>? SortOptions { get; set; }

I took a look at the Foundation project and PropertyList propeties work as expected there and the definition matches the definition used in my code. Properties do not need to be set as nullable reference types so I believe I'm missing something here.

Based on how big our code base is and how many stuff would need to start accounting for possible null values, I'd like to have a global solution so to speak.

I couldn't find any documentation about it or posts exposing a similar issue so far so any help is appreciated!

#302423
May 26, 2023 19:47
Vote:
 

If you're currently migrating it's worth being aware that Optimizely has recently released the new "official" way of implementing properylists as technically the old way has been in beta since launch.

https://world.optimizely.com/blogs/bartosz-sekula/dates/2023/1/official-list-property-support/ 

I'd suggest to future proof moving to this way, although I've not checked if your required/not required mechanism works but it might well do with better support using Block types

#302652
Edited, May 30, 2023 10:47
Vote:
 

Hi Scott!

Yes, I read that page and it looks like a promising feature. However, when discussing with the team of Content Editors the general consensus was that in its current state, it's still missing some critical features like being able to set a property like the display name instead of using the name of the block that ends up being the same for every entry more often than not. Which is why migrating isn't our first option.

We have ultimately settled for specifying explicit nullability for our optional properties for now at least. It requires a bit of refactoring that is just time-consuming. However, I cannot help but feel that such a thing is not really necessary and I am missing something here.

#302662
May 30, 2023 15:59
Vote:
 

Apologies I'm not following you regarding "being able to set a property like the display name instead of using the name of the block that ends up being the same for every entry more often than not" can you elaborate? I'm curious on what you're referring to

#302708
May 31, 2023 9:22
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.