/// <summary>
        /// Parse CRM response to get list of updated entities with timestamps and list of updated records
        /// </summary>
        /// <param name="responseCollection">Dictionary for entityName and its RetrieveEntityChange response to parse</param>
        /// <returns>List of updated records</returns>
        private TimeBasedChangedData ParseBusinessEntityChangesResponse(Dictionary <string, RetrieveEntityChangesResponse> responseCollection, CrmDbContext context, Guid websiteId)
        {
            if (responseCollection == null || responseCollection.Count == 0)
            {
                return(null);
            }
            var changedData = new TimeBasedChangedData
            {
                UpdatedEntitiesWithLastTimestamp = new Dictionary <string, string>(),
                UpdatedEntityRecords             = new List <IChangedItem>()
            };

            foreach (var kvp in responseCollection)
            {
                var entityName = kvp.Key;
                var dataToken  = kvp.Value.EntityChanges.DataToken;

                ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("RetrieveEntityChangesResponse received for entity: {0} with new data token: {1}", entityName, dataToken));
                KeyValuePair <string, string>?entityNameWithTimestamp = new KeyValuePair <string, string>(entityName, dataToken);

                if (changedData.UpdatedEntitiesWithLastTimestamp.ContainsKey(entityNameWithTimestamp.Value.Key))
                {
                    continue;
                }
                changedData.UpdatedEntitiesWithLastTimestamp.Add(entityNameWithTimestamp.Value.Key, entityNameWithTimestamp.Value.Value);
            }

            changedData.UpdatedEntityRecords.AddRange(this.GetChangesRelatedToWebsite(responseCollection, context, websiteId));

            return(changedData);
        }
Example #2
0
        /// <summary>
        /// Logs telemetry for the message processing for each entity record.
        /// Includes how long total it took from update in CRM to update in Portal
        /// </summary>
        /// <param name="pushedToCache">Time at which the records wer pushed to the cache</param>
        /// <param name="processingRecords">Messages that have notified the portal of changes from Azure</param>
        /// <param name="crmQueryResults">Record changes from CRM</param>
        /// <param name="timeStampTable">Timestamps of records before this current batch updated</param>
        private void LogTimeTelemetry(DateTime pushedToCache, Dictionary <string, EntityRecordMessage> processingRecords, TimeBasedChangedData crmQueryResults, Dictionary <string, string> timeStampTable)
        {
            var filteredProcessingRecords = processingRecords.Where(item => item.Value.MessageType == MessageType.Create || item.Value.MessageType == MessageType.Update);
            var filteredCrmQueryResults   = crmQueryResults.UpdatedEntityRecords.OfType <Microsoft.Xrm.Sdk.NewOrUpdatedItem>()
                                            // Only add telemetry for non-initial load entities (timestamp already has been recorded.
                                            // This will avoid awful timespan values being captured on initial startup
                                            .Where(filteredResult => timeStampTable.ContainsKey(filteredResult.NewOrUpdatedEntity.LogicalName)
                                            // Timestamp table stores string dataTokens from CRM in the form of 123456!04/04/2004 04:04:04.04
                                        ? filteredResult.NewOrUpdatedEntity.GetAttributeValue <DateTime>("modifiedon") > DateTime.Parse(timeStampTable[filteredResult.NewOrUpdatedEntity.LogicalName].Split('!')[1])
                                        : false);

            IEnumerable <TimeTrackingEntry> entries = filteredProcessingRecords.Join(
                // With list
                filteredCrmQueryResults,
                // Keys
                processingRecord => processingRecord.Key,
                crmQueryResult => crmQueryResult.NewOrUpdatedEntity.LogicalName,
                // How to join
                (processingRecord, crmqueryResult) => new TimeTrackingEntry(
                    processingRecord.Key, pushedToCache,
                    crmqueryResult.NewOrUpdatedEntity.GetAttributeValue <DateTime>("modifiedon"),
                    processingRecord.Value.Received));

            entries.ToList().ForEach(traceEntry =>
            {
                ADXTrace.Instance.TraceInfo(TraceCategory.Application,
                                            string.Format("Overall the '{0}' change took {1} to propagate\n\tMessage to reach portal through Azure: {2}\n\tSleep and Retreival of change from CRM: {3}",
                                                          traceEntry.EntityLogicalName,
                                                          traceEntry.OverallDelta,
                                                          traceEntry.AzureProcessingDelta,
                                                          traceEntry.InvalidationDelta));
            });
        }