Making repetitive requests to the MetadataService Web service can have a negative impact on performance. Further, the metadata information does not change frequently. As such, many developers create a cache of the data retrieved from MetadataService inside their own applications.
The RetrieveAllEntitiesResponse class has a Timestamp property that indicates the last time the metadata was updated. When building a cache you should compare the current timestamp with the one stored with your cache and refresh your cache appropriately. The timestamp can also be queried on the server using the RetrieveTimestampRequest. Developers should retrieve metadata using RetrieveAllEntitiesRequest and cache the RetrieveAllEntitiesResponse in their application. Periodically the application should then use RetrieveTimestampRequest to check for metadata updates. If the timestamp retrieved doesn’t match the timestamp in the cache, the cache can be invalidated and refreshed from CRM.
You will see a vast performance difference in retrieving the timestamp versus retrieving all entities in terms of operation time and server load. You should execute RetrieveAllEntities- Request sparingly.
In this scenario, a basic console application has been programmed to store a cache of meta-data on the disk. Each time the application runs, it checks CRM to see whether the cache needs to be updated.
This basic example uses XML object serialization to store the metadata cache. The cache, in this example, is all entities in the organization. When the cache is first generated, it is saved to the disk. Each time the application checks the cache it first retrieves the timestamp from CRM and compares this to the timestamp in the cache. If the timestamps don’t match, the application retrieves the entity metadata from CRM and writes a new cache to the file system.
Example 8-2 displays the complete code for this application. The application will require appropriate Web Service WSDLs for the MetadataService and the CrmDiscoveryService.
Example 8-2. Sample metadata file system cache
using System;using System.IO; using System.Xml; using System.Xml.Serialization; using Example23.CrmDisco; using Example23.CrmMeta; namespace MetadataSample { class Program { static void Main(string[] args) { #region Set Sample App Variables string orgName = "contoso"; string discoveryServiceUrl = "http://crm/mscrmservices/2007/ad/crmdiscoveryservice.asmx"; string metadataServiceUrl = string.Empty; string cachePath = "cache.xml"; #endregion #region Check Metadata URL with the Discovery Service CrmDiscoveryService discoveryService = new CrmDiscoveryService(); discoveryService.UseDefaultCredentials = true; discoveryService.Url = discoveryServiceUrl; RetrieveOrganizationsRequest retrieveOrgRequest = new RetrieveOrganizationsRequest(); RetrieveOrganizationsResponse retrieveOrgResponse; retrieveOrgResponse = (RetrieveOrganizationsResponse) discoveryService.Execute(retrieveOrgRequest); foreach (OrganizationDetail orgDetail in retrieveOrgResponse.OrganizationDetails) { if (orgDetail.OrganizationName == orgName) { metadataServiceUrl = orgDetail.CrmMetadataServiceUrl; break; } } #endregion #region Create Metadata Service Object CrmAuthenticationToken token = new CrmAuthenticationToken(); token.AuthenticationType = 0; token.OrganizationName = orgName; MetadataService metadataService = new MetadataService(); metadataService.CrmAuthenticationTokenValue = token; metadataService.UseDefaultCredentials = true; metadataService.Url = metadataServiceUrl; #endregion #region Creating Your Own Cache //Check the TimeStamp RetrieveTimestampRequest timestampRequest = new RetrieveTimestampRequest(); RetrieveTimestampResponse timestampResponse; timestampResponse = (RetrieveTimestampResponse) metadataService.Execute(timestampRequest); //This object represents the Cache in memory RetrieveAllEntitiesResponse metadataCache = new RetrieveAllEntitiesResponse(); //Does the Cache Exist? if (File.Exists(cachePath)) { //Retrieve Cache the Cache metadataCache = RetrieveCache(cachePath); //Check Freshness of the Cache if (metadataCache.Timestamp != timestampResponse.Timestamp) { File.Delete(cachePath); metadataCache = CreateCache(cachePath, metadataService); } } else { //Create a New Cache metadataCache = CreateCache(cachePath, metadataService); } //Write the Logical Name of each entity to the Console foreach (EntityMetadata entity in metadataCache.CrmMetadata) { Console.WriteLine(entity.LogicalName); } #endregion } //Private Method to Retrieve the Metadata from CRM and Cache It private static RetrieveAllEntitiesResponse CreateCache( string cachePath, MetadataService metadataService) { RetrieveAllEntitiesRequest retrieveAllRequest = new RetrieveAllEntitiesRequest(); retrieveAllRequest.RetrieveAsIfPublished = false; retrieveAllRequest.MetadataItems = MetadataItems.All; RetrieveAllEntitiesResponse retrieveAllResponse; retrieveAllResponse = (RetrieveAllEntitiesResponse) metadataService.Execute(retrieveAllRequest); Console.WriteLine("Retrieved from CRM"); using (XmlWriter writer = XmlWriter.Create(cachePath)) { XmlSerializer serializer = new XmlSerializer(typeof(RetrieveAllEntitiesResponse)); serializer.Serialize(writer, retrieveAllResponse); } return retrieveAllResponse; } //Private Method to Retrieve the Metadata from the Cache private static RetrieveAllEntitiesResponse RetrieveCache(string cachePath) { using (XmlReader reader = XmlReader.Create(cachePath)) { XmlSerializer deserializer = new XmlSerializer(typeof(RetrieveAllEntitiesResponse)); return (RetrieveAllEntitiesResponse) deserializer.Deserialize(reader); } } } }