Oct 31, 2012

Sample Plug-in: State change

It is important to catch the action when a state change occurs for a record. What we are referring here is the setting of Status (statecode) and Status Reason (statuscode). They are native CRM fields and they work as combinations. These values even determine whether a record is active or inactive. Here you can see full list of those codes for native CRM entities.

Though, those fields appear normal, one should not attempt to update them using normal update method as any other field. They are special fields and they are changed through state change method only.

What is important is, we have separate messages to capture those state changes and we have to write the plug-in code accordingly. Please refer below code to understand how we grab those codes so that we are ready to implement the logic.

Please note state.Value and status.Value we get in this code is the new values after the set state operation. We may capture whatever the status change we are interested in.

using System;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.ServiceModel;

namespace TestCompany.CRM.Plugin
{
 public class officeSetState : IPlugin
 {
   public void Execute(IServiceProvider serviceProvider)
   {
     IPluginExecutionContext context;
     IOrganizationServiceFactory factory;
     IOrganizationService service;

     try
     {
       context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
       factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
       service = factory.CreateOrganizationService(context.UserId);

       if ((context.InputParameters.Contains("EntityMoniker")) && (context.InputParameters["EntityMoniker"] is EntityReference))
       {
        var targetEntity = (EntityReference)context.InputParameters["EntityMoniker"];
        var state = (OptionSetValue)context.InputParameters["State"];
        var status = (OptionSetValue)context.InputParameters["Status"];

        if (targetEntity.LogicalName != "new_office")
        { return; }
                    
         // Set State Logic
         // state.Value gives state code
         // status.Value gives status code

        }
      }
      catch (FaultException<OrganizationServiceFault> e)
      {
        throw e;
      }
      finally
      {
        service = null;
        factory = null;
        context = null;
      }
    }
  }
}

Tricky part lies here. When registering the plug-in we need to have steps for both SetState and SetStateDyanamicEntity messages.


Related posts;
Sample Plug-in: Delete
Sample Plug-in: Compare Pre and Post images on Update
Sample Plug-in code: Create and Update
Retrieve attributes of entity object

Sample Plug-in: Compare Pre and Post images on Update

We often use Update message to execute something after identifying whether a particular value is changed from A to B. Typically, we might need to handle some logic to be run upon state change which is defined as a custom field (actually an optionsetvalue). In this case, we need to implement a post update plug-in with two images. Here images are snapshots of the entity in pre/ post execution which enables us to compare some values.

Scenario I am explaining got a custom field called new_officestatus which holds the status of office (new_office entity). It says whether a given office is a main, regional or sub office.


Suppose we need to do something when an office is converted from Sub to Regional.  What we going to do is compare the values of the status in each update action. Below are the optionsetvalues;

Regional - 100000001
Sub – 100000002
Main – 100000003

If we find Pre image with 100000002 and Post image with 100000001, it is the exact time that a sub office is converted to a regional one, which we need to execute our custom logic. Below code shows how it’s being done programmatically.

using System;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.ServiceModel;

namespace TestCompany.CRM.Plugin
{
public class officeUpdate : IPlugin
 {
  public void Execute(IServiceProvider serviceProvider)
  {
   IPluginExecutionContext context;
   IOrganizationServiceFactory factory;
   IOrganizationService service;
   Entity PreImage;
   Entity PostImage;

   try
   {
     context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
     factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
     service = factory.CreateOrganizationService(context.UserId);

     PreImage = (Entity)context.PreEntityImages["PreUpdateImage"];
     PostImage = (Entity)context.PostEntityImages["PostUpdateImage"];

     int _preOfficestatusVal = 0;
     int _postOfficestatusVal = 0;

     if (PreImage.Contains("new_officestatus"))
     { _preOfficestatusVal = ((OptionSetValue)PreImage["new_officestatus"]).Value; }
     if (PostImage.Contains("new_officestatus"))
     { _postOfficestatusVal = ((OptionSetValue)PostImage["new_officestatus"]).Value; }

     if ((_preOfficestatusVal == 100000002) && (_postOfficestatusVal == 100000001))
     {
        // Logic for - Sub converted to Regional
     }

    }
    catch (FaultException<OrganizationServiceFault> e)
    {
      throw e;
    }
    finally
    {
      service = null;
      factory = null;
      context = null;
      PreImage = null;
      PostImage = null;
    }
  }
 }
}

Now we will see plug-in registration. Here, we register two images for Pre and Post stages. They have the same name as images we read from the context in the code.


Related posts;
Sample Plug-in: Delete
Sample Plug-in: State change
Sample Plug-in code: Create and Update
Retrieve attributes of entity object