This content is archived. See latest version here

Last updated: Sep 22 2014

Writing custom attributes

Restricting access to who is allowed to edit a certain property

This document describes how you can write custom attributes as a way to improve the editor experience, add business rules, or add custom validation.

There are two ways to do this and these can be combined. The first is to create a ValidationAttribute. This makes is possible to add server side validation when data is saved. The other is to implement IMetadataAware for your attribute. This makes is possible to add metadata that affects the editing experience of the property.

This document shows an example how to combine implemenation of the IMetadataAware attribute with a ValidationAttribute to control which roles are required to 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;
       } 
   } 
}

And the usage on the model like this:

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

Notice the group name “administrators2” just to make sure you are not member of this group.

Go to the EPiServer editorial interface to see that the editor has been disabled in the all properties view:

In the on-page edit view, the property looks editable but when clicking on the overlay, a read-only editor is loaded. The overlay is removed entirely when the property is not editable.

Validation on the server

The code above is really simple and probably solves the customer requirements in most cases. But since this only affects the editorial interface, it is of course possible to post a fake property update to the server even without having the correct access. Let’s see how we can add server validation as well to the same attribute.

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.


Do you have feedback on this documentation? Send an email to documentation@episerver.com. For development-related questions and discussions, refer to our Forums on https://world.episerver.com/forum/