Loading...
Area: Optimizely CMS
Applies to versions: 12 and higher
Other versions:

Writing custom attributes

Recommended reading 
Note: This documentation is for the preview version of the upcoming release of CMS 12/Commerce 14/Search & Navigation 14. Features included here might not be complete, and might be changed before becoming available in the public release. This documentation is provided for evaluation purposes only.

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 IDisplayMetadataProvider for your attribute to add metadata that affects the editing experience of the property.

You can combine the implementation of the IDisplayMetadataProvider 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 as well as adds server side validation if content is changed outside the editorial interface, through an attribute:

using EPiServer.Core;
using EPiServer.Security;
using EPiServer.Shell.ObjectEditing;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using System.ComponentModel.DataAnnotations;
using System.Linq;

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

        public string[] AllowedRoles { get; set; }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (validationContext.ObjectInstance is IContentData content)
            {
                if (!content.Property[validationContext.MemberName].IsModified)
                {
                    return ValidationResult.Success;
                }

                return IsInRole ? ValidationResult.Success : new ValidationResult("You do not have access");
            }
           
            //This attribute only handles instances of IContentData. return ValidationResult.Success;
            return ValidationResult.Success;
        }

        public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
        {
            if (IsInRole)
            {
                return;
            }

            var extendedMetadata = context.DisplayMetadata.AdditionalValues[ExtendedMetadata.ExtendedMetadataDisplayKey] as ExtendedMetadata;
            if (extendedMetadata == null)
            {
                return;
            }
            extendedMetadata.IsReadOnly = true;
        }

        private bool IsInRole => AllowedRoles.Any(r => PrincipalInfo.CurrentPrincipal.IsInRole(r));

    }
}

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 Optimizely 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 example above 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.

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 find this information helpful? Please log in to provide feedback.

Last updated: Jul 02, 2021

Recommended reading