C# Windows服务LdapException:LDAP服务器不可用

C# Windows服务LdapException:LDAP服务器不可用,c#,.net,active-directory,ldap,principalcontext,C#,.net,Active Directory,Ldap,Principalcontext,我有一个Windows服务,它通过WCF向Windows窗体应用程序提供数据。该服务还负责用户身份验证,通过公司Active Directory服务器使用LDAP验证用户密码 问题是,它可以工作数周(甚至数月),而不是发生一些事情,LDAP用户身份验证失败,出现以下异常,直到我重新启动服务: System.DirectoryServices.AccountManagement.PrincipalServerDownException: The server could not be contac

我有一个Windows服务,它通过WCF向Windows窗体应用程序提供数据。该服务还负责用户身份验证,通过公司Active Directory服务器使用LDAP验证用户密码

问题是,它可以工作数周(甚至数月),而不是发生一些事情,LDAP用户身份验证失败,出现以下异常,直到我重新启动服务:

System.DirectoryServices.AccountManagement.PrincipalServerDownException: The server could not be contacted. 
---> System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.     
at System.DirectoryServices.Protocols.LdapConnection.Connect()     
at System.DirectoryServices.Protocols.LdapConnection.SendRequestHelper(DirectoryRequest request, Int32& messageID)     
at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout)     
at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request)     
at System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties)    
 --- End of inner exception stack trace ---     
 at System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties)     
 at System.DirectoryServices.AccountManagement.PrincipalContext.DoServerVerifyAndPropRetrieval()     
 at System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name, String container, ContextOptions options, String userName, String password)     
 at System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name, String userName, String password)     
 at SMSTModel.Authentication.ActiveDirectory.IsUserAllowed(String username, String password)
服务重新启动修复了该问题

public static bool IsUserAllowed(string username, string password)
{
    String localDomain = Domain.GetComputerDomain().Name;
    string userDomain = null;
    string user = username;
    if (user.Contains(@"\"))
    {
        userDomain = user.Substring(0, user.IndexOf("\\"));
        user = user.Substring(user.IndexOf("\\") + 1);
    }

    userDomain = userDomain != null ? userDomain : localDomain;
    using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, userDomain, user, password))
    {
        bool credOk = pc.ValidateCredentials(user, password);
        if (!credOk)
            return false;
        using (UserPrincipal userP = UserPrincipal.FindByIdentity(pc, user))
        {
            if (userP != null)
            {
                using (PrincipalContext pc1 = new PrincipalContext(ContextType.Domain, localDomain))
                {
                    using (GroupPrincipal groupPrincipal = new GroupPrincipal(pc1))
                    {
                        groupPrincipal.Name = "APP_*";
                        using (PrincipalSearcher principalSearcher = new PrincipalSearcher(groupPrincipal))
                            foreach (Principal found in principalSearcher.FindAll())
                            {
                                if (found.Name == "APP_Group" && found is GroupPrincipal && userP.IsMemberOf((GroupPrincipal)found))
                                {
                                    return true;
                                }
                            }
                    }
                }
            }
        }
    }

    return false;
}

你知道为什么会发生这种情况以及如何解决吗?

这里似乎发生了异常:

using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, userDomain, user, password))
那么您知道正在使用的
userDomain
是什么吗?看起来您的环境中可能有多个域,那么您的所有域都会出现这种情况,还是只有一个域

在我们的环境中,我见过广告管理员停用域控制器的情况,但出于某种原因,该服务器仍然显示在DNS中。换句话说,如果我在命令行中执行DNS查找:

nslookup example.com
其中一个IP用于退役DC

这在你的情况下是有可能的。如果它选择了一个错误的IP地址,那么重新启动应用程序将使它执行另一个DNS查找,这可能会在列表的顶部返回一个不同的IP地址,然后事情将再次工作


要弄清这一点,你必须观察它停止工作时发生了什么。如果尚未安装,请在服务器上安装。当它停止工作时,使用Wireshark使用端口389(默认LDAP端口)查找流量,并查看它正试图连接到哪个IP。

谢谢您的回答。我100%确信所使用的域始终是相同的(其他可用域仅用于管理目的,普通用户不使用它们)。当问题出现时,我们的网络团队似乎什么也没做(它开始在团队工作时间之外产生问题),所以我排除了广告配置中的更改。我将尝试使用WireShark监控此情况(当再次发生时),但我不确定是否允许在我们的DC上安装它。您不需要在DC上安装WireShark。在运行此代码的服务器上安装它。可能有几个原因。第一个问题很明显-服务器没有响应或出现一些网络问题。第二个是dc限制策略与dos攻击。当您创建到dc an的连接,然后将其弃置时,它可能不会在发动机罩下关闭。例如,如果您在短时间内发出大量广告请求,则会出现此错误。在这两种情况下,当您重新启动服务时,您可能会通过dc定位器服务连接到一个新的dc。为避免这种情况,我建议您做两件事。1.创建并缓存一个到域的连接(例如到rootdse分区)。2.连接到域控制器,而不是域控制器。如果遇到此错误,只需使用“强制重新发现”选项查找新dc