针对 Windows® 平台,Microsoft 提供了三个主要目录平台:Active Directory® 域服务、每台 Windows 计算机上的本地安全帐户管理器 (SAM) 数据存储,以及比较新的 Active Directory 轻型目录服务或 AD LDS(即您先前已经知道的 Active Directory 应用程序模式或简称 ADAM)。这篇博文不是讲活动目录的使用,具体可以参照MSDN一篇文章专门介绍活动目录的编程http://msdn.microsoft.com/zh-cn/magazine/cc135979.aspx。
本文主要是记录使用GetAuthorizationGroups()接口或用用户的时候经常抛出的一个错误:具体可以看Microsoft Connect http://connect.microsoft.com/VisualStudio/feedback/details/566463/attempted-to-access-an-unloaded-appdomain-exception-from-hresult-0x80131014-when-calling-getauthorizationgroups。
微软并没有给出解决方案,在stackoverflow 上也有讨论到这个问题 http://stackoverflow.com/questions/5895128/attempted-to-access-an-unloaded-appdomain-when-using-system-directoryservices。
在stackoverflow上的讨论中有了一种解决方案,再发生AppDomainUnloadedException 错误的时候,通过休眠一段时间重新调用这个接口:
private PrincipalSearchResult<Principal> GetAuthorizationGroups(UserPrincipal userPrincipal, int tries) { try { return userPrincipal.GetAuthorizationGroups(); } catch (FileNotFoundException ex) { if (tries > 5) throw; tries++; Thread.Sleep(1000); return GetAuthorizationGroups(userPrincipal, tries); } catch (AppDomainUnloadedException ex) { if (tries > 5) throw; tries++; Thread.Sleep(1000); return GetAuthorizationGroups(userPrincipal, tries); }}
这样就会造成一个问题,如果发生了异常,接口就非常的慢了。这可以通过引入缓存机制来解决:
public override String[] GetRolesForUser(String username){ // If SQL Caching is enabled, try to pull a cached value. if (_EnableSqlCache) { String CachedValue; CachedValue = GetCacheItem('U', username); if (CachedValue != "*NotCached") { return CachedValue.Split(','); } } ArrayList results = new ArrayList(); using (PrincipalContext context = new PrincipalContext(ContextType.Domain, null, _DomainDN)) { try { UserPrincipal p = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username); var tries = 0; var groups = GetAuthorizationGroups(p, tries); foreach (GroupPrincipal group in groups) { if (!_GroupsToIgnore.Contains(group.SamAccountName)) { if (_IsAdditiveGroupMode) { if (_GroupsToUse.Contains(group.SamAccountName)) { results.Add(group.SamAccountName); } } else { results.Add(group.SamAccountName); } } } } catch (Exception ex) { throw new ProviderException("Unable to query Active Directory.", ex); } } // If SQL Caching is enabled, send value to cache if (_EnableSqlCache) { SetCacheItem('U', username, ArrayListToCSString(results)); } return results.ToArray(typeof(String)) as String[];}
上面的代码来自于Active Directory Roles Provider。