Using DetectChanges API in the event handler

Recently I've been reviewing the code of the event system extension that prevented some users from changing value of the metadata field.


private static void OnComponentSave(Component component, SaveEventArgs args, EventPhases phases)
{
    var session = component.Session;

    var privilegedGroupName = Configuration.AppSettings.Settings["privilegedGroupName"].Value;

    if (!UserIsMemberOfGroup(session.AccessToken, privilegedGroupName))
    {
        // Extract current value that user is trying to save
        string release = ExtractReleaseTitle(component.Metadata);

        // Re-read component to get previous (saved) state
        var previousComponent = (Component)session.GetObject(component.Id);
        var previousRelease = ExtractReleaseTitle(previousComponent.Metadata);

        if (release != previousRelease)
        {
            throw new Exception($"Sorry you are not a member of {privilegedGroupName} please change the release back to {previousRelease} and try again");
        }
    }
}


In order to get saved value, the item was re-read from database. In general, I try to omit extra reads if possible as every roundtrip slows down CME response time.
As of Web 8, there is an alternative. SaveEventArgs have DetectedChanges collection that contains list of changed properties and their old and new values. There is no need in re-reading saved component state. All necessaqry information is already prepared and available. Here is how the same logic can be implemented without any extra database roundtrips:


private static void OnComponentSave(Component component, SaveEventArgs args, EventPhases phases)
{
    // Check if Metadata was changed
    if (!args.DetectedChanges.ContainsKey("Metadata")) return;

    var session = component.Session;
    var privilegedGroupName = Configuration.AppSettings.Settings["privilegedGroupName"].Value;

    if (!UserIsMemberOfGroup(session.AccessToken, privilegedGroupName))
    {
        // Extract current value that user is trying to save
        var newMetadata = args.DetectedChanges["Metadata"].CurrentValue as XmlDocument;
        string release = ExtractReleaseTitle(newMetadata);

        // Extract previous value
        var previousMetadata = args.DetectedChanges["Metadata"].LoadedValue as XmlDocument;
        var previousRelease = ExtractReleaseTitle(previousMetadata);

        if (release != previousRelease)
        {
            throw new Exception($"Sorry you are not a member of {privilegedGroupName} please change the release back to {previousRelease} and try again");
        }
    }
}

Anonymous