2015-10-16 12 views
16

Mam następujący kod wyszukiwania globalnej książki adresowej przez pewien ciąg:Podczas przeszukiwania globalnej listy adresów, czy istnieje sposób, aby zrobić częściowego szukanie i nie tylko „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; 

problem jest to, że wydaje się robi „zaczyna się od” szukaj więc mam nazwę nazwie:

„CONF-123” pokaże się, ale jeśli mam nazwę „JOE-CONF "to nie będzie.

Jak mogę zrobić częściowy ciąg wyszukiwania na tej linii

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

miałem nadzieję, że coś jak:

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

ale to nie wydają się działać.

+4

szukasz „CONF-”, ale stwierdzając, że „Joe-CONF” nie pojawi się w zamian. Nie sądzę, że oznaczałoby to, że "-" jest po "CONF", co się stanie, jeśli po prostu użyjesz "CONF" bez "-". – Ilnetd

+0

to był literówka. . Mam zaktualizowane pytanie – leora

+0

Nadal szukasz rozwiązania? – rsteward

Odpowiedz

0

Niejednoznaczne wyszukiwanie w indeksowanym polu tekstowym może być wykonane tylko z prefiksem (lub sufiksem ...). Właśnie dlatego Exchange prawdopodobnie implementuje zapytanie jako LIKE "CONF%".

Przejrzałem dokumentację i nie ma sposobu, aby ją obejść - pełne skanowanie tabeli (co musiało być w przypadku% CONF%) nie wydaje się mieć sensu.

5

EDYTOWANIE: Jan 4,2016 - Dodano przykładowy kod do wyszukiwania w AD.

Co nie zadziała

Przeszukiwanie GAL poprzez ResolveNames zawsze wykorzystuje prefiks-ciąg pasuje do niejednoznacznych Name Resolution (ARN). Chociaż dokumentacja EWS tego nie mówi wprost, to ma to miejsce w dokumentacji programu Exchange ActiveSync. EWS i Exchange ActiveSync to tylko protokoły; oba opierają się na ARN pod spodem, więc utknąłeś z dopasowaniem prefiksu, niezależnie od tego, czy używasz protokołu ActiveSync czy EWS.

Oto odpowiedni cytat z Exchange ActiveSync dokumentacji (https://msdn.microsoft.com/en-us/library/ee159743%28v=exchg.80%29.aspx)

ciągu kwerendy tekstowej, która jest dostarczana do polecenia Search służy w meczu prefix-strunowej

.

Co będzie działać

Najlepszą rzeczą do zrobienia, zależy od przypadku użycia, ale oto kilka pomysłów:

Szukaj Active Directory w programie klienta (program, który zawiera kod, który pokazał na twoje pytanie)

Skonfiguruj własną usługę, aby przeszukać GAL. Twój program klienta łączyłby się zarówno z Exchange, jak iz twoją usługą. Lub Twoja usługa może pełnić rolę serwera proxy EWS, aby program klienta musiał łączyć się tylko z Twoją usługą.

W jaki sposób można uzyskać dostęp do danych GAL?Jednym ze sposobów byłoby wielokrotne używanie EWS ResolveNames, aby uzyskać dane GAL, 100 wpisów jednocześnie i buforować te dane w usłudze. Najpierw pobierz wszystkie "a", potem wszystkie "b" itp. Oczywiście w GAL może być ponad 100 "a", więc po prostu uzyskanie wszystkich "a" może zająć wiele wyszukiwań - skonstruowałbyś następny ciąg wyszukiwania, oparty na ostatnim wpisie zwróconym z każdego wyszukiwania. To może być powolne i bolesne. Prawdopodobnie będziesz chciał buforować te dane w bazie danych i odświeżać je okresowo.

Możesz również dostać się do GAL przez MAPI. Możesz użyć MAPI bezpośrednio (https://msdn.microsoft.com/en-us/library/cc765775%28v=office.12%29.aspx) lub przez bibliotekę pomocniczą, taką jak Redemption (http://www.dimastr.com/redemption/home.htm). Niezależnie od tego, czy korzystasz z MAPI bezpośrednio, czy poprzez Odkupienie, musisz zainstalować program Outlook (lub Exchange) na komputerze, na którym działa twój kod. Z powodu tego ograniczenia najlepiej nie używać MAPI w programie klienckim, ale trzymać go w usłudze działającej na jakimś serwerze i mieć połączenie programu klienta z tą usługą.

Kod AD Próbka

Inna odpowiedź warunkiem przykładowy kod do wyszukiwania Active Directory. Dodaję próbkę kodu, która może być lepiej dostosowana do ogólnego użytku przez osoby, które mogą znaleźć to pytanie poprzez wyszukiwanie. W porównaniu do drugiej próbki, kod poniżej zawiera następujące ulepszenia:

  • Jeśli ciąg wyszukiwania zawiera żadnych znaków specjalnych (jak nawiasie), są one uciekły, tak skonstruowany, że filtr jest prawidłowy ciąg.

  • Wyszukiwanie według samego samaccountname wiele nie wystarczy. Jeśli "Dawid Smith" ma nazwę konta "dsmith", wyszukiwanie "David" przez samaccountname nie pozwoli mu go znaleźć. Mój przykład pokazuje, jak wyszukiwać według większej liczby pól i podaje niektóre z pól, które można przeszukiwać.

  • Uruchamianie z poziomu głównego takiego jak "GC:" jest bardziej niezawodne niż próba skonstruowania wpisu LDAP z Domain.GetComputerDomain().

  • Wszystkie należy usunąć (zwykle za pomocą ich w konstrukcji 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

Doceniam, że udostępniłeś lepszą implementację Wyszukiwania AD. Ale proszę bądź miły/uprzejmy i zamiast tego używaj słów takich jak "poprawić powyższą odpowiedź", "dodać do niej" itp. Zachęcam cię, abyś nie używał słów/dźwięków jak "Powyżej odpowiedź ma wiele wad", "Moja odpowiedź brzmi: lepszy". Wszyscy tutaj mają pomagać, uczyć się od siebie nawzajem. Nie ulega wątpliwości, że każdy fragment kodu może być ulepszony. Głównym problemem Leory jest szukanie z zapałkami. Próbowałem na nie odpowiedzieć, zamiast koncentrować się na napisaniu najbardziej wydajnego kodu, który, jak sądzę, nie będzie miał problemu z pisaniem. –

+0

Masz rację, Abhijit. Dzięki za nauczenie mnie właściwych manier. Zmieniłem moje brzmienie. – George

4

Choć wieloznaczny wyszukiwania nie jest możliwe w EWS, jest możliwe w poszukiwaniu AD. Zapytania AD obsługują znaki wieloznaczne. tzn. * CONF * można wyszukać w AD, co spowoduje zwrócenie wszystkich wyników, które zawierają "CONF". Na podstawie wyników zapytaj EWS o odpowiedni obiekt wymiany. Musisz znaleźć parametr, pod którym znajdziesz odpowiedni wpis EWS. Domyślam się, że adres e-mail (nazwa użytkownika) powinien wystarczyć do znalezienia odpowiedniego obiektu wymiany.

AD kod Szukaj fragment ...

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 Przykład Zapytanie here.

0

Próbuję również przeszukiwać GAL z PHP za pomocą php-ews. Na stronie internetowej użytkownik zaczyna wpisywać nazwę, która ma być przeszukana, po wprowadzeniu 2 znaków wywołanie read_contacts.php jest wykonywane po podaniu dwóch wprowadzonych znaków. read_contacts.php używa żądania EWS ResolveNames do pobrania ograniczonej listy kontaktów. Kod następnie filtruje niektóre kryteria i sprawdza, czy nazwa wyświetlana zaczyna się od wprowadzonych znaków.To z kolei zwraca przefiltrowaną listę:

<?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; 
} 

Większość czasu to wydaje się działać, to znaczy: 'mi', 'jo' zwraca Mike, Michael, czy Joe, John wyjątkiem gdy wysłałem 'Si' lub "si", dla Simona, wtedy wywołanie ResolveNames zwraca pierwsze 100 wpisów z GAL.

Na razie zwiększyłem minimalną liczbę znaków, które należy wprowadzić do 3, tj .: "sim", a to działa. Problem będzie, gdy otrzymamy personel z tylko 2-znakowymi imionami.

Po prostu pomyślałem, że udostępnię kod, aby sprawdzić, czy to pomaga, i sprawdzić, czy ktoś wie, dlaczego moje "si" nie działa poprawnie.

mam dostępu do Exchange 2010

Powiązane problemy