Memory leaks System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity出现奇怪问题

Memory leaks System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity出现奇怪问题,memory-leaks,active-directory,ldap,directoryservices,account-management,Memory Leaks,Active Directory,Ldap,Directoryservices,Account Management,我们正在编写一个系统,允许用户通过内部网上的web应用程序更改其帐户密码 起初,一切似乎都进展顺利。在开发过程中,可以毫无问题地更改测试帐户的密码 然而,当我们让系统上线时,我们开始遇到问题。以下是症状: 起初,一切都很好。使用者 可以更改他们的密码 有时 在这一点上,以下错误发生在 UserPrincipal.FindByIdentity: “System.Runtime.InteropServices.COMException: 身份验证机制是 未知。” 从那时起,努力 通过网络更改密码 应

我们正在编写一个系统,允许用户通过内部网上的web应用程序更改其帐户密码

起初,一切似乎都进展顺利。在开发过程中,可以毫无问题地更改测试帐户的密码

然而,当我们让系统上线时,我们开始遇到问题。以下是症状:

  • 起初,一切都很好。使用者 可以更改他们的密码
  • 有时 在这一点上,以下错误发生在 UserPrincipal.FindByIdentity: “System.Runtime.InteropServices.COMException: 身份验证机制是 未知。”
  • 从那时起,努力 通过网络更改密码 应用程序导致错误: “System.Runtime.InteropServices.COMException: 服务器无法运行。“
  • 如果我手动回收应用程序池, 一切似乎都会自行修复,直到 更多的错误开始发生。。。即。, 这一过程从一开始就重新开始 第一阶段
  • 以下是相关的代码片段:



    关于为什么会发生这种情况,有什么线索吗?谷歌搜索没有发现任何真正有用的东西,MSDN上的文档也没有。

    我注意到的第一件事是,您使用的是继承自的。我之所以这样说,是因为
    Principal
    类在
    FindByIdentity
    中存在已知的内存泄漏。如果你看一下这个,你会注意到在底部,微软说:

    此调用存在非托管内存泄漏 因为底层的实现 使用DirectorySearcher和 SearchResultsCollection,但没有 打电话到 SearchResultsCollection作为 文件描述了

    我猜这是你的问题。内存泄漏会导致应用程序池填满,并最终导致错误,直到应用程序池重置并释放内存

    当我们使用任何active directory功能时,我们使用以下方法来完成用户密码的设置:

    Public Shared Function GetUserAccount(ByVal username As String) As DirectoryEntry
        Dim rootPath As String = GetRootPath()
        Using objRootEntry As New DirectoryEntry(rootPath)
            Using objAdSearcher As New DirectorySearcher(objRootEntry)
                objAdSearcher.Filter = "(&(objectClass=user)(samAccountName=" & username & "))"
                Dim objResult As SearchResult = objAdSearcher.FindOne()
                If objResult IsNot Nothing Then Return objResult.GetDirectoryEntry()
            End Using
        End Using
        Return Nothing
    End Function
    
    Public Shared Sub SetPassword(ByVal username As String, ByVal newPassword As String)
        Using objUser As DirectoryEntry = GetUserAccount(username)
            If objUser Is Nothing Then Throw New UserNotFoundException(username)
            Try
                objUser.Invoke("SetPassword", newPassword)
                objUser.CommitChanges()
            Catch ex As Exception
                Throw New Exception("Could not change password for " & username & ".", ex)
            End Try
        End Using
    End Sub
    

    此外,如果你想让用户直接更改密码,而不想依赖他们的诚实,你可能想考虑使用LDAP这样的<代码> CuxEpasWord < /Case>函数:

    Public Shared Sub ChangePassword(ByVal username As String, ByVal oldPassword As String, ByVal newPassword As String)
        Using objUser As DirectoryEntry = GetUserAccount(username)
            If objUser Is Nothing Then Throw New UserNotFoundException(username)
            Try
                objUser.Invoke("ChangePassword", oldPassword, newPassword)
                objUser.CommitChanges()
            Catch ex As TargetInvocationException
                Throw New Exception("Could not change password for " & username & ".", ex)
            End Try
        End Using
    End Sub
    
    这会强制用户在更改为新密码之前知道先前的密码

    我希望这有帮助


    谢谢你对ActiveDirectoryManagementAccountName有什么建议?请尝试将其设置为“域\用户名”而不仅仅是“用户名”-这在过去对我很有效。我会尝试,尽管我怀疑这是问题所在。如果错误不是断断续续的,我更可能怀疑这种性质的问题。这段代码运行良好,直到一些看似随机的东西触发了螺旋形死亡虫洞。如果帐户名有问题,我会怀疑会出现一致的错误。然而,我们谈论的是System.DirectoryServices。。。因此,任何一种令人讨厌的奇怪现象都是可能的;)肯定有帮助。我们已经安装了一个修补程序,据说它解决了FindByIdentity的一些(但不是全部)问题,现在正在测试我们的代码。虽然我们更喜欢使用ChangePassword方法,但不幸的是,我们的域中有一些有趣的东西,它们强制执行我们不想要的密码规则。SetPassword绕过这些规则。如果我们当前修复现有代码的尝试不起作用,下一步将是直接使用System.DirectoryServices(无AccountManagement内容)重写它,正如您所演示的。Nick,当我实现上述方法时,它似乎还检查域用户帐户密码策略。我想这就是它的工作原理,因为在引擎盖下,它使用相同的方法。另外,看看这篇MSDN文章:您可以看到SetPassword可以生成一个
    PasswordException
    。它还声明,如果新密码不满足密码复杂性要求,它将抛出此错误。希望这有帮助!在引擎盖下,ChangePassword正在调用DirectoryEntry.Invoke(“ChangePassword”,password)。SetPassword正在调用DirectoryEntry.Invoke(“SetPassword”,password)。在使用ChangePassword时,我们的策略是强制执行的(比如不允许重复使用过去的密码)。它们不使用SetPassword强制执行。使用SetPassword,如果我有正确的权限,我可以将任何人的帐户密码设置为我喜欢的任何密码。如果你看这里:你会注意到其他人也发现了这一点。MSDN文档在这方面有误导性。尼克-这是您所指的热修复程序吗?-JeffI有一个类似的问题,我已经发布了。如果你们中有人找到了解决办法。请评论这篇文章。
    Public Shared Sub ChangePassword(ByVal username As String, ByVal oldPassword As String, ByVal newPassword As String)
        Using objUser As DirectoryEntry = GetUserAccount(username)
            If objUser Is Nothing Then Throw New UserNotFoundException(username)
            Try
                objUser.Invoke("ChangePassword", oldPassword, newPassword)
                objUser.CommitChanges()
            Catch ex As TargetInvocationException
                Throw New Exception("Could not change password for " & username & ".", ex)
            End Try
        End Using
    End Sub