Search code examples
episerver

Episerver – Why is property setter bypassed?


It seems that content model setter is called only once when created from within

SetDefaultValues(ContentType contentType)

I performed some tests:

1. Create new block

  1. Properties are tried to be set with some values from SetDefaultValues.
  2. Because of setters implementation other values are used.
[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

enter image description here

2. Create new block again

  1. Let setters throws exception.
[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

  1. No default values override call = no default values, resp. no exception.

enter image description here

3. Publish changes to block from test 2

  1. Input some values in CMS web interface.
  2. Publish changes.

enter image description here

This result is not so expectable

  1. CMS shows no errors so no exception was thrown.

enter image description here

Summary

  1. Property setter is called only from SetDefaultValues(ContentType contentType) method (during block first-time creation).
  2. 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, GetDbStoreFormValue());
        
      string GetDbStoreFormValue()
      {  
         return string.Join(
           ",",
           value
             .Split(new[] { '♦', '♣', '♠'}, StringSplitOptions.RemoveEmptyEntries)
             .Select(x => x.Trim()));
      }
    }
  }
}

Since issue described in summary setter logic is basically useless.

Am I wrong in some part?

I know how to solve this problem other proper way. I just wonder why setter is not called.


Solution

  • Property values aren't saved through the model class' property when, for example, saving content by editing it in edit mode (remember: content can be saved even if the content type class is removed from code).

    The reason why the setter is called in SetDefaultValues is because your code uses the class property.

    For your case, it would perhaps be more suitable to wire up the ContentSaving event to make any property value changes when content is being saved.