I am trying to pull the audit history of a specific account as demonstrated by an example here:
I specifically need to pull all the results for the Changed Field called Credit Limit.
In order to do this, I have the following code in C#:
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Tooling.Connector;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PowerApps.Samples
{
public partial class SampleProgram
{
[STAThread] // Added to support UX
static void Main(string[] args)
{
CrmServiceClient service = null;
service = SampleHelpers.Connect("Connect");
if (!service.IsReady)
Console.WriteLine("No Connection was Made.");
Console.WriteLine("Connected");
//Create a new RetrieveAttributeChangeHistoryRequest
RetrieveAttributeChangeHistoryRequest req = new RetrieveAttributeChangeHistoryRequest();
//Set the target Entity
req.Target = new EntityReference("new_case", new Guid("468f8db5-4f98-eb11-57ee-0006ffc2587a"));
//Set the attribute you want to retrieve specifically
req.AttributeLogicalName = "credit_limit";
//Execute the request against the OrgService
RetrieveAttributeChangeHistoryResponse resp = (RetrieveAttributeChangeHistoryResponse)service.Execute(req);
AuditDetailCollection details = resp.AuditDetailCollection;
Console.WriteLine("Before the loop");
//Iterate through the AuditDetails
foreach (var detail in details.AuditDetails)
{
Console.WriteLine("Inside the loop");
//Important: the AuditDetailCollection.AuditDetails doesn’t always contain the type of AttributeAuditDetail, so make sure it is of correct type before casting
if (detail.GetType() == typeof(AttributeAuditDetail))
{
AttributeAuditDetail attributeDetail = (AttributeAuditDetail)detail;
String oldValue = "(no value)", newValue = "(no value)";
if (attributeDetail.OldValue.Contains("credit_limit"))
Console.WriteLine("old value: "+oldValue);
oldValue = attributeDetail.OldValue["credit_limit"].ToString();
if (attributeDetail.NewValue.Contains("credit_limit"))
Console.WriteLine("new value: "+newValue);
newValue = attributeDetail.NewValue["credit_limit"].ToString();
//TODO: Use the old value and new value in the Business Logic
}
}
Console.WriteLine("After the loop");
Console.ReadLine();
}
}
}
What happens is that I get the following result in the command line:
Connected
Before the loop
Inside the loop
old value: (no value)
new value: (no value)
Inside the loop
And then it breaks on exception, telling me in Visual Studio that
System.Collections.Generic.KeyNotFoundExemption: The given key was not present in the dictionary.
Can someone clarify what it is that I am doing wrong and what I can do to fix it?
The problem is you are checking if "new value" and "old value" contain your attribute but then trying to use it even if it is false.
I made a slight change to your code and it works as expected.
//Create a new RetrieveAttributeChangeHistoryRequest
RetrieveAttributeChangeHistoryRequest req = new RetrieveAttributeChangeHistoryRequest();
//Set the target Entity
req.Target = new EntityReference("new_case", new Guid("468f8db5-4f98-eb11-57ee-0006ffc2587a"));
//Set the attribute you want to retrieve specifically
req.AttributeLogicalName = "credit_limit";
//Execute the request against the OrgService
RetrieveAttributeChangeHistoryResponse resp = (RetrieveAttributeChangeHistoryResponse)crmService.Execute(req);
AuditDetailCollection details = resp.AuditDetailCollection;
Console.WriteLine("Before the loop");
//Iterate through the AuditDetails
foreach (var detail in details.AuditDetails)
{
Console.WriteLine("Inside the loop");
//Important: the AuditDetailCollection.AuditDetails doesn’t always contain the type of AttributeAuditDetail, so make sure it is of correct type before casting
if (detail.GetType() == typeof(AttributeAuditDetail))
{
AttributeAuditDetail attributeDetail = (AttributeAuditDetail)detail;
String oldValue = "(no value)", newValue = "(no value)";
if (attributeDetail.OldValue.Contains("credit_limit"))
oldValue = attributeDetail.OldValue["credit_limit"].ToString();
Console.WriteLine("old value: " + oldValue);
if (attributeDetail.NewValue.Contains("credit_limit"))
newValue = attributeDetail.NewValue["credit_limit"].ToString();
Console.WriteLine("new value: " + newValue);
//TODO: Use the old value and new value in the Business Logic
}
}
Console.WriteLine("After the loop");
Console.ReadLine();