November Happy Hour will be moved to Thursday December 5th.

Property setters bypassed – why?

Vote:
 

I struck on that the block property setter is called only once during block “life time”. In case from call within

SetDefaultValues(ContentType contentType)

I performed some tests on this:

1. Create new block

[ContentType(DisplayName = "SetterTestsBlock", GUID = "43ca7e93-6982-4b95-b073-c42af6ad2315", Description = "")]
public class SetterTestsBlock : BlockData
{
  public virtual string SomeVirtualStringProperty
  {
    get => this.GetPropertyValue(t => t.SomeVirtualStringProperty);
    set { this.SetPropertyValue(t => t.SomeVirtualStringProperty, "Ahoj1"); }      
  }

  public string SomeStringProperty
  {
    get => this.GetPropertyValue(t => t.SomeStringProperty);
    set { this.SetPropertyValue(t => t.SomeStringProperty, "Ahoj2"); }    
  }

  public override void SetDefaultValues(ContentType contentType)
  {
    SomeVirtualStringProperty = "Čau1";
    SomeStringProperty = "Čau2";
  }
}

The result is expectable:

Test 1 result

2. Create new block again

[ContentType(DisplayName = "SetterTestsBlock", GUID = "43ca7e93-6982-4b95-b073-c42af6ad2315", Description = "")]
public class SetterTestsBlock : BlockData
{
  public virtual string SomeVirtualStringProperty
  {
    get => this.GetPropertyValue(t => t.SomeVirtualStringProperty);
    //set { this.SetPropertyValue(t => t.SomeVirtualStringProperty, "Ahoj1"); }
    //set { }
    set { throw new Exception(); }
  }

  public string SomeStringProperty
  {
    get => this.GetPropertyValue(t => t.SomeStringProperty);
    //set { this.SetPropertyValue(t => t.SomeStringProperty, "Ahoj2"); }
    //set { }
    set { throw new Exception(); }
  }

  //public override void SetDefaultValues(ContentType contentType)
  //{
  //    SomeVirtualStringProperty = "Čau1";
  //    SomeStringProperty = "Čau2";
  //}
}

This time the result is also quite expectable:
Test 2 result

3. Publish changes to block from test 2

Test 3

This result is not so expectable:


Test 3 result

Tests conclusion:

  1. Property setter is called only from SetDefaultValues(ContentType contentType) method during block first-time creation.
  2. Property setter is never further called.
  3. Observed behaviour does not depend on property virtuality (virtual modifier).

The Problem

Imagine situation illustrated by code underneath.

[ContentType(DisplayName = "RealUsageSimulation", GUID = "12737925-ab51-4f63-9144-cd4632244a1c", Description = "")]
public class RealUsageSimulation : BlockData
{
  public string SomeStrPropWithDependency
  {
    get => this.GetPropertyValue(t => t.SomeStrPropWithDependency);
    set
    {
      this.SetPropertyValue(t => t.SomeStrPropWithDependency, GetDBValue());
        
      string GetDBValue()
      {  
      return string.Join(
        ",",
        value.Split(new[] { ',', ';', '/'}, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()));
      }
    }
  }
}

Since issue described in tests this code is useless.

Am I wrong in some part? How to work around this in some good-approach manner?

#201492
Edited, Feb 20, 2019 18:16
Vote:
 

I haven't seen anyone bypassing setters as you described.

Some common scenarios:

Default values

Executed once, when a page is created

public override void SetDefaultValues(ContentType contentType)
{
    base.SetDefaultValues(contentType);
    this[MetaDataProperties.PageChildOrderRule] = FilterSortOrder.Alphabetical;
}

Fallback values

Doesn't work in All Properties view

public virtual string MyProperty
{
    get { return this.GetPropertyValue(x => x.MyProperty) ?? Name; }
    set { this.SetPropertyValue(x => x.MyProperty, value); }
}

Modify property values when saving a page

Init module

public void Initialize(InitializationEngine context)
{
    var events = context.Locate.Advanced.GetInstance<IContentEvents>();
    events.SavingContent += Events_SavingContent;
}

private void Events_SavingContent(object sender, EPiServer.ContentEventArgs e)
{
    if (e.Content is MyPage myPage)
    {
        if (myPage.MyProperty == "Foo")
        {
            myPage.MyProperty = "Boo";
        }
    }
}
#201522
Feb 21, 2019 16:53
Vote:
 

Did you try the example?

No matter this the reason relates to fact that content let’s say exists at DB level. So, if one delete the class, it is still possible to work with created content of that type (in CMS edit) including value sets.

If the model class exists, non-auto property getters are called – at least in some cases – in opposite to setters behaviour.

#201648
Feb 26, 2019 13:14
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* 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.