C# 在System.DirectoryServices.AccountManagement中调用UserPrinciapl.GetGroups时出现奇怪的间歇性错误处理错误 背景
我们有一个用C编写的asp.NET4.0Web应用程序,它调用用C编写的.NET3.5Web服务。web服务被传递一个用户id,并根据用户所属的active directory组返回一个数据列表 web服务使用.net 3.5版本的System.DirectoryServices.AccountManagement获取用户所属组的SID 对UserPrincipal.GetGroups的调用间歇性失败,错误如下。两次发生之间有很长的时间间隔,但当它确实发生时,会重复发生几分钟。该问题针对不同的广告用户 这个异常的堆栈跟踪对我们来说毫无意义。我们花了很多时间查看Reflector/ILSpy中的Microsoft广告代码,但除了调用IADsPathName.Retrieve之外,我们没有其他方法 例外情况 要复制的代码 请注意,CausenotSupportDexception方法模拟的代码不是在我们的应用程序中运行的,而是在我们无法控制的环境中其他地方的代码中运行的。 实现流以模拟HttpResponseStream行为C# 在System.DirectoryServices.AccountManagement中调用UserPrinciapl.GetGroups时出现奇怪的间歇性错误处理错误 背景,c#,.net,error-handling,active-directory,C#,.net,Error Handling,Active Directory,我们有一个用C编写的asp.NET4.0Web应用程序,它调用用C编写的.NET3.5Web服务。web服务被传递一个用户id,并根据用户所属的active directory组返回一个数据列表 web服务使用.net 3.5版本的System.DirectoryServices.AccountManagement获取用户所属组的SID 对UserPrincipal.GetGroups的调用间歇性失败,错误如下。两次发生之间有很长的时间间隔,但当它确实发生时,会重复发生几分钟。该问题针对不同的广
public class FakeStream : Stream
{
public override bool CanRead { get { return false; } }
public override bool CanSeek { get { return false; } }
public override bool CanWrite { get { return true; } }
public override void Flush() { }
public override long Length { get { throw new NotSupportedException("No Seek"); } }
public override long Position
{
get { throw new NotSupportedException("No Seek"); }
set { throw new NotSupportedException("No Seek"); }
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new InvalidOperationException("Write only stream");
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException("net_noseek");
}
public override void SetLength(long value) { }
public override void Write(byte[] buffer, int offset, int count) { }
}
问题
我不清楚这是如何发生的。如果您使用的是.NET 3.5或更高版本,您可以使用新的
System.DirectoryServices.AccountManagement
(S.DS.AM)命名空间,这比以前容易得多
请阅读此处的全部内容:[在.NET Framework 3.5中管理目录安全主体][1]
基本上,您需要有一个“主体上下文”(通常是您的域)、一个用户主体,然后您就可以很容易地获得其组:
public List<GroupPrincipal> GetGroups(string userName)
{
List<GroupPrincipal> result = new List<GroupPrincipal>();
// establish domain context
PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);
// find your user
UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username);
// if found - grab its groups
if(user != null)
{
PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();
// iterate over all groups
foreach(Principal p in groups)
{
// make sure to add only group principals or change this to add to a list or varible if needed.
if(p is GroupPrincipal)
{
result.Add(p);
}
}
}
return result;
}
在拨打支持电话后,Microsoft已针对此问题发布了热修复程序。请参阅下面的链接 所述原因是: “出现此问题的原因是System.DirectoryServices.AccountManagement命名空间是本机API Active Directory服务接口(ADSI)的精简包装器。”。IADsPathName接口实现的IErrorInfo接口响应ADSI不会引发的异常。当堆栈上没有ADSI异常时,IErrorInfo接口会引发堆栈顶部的异常,即使该异常由应用程序中的另一个处理程序处理。”
感谢那些提供建议的人。问题,您是否正在尝试查找用户是否属于特定组。。我正试图更好地了解你真正想要的东西。。我可能有一个更好的编码方法的建议。。这里有一个链接也会有帮助,我将在下面粘贴两段代码片段,这将帮助您更轻松地获得所需内容。非常感谢您的回复。我需要的是用户所属组的SID列表。我当前正在使用System.DirectoryServices.AccountManagement命名空间(UserPrincipal.GetGroups位于该命名空间中)。因此,我的代码示例与您在下面发布的代码示例非常相似。我所拥有的代码很好地满足了我的需求,它只是由我试图理解的无关代码引起的间歇性错误。如果您有时间,那么运行示例代码并逐步完成它是值得的。。一开始很难确定你想要什么。。很抱歉,您仍然需要检查该属性或(字符串)属性[“SamaAccountName”][0]。ToString(),因为此时它将是一个对象。。希望这是有意义的…对不起,我发现写这些东西很难提供足够的信息,但仍然很清楚。奇怪的是,当CausenotSupportDexception中出现错误时,它会跳转到GetGroups并抛出异常。如果不查看所有代码,我无法判断有多少种方法可以获得您想要的内容,但我正在尝试为您提供答案,以帮助您解决代码问题,以防您需要修复或重构某些内容
public class FakeStream : Stream
{
public override bool CanRead { get { return false; } }
public override bool CanSeek { get { return false; } }
public override bool CanWrite { get { return true; } }
public override void Flush() { }
public override long Length { get { throw new NotSupportedException("No Seek"); } }
public override long Position
{
get { throw new NotSupportedException("No Seek"); }
set { throw new NotSupportedException("No Seek"); }
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new InvalidOperationException("Write only stream");
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException("net_noseek");
}
public override void SetLength(long value) { }
public override void Write(byte[] buffer, int offset, int count) { }
}
public List<GroupPrincipal> GetGroups(string userName)
{
List<GroupPrincipal> result = new List<GroupPrincipal>();
// establish domain context
PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);
// find your user
UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username);
// if found - grab its groups
if(user != null)
{
PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();
// iterate over all groups
foreach(Principal p in groups)
{
// make sure to add only group principals or change this to add to a list or varible if needed.
if(p is GroupPrincipal)
{
result.Add(p);
}
}
}
return result;
}
public string GetDepartment(Principal principal)
{
string result = string.Empty;
DirectoryEntry de = (principal.GetUnderlyingObject() as DirectoryEntry);
if (de != null)
{
if (de.Properties.Contains("samAccountName"))
{
result = de.Properties["samAccountName"][0].ToString();
}
}
return result;
}
//Change this Method to fit what ever your needs desire..
public string GetDepartment(string username)
{
string result = string.Empty;
// if you do repeated domain access, you might want to do this *once* outside this method,
// and pass it in as a second parameter!
PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);
// find the user
UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username);
// if user is found
if(user != null)
{
// get DirectoryEntry underlying it
DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry);
if (de != null)
{
if (de.Properties.Contains("department"))
{
result = de.Properties["department"][0].ToString();
}
}
}
return result;
}