How to get better performance from the MetadataService


You may have noticed that in 4.0, the MetadataService is considerably slower at retrieving data that it was in 3.0. In fact, you’ll still see the difference if you compare the 2006 MetadataService endpoint and the 2007 endpoint. Why is this?

The reason is that in 3.0, the MetadataService reads from the server’s MetadataCache, so it’s very quick. In 4.0 it reads from the database, so each request has to build up the objects you want. The reason we read from the database is to give you the option of retrieving either published or unpublished Metadata.

Here are some key differences between the MetadataService of 3.0 and 4.0, or the 2006 and 2007 endpoint:

Microsoft Dynamics CRM 3.0


  • Fast
  • Read Only
  • Returns only published metadata
  • Method based (ex: RetrieveEntityMetadata())

Microsoft Dynamics CRM 4.0


  • Slower
  • Returns more data

    • Ex: EntityMetadata now contains properties such as: ‘IsAvailableOffline’, ‘IsIntersect’, ‘CanTriggerWorkflow’, …
    • Ex: OneToManyMetadata contains the cascade behavior of the relationship.

  • Allows Read and Write operations
  • Can return either published or unpublished metadata

    • Each request message has a Boolean parameter called ‘RetrieveAsIfPublished’.
    • This parameter bears some explanation as the name can be confusing at first.

      • ‘RetrieveAsIfPublished = True’ means “return the Metadata including unpublished changes” or “as it would look if I published.”
      • ‘RetrieveAsIfPublished = False’ means “return only the currently published Metadata, ignoring any unpublished changes that exist.”

  • Uses the same Request/Response pattern as the CrmService (ex: RetrieveEntityRequest/RetrieveEntityResponse)

Some tips for dealing with performance:


  • Use the EntityItems flag to retrieve only what you need.

    • If you need to know the PrimaryKey of an entity, use the RetrieveEntityRequest and set the ‘EntityItems’ property to  ‘EntityItems.EntityOnly’. Then it won’t spend the time building up a list of Attributes or Relationships that you won’t use.
    • Note that this parameter existed in the 3.0 MetadataService, but since it was reading cached data, it didn’t provide much of an improvement. In 4.0, you’ll see a significant performance gain by using this property appropriately.

  • Use the appropriate Retrieve message to get only what you need.

    • Use RetrieveAttributeRequest or RetrieveRelationshipRequest instead of RetreiveEntityRequest to get just the object you need.

  • Build your own Metadata cache.

    • Retrieve the entire Metadata once, and then whenever your application needs it, read from your cached data instead of making a call to the server. Then use the RetrieiveTimestampRequest to poll the server to see if the metadata has changed since the last time you loaded it.  The name ‘RetrieveTimestamp’ is a bit misleading because it doesn’t return a DateTime, it returns a string that represents a hash of the entire metadata(ex: “-2127913662”). Whenever the published metadata changes, this hash is recalculated.

Here’s an example of what your MetadataCache might look like:


public class MetadataCache
{
      private bool MetadataHasChanged
      {
            get
            {
                  //get the most recent timestamp
                  RetrieveTimestampRequest req = new RetrieveTimestampRequest();
                  RetrieveTimestampResponse resp = (RetrieveTimestampResponse)MetadataService2007.Execute(req);

                  //compare it with the last timestamp I retrieved.
                  //Note: I'm not storing the new Timestamp because I'm not loading the Metadata.
                  return resp.Timestamp != _lastTimestamp;
            }
      }
private string _lastTimestamp = string.Empty;
      private CrmMetadata[] _metadata;
      private CrmMetadata[] Metadata
      {
            get
            {
                  //If the Metadata has changed since I last retrieved it, reload it.
                  if (MetadataHasChanged)
                  {
                        RetrieveAllEntitiesRequest req = new RetrieveAllEntitiesRequest();
                        req.MetadataItems = MetadataItems.All; //I want all of the Metadata.
                        req.RetrieveAsIfPublished = false; //I want the published Metadata.
                        RetrieveAllEntitiesResponse resp =  (RetrieveAllEntitiesResponse)MetadataService2007.Execute(req);
                        _metadata = resp.CrmMetadata; //set the Metadata cache.
                        _lastTimestamp = resp.Timestamp; //store the timestamp.
                  }
                  return _metadata;
            }
      }

      public EntityMetadata GetEntity(string entityName)
      {
            foreach (EntityMetadata entity in Metadata)
            {
                  if (entity.LogicalName == entityName)
                  {
                        return entity;
                  }
            }
            throw new ArgumentException("The entity " + entityName + " was not found in the MetadataCache.");
      }
//Add more methods to retrieve Attributes, Relationships, etc...
}


Cheers,


Mark Harrington

Comments (4)

  1. I just wanted to clarify one point. Someone suggested this implies that the 4.0 release is slower than 3.0. That’s not the case. This is describing the web service for accessing Metadata in your own custom applications. The CRM application uses its own MetadataCache, not this web service. What I’m trying to say here is that retrieving Metadata is expensive, and so if your application needs to do it a lot, do what we do and build your own MetadataCache.

  2. Adnan Ali says:

    I have a related question regarding the 2006 endpoints. In case of the using 2006 endpoint for crmservice, the events are generated in the same way they are in 2007 endpoint. I have a case where using the 2006 endpoint, when I SetState of an Appointment, my plugin (registered for SetStateDynamicEntity, Update) is not fired.

  3. Adnan,

    I think you need to register a plugin for SetState as well. This link provides some more detail.  http://code.msdn.microsoft.com/Thread/View.aspx?ProjectName=crmplugin&ThreadId=51

  4. Matthew Yee says:

    Sorry to bring uo an old post. I just wanted to ask if you know if calling teh metadataservcie through crm plugins (ie: IMetadataService _iMetadataService = executionContext.CreateMetadataService(false); makes use of crm internal metadata cache.

    In addition, would you be aware of if when using crmservice in plugings (ICrmService _iCrmService = executionContext.CreateCrmService(false);) is actually calling out through to the webservice or does it have an internal reference to the "core" service implementation such that it can bypass the webservice call (ie: avoid all the http stuff, serilizing etc)…. Hope I'm not sidetracking too far.

Skip to main content