Thursday, October 10, 2013

EPiServer 7: Set default values on properties with attribute

I have been looking into setting default values on a property in EPiServer 7 MVC to be set if the value is null, but so far I have only stumbled upon setting a default value on a property when creating a new page.

I want to be able to specify the default value as an attribute to the property and found what I thought would work and that is System.ComponentModel.DefaultValueAttribute.


   1:  [DefaultValue("Y")]
   2:  public virtual string DisplayTeasers { get; set; }

It looked perfect, but didn't work. :-(

So, I tweaked it a little to make it work the way I wanted it to. Perhaps you need to be familiar with the EPiServer 7 MVC templates in order to achieve this but the idea is to "transform" to CurrentPage object and set the default values if the current property value is null, and we do this when creating the PageViewModel.

The attribute contains constructors for setting the default values and some static methods to transform an entire CurrentPage object based on any default value attributes specified.


   1:  public class ViewModelDefaultValueAttribute : DefaultValueAttribute
   2:  {
   3:      public ViewModelDefaultValueAttribute(string value) : base(value)
   4:      { }
   5:   
   6:      public ViewModelDefaultValueAttribute(int value) : base(value)
   7:      { }
   8:   
   9:      public ViewModelDefaultValueAttribute(bool value) : base(value)
  10:      { }
  11:   
  12:   
  13:      public static T SetDefaultValues<T>(T currentPage) where T : SitePageData
  14:      {
  15:          if (currentPage == null)
  16:              return currentPage;
  17:   
  18:          Type currentPageType = GetType<T>(currentPage);
  19:          if (currentPageType == null)
  20:              return currentPage;
  21:   
  22:          T clone = currentPage.CreateWritableClone() as T;
  23:   
  24:          Type defaultValueType = typeof(ViewModelDefaultValueAttribute);
  25:   
  26:          foreach (PropertyInfo property in currentPageType.GetProperties())
  27:          {
  28:              if (clone[property.Name] != null)
  29:                  continue;
  30:   
  31:              object[] attributes = property.GetCustomAttributes(defaultValueType, false);
  32:              if (attributes == null || attributes.Length == 0)
  33:                  continue;
  34:   
  35:              ViewModelDefaultValueAttribute defaultValue = attributes.Cast<ViewModelDefaultValueAttribute>().Single();
  36:              if (defaultValue == null)
  37:                  continue;
  38:   
  39:              clone.Property[property.Name].Value = defaultValue.Value;
  40:          }
  41:   
  42:          if (clone.IsModified)
  43:          {
  44:              clone.MakeReadOnly();
  45:              return clone;
  46:          }
  47:   
  48:          return currentPage;
  49:      }
  50:   
  51:      private static Type GetType<T>(T currentPage) where T : SitePageData
  52:      {
  53:          Type type = currentPage.GetType();
  54:   
  55:          while (type != null && !type.FullName.Contains("EPi7.Models.Pages"))
  56:          {
  57:              type = type.BaseType;
  58:          }
  59:   
  60:          return type;
  61:      }
  62:  }

As you can see we inherit the DefaultValueAttribute in order to utilize existing functionality.

The static method SetDefaultValues is used to "transform" the CurrentPage object and it loops through all the properties on the page type and then finds any ViewModelDefaultValueAttributes specified and if the property value is null sets the default value specified.

SitePageData is the base class for all pages types.


   1:  /// <summary>
   2:  /// Base class for all page types
   3:  /// </summary>
   4:  public abstract class SitePageData : PageData

You specify the default value like this on a property.


   1:  [ViewModelDefaultValue("Y")]
   2:  public virtual string DisplayTeasers { get; set; }

We also need to use the SetDefaultValues method somewhere and this is done in the constructor when creating the PageViewModel.


   1:  public class PageViewModel<T> : IPageViewModel<T> where T : SitePageData
   2:  {
   3:      public PageViewModel(T currentPage)
   4:      {
   5:          CurrentPage = ViewModelDefaultValueAttribute.SetDefaultValues(currentPage);
   6:      }
   7:  }

When putting all of this together you can specify a default value as a attribute on a property and before the CurrentPage object is sent to the view (via view model) it is tranformed to set default values if the property is null.

As you can see in the image above the default value "Y" is displayed (as an example) on the page but when editing the property it is blank (null).

No comments:

Post a Comment