2015-10-16 60 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