2015-10-16 64 views
16

我有下面的代码通过一定的字符串搜索全局地址簿:当搜索全局地址列表,有没有办法做局部搜索,而不仅仅是一个“startsWith”

“CONF”

var esb = new ExchangeServiceBinding(); 
esb.Url = @"https://myurl.com/EWS/Exchange.asmx"; 

esb.Credentials = new NetworkCredential(_user,_pwd, _domain); 

var rnType = new ResolveNamesType {ReturnFullContactData = true, UnresolvedEntry = "CONF"}; 

ResolveNamesResponseType response = esb.ResolveNames(rnType); 
ArrayOfResponseMessagesType responses = resolveNamesResponse.ResponseMessages; 
var responseMessage = responses.Items[0] as ResolveNamesResponseMessageType; 

ResolutionType[] resolutions = responseMessage.ResolutionSet.Resolution; 

的问题是,它似乎是在做一个“打头”搜索,所以我有个名字叫:

“CONF-123”,它会显示出来,但如果我有一个名为“乔 - CONF “那么它不会。

我该怎么办部分字符串搜索在这条线

var rnType = new ResolveNamesType {ReturnFullContactData = true, UnresolvedEntry = "CONF-"}; 

我希望能有这样的:

var rnType = new ResolveNamesType {ReturnFullContactData = true, UnresolvedEntry = "%CONF-%"}; 

,但似乎并没有工作。

+4

您正在寻找'CONF-',但声明'JOE-CONF'没有显示在回报中。我不认为它会认为' - '是在'CONF'之后,如果你只是使用'CONF'而没有' - '会发生什么。 – Ilnetd

+0

这是一个错字。 。我已更新问题 – leora

+0

您还在寻找解决方案吗? – rsteward

回答

0

索引文本字段上的含糊搜索只能使用前缀(或后缀...)进行。这就是为什么Exchange可能将查询实现为LIKE'CONF%'。

我查看了文档,并且没有任何方法可以绕过它 - 全表扫描(这将是%CONF%的情况)似乎没有意义。

5

编辑: Jan 4,2016 - 增加了用于搜索AD的示例代码。

什么都不行

搜索通过ResolveNames的GAL始终使用前缀字符串匹配不明确名称解析(ARN)。尽管EWS文档没有明确说明,但Exchange ActiveSync文档确实如此。 EWS和Exchange ActiveSync只是协议;它们都依赖于ARN,因此无论使用ActiveSync协议还是EWS,都会阻止前缀匹配。

下面是从Exchange ActiveSync的文档(https://msdn.microsoft.com/en-us/library/ee159743%28v=exchg.80%29.aspx

提供给搜索命令的文本查询字符串的相关报价在前缀字符串匹配

使用 。

什么工作

做的最好的事情取决于你的使用情况,但这里有一些想法:

搜索的Active Directory中的客户端程序(包含您显示的代码程序在你的问题)

建立你自己的服务来搜索GAL。您的客户端程序将连接到Exchange和您的服务。或者您的服务可以代理EWS,这样客户端程序只需要连接到您的服务。

你将如何获得GAL数据?一种方法是反复使用EWS ResolveNames,一次获得100个条目的GAL数据,并将这些数据缓存到您的服务中。首先,检索所有的“a”,然后检索所有的“b”等等。当然,GAL中可能有100多个“a”,因此只需获取所有“a”就可以进行多次搜索 - 根据每个搜索返回的最后一个条目,您将构建您的下一个搜索字符串。这可能是缓慢而痛苦的。您可能想要将这些数据缓存在数据库中并定期刷新。

您也可以通过MAPI进入GAL。您可以直接使用MAPI(https://msdn.microsoft.com/en-us/library/cc765775%28v=office.12%29.aspx)或通过帮助库(如Redemption(http://www.dimastr.com/redemption/home.htm))。无论您是直接使用MAPI还是通过兑换,都需要在运行代码的计算机上安装Outlook(或Exchange)。由于这种限制,最好不要在客户端程序中使用MAPI,而要将其保存在某个服务器上运行的服务中,并让客户端程序连接到该服务。

AD代码示例

另一个答案提供的示例代码搜索Active Directory。我添加的代码示例可能更适合那些可能通过搜索找到此问题的人使用。相比于其他样品,下面的代码有以下改进:

  • 如果搜索字符串包含任何特殊字符(如括号),它们被转义,因此,所构建的过滤字符串是有效的。

  • 只用samaccountname进行搜索很多都不够用。如果“David Smith”的帐户名称为“dsmith”,则通过samaccountname搜索“David”不会找到他。我的示例显示了如何通过更多字段进行搜索并提供一些可能想要搜索的字段。

  • 从像“GC:”这样的根开始比尝试从Domain.GetComputerDomain()构造LDAP条目更加健壮。

  • 所有IDisposable必须处置(通常通过使用它们在using构造)。

    // Search Active Directory users. 
    public static IEnumerable<DirectoryEntry> SearchADUsers(string search) { 
        // Escape special characters in the search string. 
        string escapedSearch = search.Replace("*", "\\2a").Replace("(", "\\28") 
         .Replace(")", "\\29").Replace("/", "\\2f").Replace("\\", "\\5c"); 
    
        // Find entries where search string appears in ANY of the following fields 
        // (you can add or remove fields to suit your needs). 
        // The '|' characters near the start of the expression means "any". 
        string searchPropertiesExpression = string.Format(
         "(|(sn=*{0}*)(givenName=*{0}*)(cn=*{0}*)(dn=*{0}*)(samaccountname=*{0}*))", 
         escapedSearch); 
    
        // Only want users 
        string filter = "(&(objectCategory=Person)(" + searchPropertiesExpression + "))"; 
    
        using (DirectoryEntry gc = new DirectoryEntry("GC:")) { 
         foreach (DirectoryEntry root in gc.Children) { 
          try { 
           using (DirectorySearcher s = new DirectorySearcher(root, filter)) { 
            s.ReferralChasing = ReferralChasingOption.All; 
            SearchResultCollection results = s.FindAll(); 
            foreach (SearchResult result in results) { 
             using (DirectoryEntry de = result.GetDirectoryEntry()) { 
              yield return de; 
             } 
            } 
           } 
          } finally { 
           root.Dispose(); 
          } 
         } 
        } 
    } 
    
+0

我感谢你分享了更好的AD搜索实现。但请保持良好/礼貌,并改为使用“改善上述答案”,“添加”等词语。我强烈建议您不要使用“上面的答案有很多缺点”等词语或声音,“我的回答是更好”。这里的每个人都是帮助,互相学习。毫无疑问,任何代码都有改进的空间。 leora问题的症结在于搜索与包含匹配。我试图回答它,而不是专注于编写最有效的代码,我相信leora不会写任何问题。 –

+0

你是对的,阿布吉特。谢谢你教我适当的礼节。我编辑了我的措辞。 – George

4

虽然通配符搜索在EWS是不可能的,所以能够在AD搜索。 AD查询支持通配符。即,可以在AD中搜索* CONF *,这将返回包含“CONF”的所有结果。根据结果​​,查询相应Exchange对象的EWS。您需要找到可以找到相应EWS条目的参数。我猜电子邮件地址(用户名)应该足以找到相应的交换对象。

AD

搜索代码段...

private SearchResultCollection SearchByName(string username, string password, string searchKeyword) 
{ 
    DirectorySearcher ds = new DirectorySearcher(new DirectoryEntry("LDAP://" + Domain.GetComputerDomain().ToString().ToLower(), username, password)); 
    ds.Filter = "(&((&(objectCategory=Person)(objectClass=User)))(samaccountname=*" + searchKeyword + "*))"; 
    ds.SearchScope = SearchScope.Subtree; 
    ds.ServerTimeLimit = TimeSpan.FromSeconds(90); 
    return ds.FindAll(); 
} 

AD查询示例here

0

我也一直在尝试使用php-ews从PHP搜索GAL。在网页上,用户开始输入要搜索的名称,一旦输入了2个字符,就会通过输入的2个字符来调用read_contacts.php。 read_contacts.php使用EWS ResolveNames请求来检索有限的联系人列表。代码然后根据一些条件进行过滤,并检查displayName是否以输入的字符开头。这则返回筛选列表:

<?php 
$staffName = $_GET['q'];  
require_once './php-ews/EWSType.php'; 
require_once './php-ews/ExchangeWebServices.php'; 
require_once 'php-ews/EWSType/RestrictionType.php'; 
require_once 'php-ews/EWSType/ContainsExpressionType.php'; 
require_once 'php-ews/EWSType/PathToUnindexedFieldType.php'; 
require_once 'php-ews/EWSType/ConstantValueType.php'; 
require_once 'php-ews/EWSType/ContainmentModeType.php'; 
require_once 'php-ews/EWSType/ResolveNamesType.php'; 
require_once 'php-ews/EWSType/ResolveNamesSearchScopeType.php'; 
require_once 'php-ews/NTLMSoapClient.php'; 
require_once 'php-ews/NTLMSoapClient/Exchange.php'; 

$host = '[exchange server]'; 
$user = '[exchange user]'; 
$password = '[exchange password]'; 

$ews = new ExchangeWebServices($host, $user, $password); 

$request = new EWSType_ResolveNamesType(); 

$request->ReturnFullContactData = true; 
$request->UnresolvedEntry = $staffName; 


$displayName = ''; 
$i = 0; 
$staff_members = false; 
$response = $ews->ResolveNames($request); 
if ($response->ResponseMessages->ResolveNamesResponseMessage->ResponseClass == 'Error' && $response->ResponseMessages->ResolveNamesResponseMessage->MessageText == 'No results were found.') { 
} 
else { 
    $numNamesFound = $response->ResponseMessages->ResolveNamesResponseMessage->ResolutionSet->TotalItemsInView; 
    $i2=0; 
    for ($i=0;$i<$numNamesFound;$i++) { 
     if ($numNamesFound == 1) { 
      $displayName = $response->ResponseMessages->ResolveNamesResponseMessage->ResolutionSet->Resolution->Contact->DisplayName; 
     } 
     else { 
      $displayName = $response->ResponseMessages->ResolveNamesResponseMessage->ResolutionSet->Resolution[$i]->Contact->DisplayName; 
     } 
     echo "DisplayName: " . $displayName . "\n";  
     if (stripos($displayName, 'External') == true) { 
     } 
     else { 
      $searchLen = strlen($staffName); 
      if (strcasecmp(substr($displayName, 0, $searchLen), $staffName) == 0) { 
       if ($numNamesFound == 1) { 
        $emailAddress = $response->ResponseMessages->ResolveNamesResponseMessage->ResolutionSet->Resolution->Mailbox->EmailAddress; 
       } 
       else { 
        $emailAddress = $response->ResponseMessages->ResolveNamesResponseMessage->ResolutionSet->Resolution[$i]->Mailbox->EmailAddress; 
       } 
       $staff_members[$i2] = array('name' => $displayName,'email' => $emailAddress); 
       $i2++; 
      } 
     } 
    } 
    $staffJson = json_encode($staff_members); 
echo $staffJson; 
} 

这其中大部分似乎工作的时间,即:,“JO”返回麦克迈克尔,或乔,约翰,除了我给当“硅”“MI”或'si',对于Simon,那么ResolveNames调用会返回GAL中的前100个条目。

目前我已经增加了输入到3的最小字符数,即:'sim',并且这个工作。问题将出现在我们获得只有2个字符名字的员工时。

我只是以为我会分享代码,看看是否有帮助,并看看是否有人知道我的'si'不能正常工作。

我正在访问Exchange 2010

相关问题