在系统中查找用户是否存在的更快方法?

10
每次应用程序启动时,我都会检查用户是否存在(如果不存在则创建)。具体操作如下:

bool bUserExists = false;
DirectoryEntry dirEntryLocalMachine = 
    new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");

DirectoryEntries dirEntries = dirEntryLocalMachine.Children;

foreach (DirectoryEntry dirEntryUser in dirEntries)
{
    bUserExists = dirEntryUser.Name.Equals("UserName", 
        StringComparison.CurrentCultureIgnoreCase);

    if (bUserExists)
      break;
}

问题出现在大多数部署系统上。这可能需要6-10秒,时间太长了...我需要找到一种方式来尽可能地减少这个时间。是否有更好或更快的方法可以用来验证用户是否存在于系统中?
我知道还有其他解决方法,比如让其他应用程序休眠10秒,或者让这个工具在准备好时发送消息等等...但是如果我能大大缩短找到用户所需的时间,那么我的生活将变得更加轻松。

你正在寻找本地机器上的用户吗? - Philip Wallace
您的用户需要在应用程序完成启动之前存在吗? - Aaron M
是的,应用程序会检查它是否存在,如果不存在则创建它...这很好 - 唯一的问题是检查需要很长时间。 - Shaitan00
4个回答

26

.NET 3.5支持位于System.DirectoryServices.AccountManagement命名空间下的新的AD查询类。

要使用它,您需要将“System.DirectoryServices.AccountManagement”添加为引用并添加using语句。

using System.DirectoryServices.AccountManagement;


using (PrincipalContext pc = new PrincipalContext(ContextType.Machine))
{
    UserPrincipal up = UserPrincipal.FindByIdentity(
        pc,
        IdentityType.SamAccountName,
        "UserName");

    bool UserExists = (up != null);
}

< .NET 3.5

在.NET 3.5版本之前,我在dotnet-snippets找到了一个简洁的示例。

DirectoryEntry dirEntryLocalMachine =
    new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");

bool UserExists =
    dirEntryLocalMachine.Children.Find(userIdentity, "user") != null;

很遗憾,我不能使用.NET 3.5,我只能使用.NET 2.0... 有没有相应的替代方案? - Shaitan00
我更新了我的答案,包括一篇关于你所寻找的内容的好文章。它与你当前的方法非常相似,但是它不是枚举每个对象,而是使用Children.Find()函数。请点击链接,因为这篇文章有一个完整的类来处理这个问题,而且非常好用。 - Michael La Voie
很遗憾,我不知道其他未被提及的解决方案。当然,您可以重新评估是否需要每次调用该逻辑或者它是否需要在启动时调用。也许将其放入线程中以让用户开始工作?否则,感知起着重要作用,使用指数加速的进度条(即:前两秒缓慢,接下来两秒中等速度,最后两秒超快)可以创造出快速加载的感觉。如果所有其他方法都失败了,请尝试这个:http://stackoverflow.com/questions/182112/funny-loading-statements-to-keep-users-amused - Michael La Voie

6
你想使用DirectorySearcher。
类似这样:
static bool userexists( string strUserName ) {
    string adsPath = string.Format( @"WinNT://{0}", System.Environment.MachineName );
    using( DirectoryEntry de = new DirectoryEntry( adsPath ) ) {
        try {
            return de.Children.Find( strUserName ) != null;
        } catch( Exception e ) {
            return false;
        }
    }
}

这样应该会更快。此外,如果你只是检查是否存在,则可以减少属性。


这是一种快速的方法,并且它适用于 .NET 版本 3.5 之前的环境(如果您使用的是这个版本)。 - Michael La Voie
我对DirectoryEntry(活动目录等)不是很熟悉,如果我只有用户名作为依据,哪些属性不需要100%确定用户是否已经存在? - Shaitan00
实际上,不包括任何内容就可以了。我只是举了一个通用的例子,以防您也想了解它们的信息。因此,过滤器是您想要的,然后是搜索结果。 - Beached
存在一些问题,例如字符串strDomainName使用了ds,但是ds稍后才被创建并使用de,而de又使用了strDomainName(循环问题)... - Shaitan00
我对DirectorySearcher的理解是错误的。它只能与AD一起使用。我已经更新了解决方案,使用DirectoryEntry对象上的Find方法。 - Beached

1
另一种方法如下(支持本地或域用户):
bool UserExists(string userName)
{
    var user = new NTAccount(userName);
    try
    {
        var sid = (SecurityIdentifier)user.Translate(typeof(SecurityIdentifier));
        return true;
    }
    catch (IdentityNotMappedException)
    {
        return false;
    }
}

用户可能是未经过资格认证的,也可能通过机器/域名(DOMAIN\UserName)进行了资格认证。如果您需要明确检测帐户是否存在于本地计算机上,请使用Environment.MachineName进行限定($"{Environment.MachineName}\\{userName}")。

0
在命令提示符中输入以下内容,如果“用户名”存在,则返回1。
net user | find "username" /c

1
这与在C#中查找用户是否存在有什么关系? - Ken White
它可以被C#使用,但我担心这不是最优雅的解决方案。 - Henri
我不想启动命令行来使用net user,最好使用C#来完成。 - Shaitan00
@Henri:好的,你可以使用它。你如何在你的C#应用程序中获取结果以找出用户是否存在?请发布代码。 - Ken White

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接