Friday, May 24, 2013

Dynamics CRM 2011 – Reading Attribute Values Inside Your Plug-In

Posted in [Dynamics CRM], [Technical] By Eddie Furr @ 3/4/2011 10:20 AM

As the Dynamics CRM product evolves to provide more flexibility and extensibility for the user, changes to the underlying object model are inevitable. Microsoft must provide more robust and flexible entity attributes that allow users to customize CRM 2011 to meet their specific needs. Fortunately for developers, the programming model has been changed to use native .NET types whenever possible.  The net result is that many of the specific attributes from CRM 4.0 have been replaced with more “generic” types in CRM 2011. For a summary of these changes, take a peek here: http://technet.microsoft.com/en-us/library/gg328507.aspx

Often, developers need to capture an entity's attribute values to perform some custom function or action using a plugin. This might include updating other entities or even creating new entities based on the values derived from the base entity.

This article deals with the new OptionSetValue type, which replaces the PickList type in 4.0. It also replaces the “State” and “Status” entity attributes, which are specific PickList types. We will also read the other attributes, including the new EntityReference type which replaces a number of CRM 4.0 types such as Lookup, Customer, and Owner.  You will note that the CRM 2011 UI still refers to the “LookUp” data type, but the Attribute object model uses the EntityReference.

For examples of how we construct a plug-in and get our entity and attribute data, download the Microsoft Dynamics CRM 2011 SDK here: http://msdn.microsoft.com/en-us/dynamics/crm/default

The code below assumes we have created our service proxy from our context and implemented the Retrieve method to retrieve our entity and metadata column information. An example can be found here: http://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.iorganizationservice.retrieve.aspx

In the example reference above, and for our purposes, we will use the “Account” entity type as our basis. As in the example, we will call our account entity “retrievedAccount”.  We can iterate through the attributes of our entity as shown below. This snippet will call our custom function to read and return the value of each attribute. Note that we must call RetrieveAttributeRequest to get the metadata for our attribute itself.

   1: // Iterate the metadata columns collection
   2: foreach (KeyValuePair<string, object> metaAttribute in retrievedAccount.Attributes)
   3:      {
   4:         // Get our property object
   5:         object myProp = retrievedAccount.Attributes[metaAttribute.Key];
   6:         //
   7:         // Get the attribute metadata for the state attribute using RetrieveAttributeRequest.
   8:         RetrieveAttributeRequest attribReq = new RetrieveAttributeRequest();
   9:         attribReq.EntityLogicalName = retrievedAccount.LogicalName;
  10:         attribReq.LogicalName = metaAttribute.Key;
  11:         attribReq.RetrieveAsIfPublished = true;
  12:         RetrieveAttributeResponse amRes = (RetrieveAttributeResponse)_serviceProxy.Execute(attribReq);
  13:         AttributeMetadata attmetadata = amRes.AttributeMetadata;
  14:         // Now we call our function to read the attribute value for our entity
  15:         string sMyValue = GetMetadataValue(myProp , amRes);
  16:         Console.Write("Value of {0} is {1} ", metaAttribute.Key, sMyValue);
  17:  
  18:     }

Finally, here is our function to read and return the actual attribute value. Note that it uses attribute metadata from the RetrieveAttributeRequest to determine just how to read the value. For our OptionSetValue type, we simply put the possible values from the RetrieveAttributeRequest into an array and then find a match to the numeric value stored in our Entity’s metadata. We want to return the matching string value. For our EntityReference type, we simply return the Name property. For many attribute types we only have to return the objects string value.

   1: private string GetMetadataValue(object oAttribute, RetrieveAttributeResponse attMetadata)
   2: {
   3:     string sReturn = string.Empty;
   4:     if (oAttribute.GetType().Equals(typeof(Microsoft.Xrm.Sdk.OptionSetValue)))
   5:     {
   6:  
   7:         OptionMetadata[] optionList = null;
   8:         // Access the retrieved attribute.
   9:         //'Microsoft.Xrm.Sdk.Metadata.PicklistAttributeMetadata' 
  10:         if (attMetadata.AttributeMetadata.GetType().FullName.Contains("PicklistAttributeMetadata"))
  11:         {
  12:             PicklistAttributeMetadata retrievedPicklistAttributeMetadata =
  13:                 (PicklistAttributeMetadata)attMetadata.AttributeMetadata;
  14:             // Get the current options list for the retrieved attribute.
  15:             optionList = retrievedPicklistAttributeMetadata.OptionSet.Options.ToArray();
  16:         }
  17:         else if (attMetadata.AttributeMetadata.GetType().FullName.Contains("StatusAttributeMetadata"))
  18:         {
  19:             StatusAttributeMetadata retrievedPicklistAttributeMetadata =
  20:                 (StatusAttributeMetadata)attMetadata.AttributeMetadata;
  21:             // Get the current options list for the retrieved attribute.
  22:             optionList = retrievedPicklistAttributeMetadata.OptionSet.Options.ToArray();
  23:         }
  24:         else if (attMetadata.AttributeMetadata.GetType().FullName.Contains("StateAttributeMetadata"))
  25:         {
  26:             StateAttributeMetadata retrievedPicklistAttributeMetadata =
  27:                 (StateAttributeMetadata)attMetadata.AttributeMetadata;
  28:             // Get the current options list for the retrieved attribute.
  29:             optionList = retrievedPicklistAttributeMetadata.OptionSet.Options.ToArray();
  30:         }
  31:         else
  32:             return string.Empty;
  33:         // get the text values
  34:         int i = int.Parse((oAttribute as Microsoft.Xrm.Sdk.OptionSetValue).Value.ToString());
  35:         for (int c = 0; c < optionList.Length; c++)
  36:         {
  37:             OptionMetadata opmetadata = (OptionMetadata)optionList.GetValue(c);
  38:             if (opmetadata.Value == i)
  39:             {
  40:                 sReturn = opmetadata.Label.UserLocalizedLabel.Label;
  41:                 break;
  42:             }
  43:         }
  44:  
  45:     }
  46:     else if (oAttribute.GetType().Equals(typeof(Microsoft.Xrm.Sdk.Money)))
  47:     {
  48:         sReturn = (oAttribute as Microsoft.Xrm.Sdk.Money).Value.ToString();
  49:     }
  50:     else if (oAttribute.GetType().Equals(typeof(Microsoft.Xrm.Sdk.EntityReference)))
  51:     {
  52:         sReturn = (oAttribute as Microsoft.Xrm.Sdk.EntityReference).Name;
  53:     }
  54:     else
  55:     {
  56:         sReturn = oAttribute.ToString();
  57:     }
  58:     if (sReturn == null || sReturn.Length == 0)
  59:         sReturn = "No Value";
  60:     return sReturn;
  61: }

 In the above function I have tried to cover most of the common attribute types including the Money type. You will see that there is opportunity for an empty string to be returned if we run into an unexpected type. I also have it returning the string “No Value” if the attribute exists, but is not valued. This seems to be working pretty well thus far, but if I find additional functionality to add, I will post an update. Meanwhile, feel free to experiment with this a offer comments and enhancements.

Popular tags: , , , ,

Comments

Got something to say? Join the discussion »

leave a reply

 [Quick Submit with Ctrl+Enter]

Remember my details
Notify me of followup comments via e-mail

C5_Insight

About C5 Insight

We are a Microsoft Gold Certified partner focusing on SharePoint, Microsoft Dynamics CRM and Salesforce.com.  Learn more about us by visiting our website.

Search

We Wrote the Bible on Microsoft SharePoint and Dynamics CRMBook-Microsoft Dynamics CRM 2011 and SharePoint 2010 Bible

Tags

Maximize

Recent Comments

Maximize

Blog Roll

Maximize

Disclaimer

The information herein may be used solely at your own risk.  No warranty is made by the author or by C5 Insight, Inc.

The opinons expressed herein are those of the individual authors and do not necessarily represent C5 Insight, Inc in any way.

Copyright 2011 by C5 Insight