我有一个在 Windows 服务下运行的 C# .NET 6 控制台应用程序,该应用程序使用
DirectorySearcher
来确定联系人(从 CRM 的 SQL 数据库读取)当前是否也存在于 Active Directory 中。即使多次重复完全相同的搜索,从 DirectorySearcher
返回的结果也不一致(本质上,搜索有时会找到联系人,有时找不到联系人,即使它存储在搜索的 OU 中)。
然后,我创建了一个作为计划任务运行的 C# .NET 6 控制台测试应用程序。它隔离故障应用程序中使用的完全相同的搜索代码,并对输入的搜索条件重复相同的搜索三次。该应用程序始终返回准确的搜索结果。 (由于 gMSA 提供的凭据以及需要输入电子邮件 ID 进行测试,测试应用程序是一项计划任务。)
这是出现故障的应用程序和正常运行的测试应用程序中使用的代码:
public (bool ContactExists, DirectoryEntry DirectoryEntryObjectNullIfFalse) ADContactExists(int srcId, long emailId, bool shortEmailIdNeedsConversion, bool searchExceptionsPath = false)
{
#if STAGING || DEBUG
string searchPath = configuration.GetValue<string>("ActiveDirectory:StagingAdsSearchPath");
#else
string searchPath = App_Configuration.GetAdsClientsPath();
#endif
if (searchExceptionsPath)
searchPath = App_Configuration.GetAdsExceptionsPath();
using (DirectoryEntry rootDirectoryEntry = App_Configuration.GetCredentialedDirectoryEntry(false, searchPath))
{
using (DirectorySearcher ds = new DirectorySearcher(rootDirectoryEntry))
{
ds.SearchScope = SearchScope.OneLevel;
long longEmailId = 0;
if (shortEmailIdNeedsConversion)
longEmailId = InterActionShortIdConversions.ConvertToLongInterActionID(srcId, emailId);
else
longEmailId = emailId;
ds.Filter = GetFilter("extensionAttribute8", "=", longEmailId.ToString());
ds.PropertiesToLoad.Add("extensionAttribute8"); //InterAction Email ID (Converted Long Form)
SearchResult sr = ds.FindOne();
if (sr != null)
{
//Update existing Active Directory contact
DirectoryEntry directoryEntryResult = App_Configuration.GetCredentialedDirectoryEntry(false, sr.Path);
return (true, directoryEntryResult);
}
else
{
//Create new Active Directory contact
DirectoryEntry directoryEntryResult = new DirectoryEntry();
return (false, directoryEntryResult);
}
}
}
}
public string GetFilter(string property, string comparisonOperator, string propertyValue)
{
string filter = "(&(objectCategory=person)(objectClass=contact)(" + property + comparisonOperator + propertyValue + "))";
return filter;
}
System.DirectoryServices
NServiceBus和
Quartz.NET,故障应用程序具有一些异步 (
async
await
) 代码,但大多数是同步的。话虽这么说,异步代码确实调用了一些同步方法,然后调用 DirectorySearcher
代码。如果有人认为异步代码可能以某种方式影响 Active Directory 搜索,我会提到这一点。非常感谢您为
DirectorySearcher
持续返回准确结果提供的所有帮助。
该问题是由异步填充和读取 C#
Dictionary
引起的。由于某些线程会在完全填充之前访问Dictionary
,因此有时会向 Active Directory 搜索提交不正确的信息(例如空值),从而导致检索到不正确的结果。
我尝试使用
ConcurrentDictionary
来纠正这个问题,如SO帖子在从读取字典内容的线程访问之前通过条件参数以异步方式填充C#字典中详细介绍的那样,但是这对于我的用例来说是不可能的,所以我最终重写了受影响方法的逻辑并完全删除 Dictionary
。一旦我这样做了,DirectorySearcher
始终返回准确的结果。