Hide menu Last updated: Sep 21 2015

Writing custom attributes

Write custom attributes to improve the editor experience, add business rules, or add custom validation.

Restricting access for editing a certain property

You can restrict access in the following ways:

  • Create a ValidationAttribute to add server-side validation when data is saved.
  • Implement IMetadataAware for your attribute to add metadata that affects the editing experience of the property.

You can combine the implementation of the IMetadataAware attribute with a ValidationAttribute to control which roles can edit a specific property.

The following example shows how to make a property read-only in the editorial interface through an attribute:

using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace EPiServer.Samples
{
   public class PropertyEditRestrictionAttribute : ValidationAttribute, IMetadataAware
   {
       public PropertyEditRestrictionAttribute(string[] allowedRoles)
       {
          AllowedRoles = allowedRoles;
       }
 
       public string[] AllowedRoles { get; set;
       } 
       public void OnMetadataCreated(ModelMetadata metadata)
       { 
           foreach (string role in AllowedRoles)
           { 
              if (EPiServer.Security.PrincipalInfo.CurrentPrincipal.IsInRole(role))
              { 
                 return;
              } 
           }
           metadata.IsReadOnly = true;
       } 
   } 
}

Usage on the model should look as follows. The example uses the group name administrators2 to make sure you are not member of this group.

[PropertyEditRestriction(new string[]{"administrators2"})]
public virtual XhtmlString MainBody { get; set; }

Go to the Episerver edit view to see that the editor was disabled in the All properties editing view:

In the On-page editing view, the property looks editable, but if you cannot edit the property and you click on the overlay, edit view loads a read-only editor and removes the overlay entirely.

Validation on the server

The following example adds server validation to the same attribute from the example in the previous section, so that you cannot post a fake property update to the server even without having the correct access.

using System;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using EPiServer.Core;

namespace EPiServer.Samples
{
   public class PropertyEditRestrictionAttribute : ValidationAttribute, IMetadataAware
   {
       public PropertyEditRestrictionAttribute(string[] allowedRoles)
       {
           AllowedRoles = allowedRoles;
       } 

       public string[] AllowedRoles { get; set; }

       public void OnMetadataCreated(ModelMetadata metadata)
       {
          foreach (string role in AllowedRoles)
          {
             if (EPiServer.Security.PrincipalInfo.CurrentPrincipal.IsInRole(role))
             {
                 return;
             }
          }
          //Comment row below to test the server validation.
          metadata.IsReadOnly = true;
       }
       
       public override string FormatErrorMessage(string name)
       {
          return "You do not have access to change " + name;
       }
 
       protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
       {
         var contentData = validationContext.ObjectInstance as IContentData;
         if (contentData == null)
         {
            //This attribute only handles instances of IContentData. return ValidationResult.Success;
         } 
         if (!contentData.Property[validationContext.MemberName].IsModified) 
         { 
            return ValidationResult.Success; 
         } 
         if (Validate()) 
         { 
            return ValidationResult.Success; 
         } 
         else { return new ValidationResult("You do not have access"); } 
      }
 
      public override bool RequiresValidationContext 
      { 
         get 
         { 
            return true; 
         } 
      } 

      public bool Validate() 
      { 
         foreach (string role in AllowedRoles) 
         { 
            if (EPiServer.Security.PrincipalInfo.CurrentPrincipal.IsInRole(role))
            { 
               return true; 
            } 
         } 
         return false;
      } 
   } 
}

You can comment out the line that makes the property read-only, and edit the property to validate that the server validation actually does work. 

Comments

Hello!

Is it possible to make the custom validation to appear next to the property that failed?


Hi,
Thanks for the feedback.

Right now it is not possible to get that information next to the property, I will forward this to our UX-team.

/Magnus

Is there a way of forcing all error messages to only apear next to the publish button?

Right now for example these attributes will have their messages displayed next to the validated property input.

[Required]
[Range(0.0,1.0)]

Like this.

It's feels like somewhat strange and inconsistent behavior to mix and have some validation messages for a property apear next to the property and some (my custom ones) next to the publish button.

 /Peter

Hi,

Right now it is not possible force all the errors to the same place. And I agree that it is inconsistent right now.

/Magnus