简体   繁体   English

MS Dynamics 365 C# 审核历史记录 KeyNotFoundException

[英]MS Dynamics 365 C# audit history KeyNotFoundException

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.我特别需要提取名为 Credit Limit 的 Changed Field 的所有结果。

In order to do this, I have the following code in C#:为了做到这一点,我在 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然后它在异常时中断,在 Visual Studio 中告诉我

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();

You have to group the statements inside {} if there are more than one statement to execute based on if condition.如果根据if条件执行多个语句,则必须将{}中的语句分组。

if (attributeDetail.OldValue.Contains("credit_limit"))
{
        oldValue = attributeDetail.OldValue["credit_limit"].ToString();
        Console.WriteLine("old value: " + oldValue);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM