При поиске глобального списка адресов есть способ сделать частичный поиск, а не просто "startWith",
У меня есть следующий код для поиска глобальной адресной книги по определенной строке:
"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" будет отображаться, но если у меня есть имя "JOE-CONF", это не будет.
Как выполнить частичный поиск строк в этой строке
var rnType = new ResolveNamesType {ReturnFullContactData = true, UnresolvedEntry = "CONF-"};
Я надеялся, что есть что-то вроде:
var rnType = new ResolveNamesType {ReturnFullContactData = true, UnresolvedEntry = "%CONF-%"};
но это не работает.
Ответы
Ответ 1
EDIT: Ян 4,2016 - Добавлен образец кода для поиска AD.
Что не будет работать
Поиск GAL через ResolveNames всегда использует соответствие префиксной строки для неоднозначного разрешения имен (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 несколько раз, чтобы получать данные GAL, 100 записей за раз и кэшировать эти данные в вашей службе. Сначала загрузите все "a", затем все "b" и т.д. Конечно, в GAL может быть больше 100 "а", поэтому просто получение всех "а" может выполнять несколько запросов - вы построили бы следующую строку поиска на основе последней записи, возвращаемой из каждого поиска. Это может быть медленным и болезненным. Возможно, вам захочется кэшировать эти данные в базе данных и периодически обновлять их.
Вы также можете попасть в GAL через MAPI. Вы можете использовать MAPI напрямую (https://msdn.microsoft.com/en-us/library/cc765775%28v=office.12%29.aspx) или через вспомогательную библиотеку, такую как Redemption (http://www.dimastr.com/redemption/home.htm). Независимо от того, используете ли вы MAPI напрямую или через Redemption, вам необходимо установить Outlook (или Exchange) на компьютер, на котором работает ваш код. Из-за этого ограничения может быть лучше не использовать MAPI в вашей клиентской программе, а вставлять его в службу, запущенную на каком-либо сервере, и подключить вашу клиентскую программу к этой службе.
Пример кода AD
Другой ответ предоставил пример кода для поиска в Active Directory. Я добавляю образец кода, который может быть лучше подходит для общего использования людьми, которые могут найти этот вопрос через поиск. По сравнению с другим образцом, приведенный ниже код имеет следующие улучшения:
-
Если строка поиска содержит любые специальные символы (например, скобки), они экранируются, поэтому строковая строка фильтра действительна.
-
Поиск по простому учетному имени многого не достаточно. Если "Дэвид Смит" имеет имя учетной записи "dsmith", поиск "Давида" по имени samaccount не найдет его. В моем примере показано, как выполнять поиск по большему количеству полей и дает некоторые поля, которые можно искать.
-
Начиная с корня типа "GC:" является более надежным, чем попытка создать запись LDAP из Domain.GetComputerDomain().
-
Все 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();
}
}
}
}
Ответ 2
Несмотря на то, что поиск по шаблону в EWS невозможен, это возможно в поиске AD. Запросы AD поддерживают подстановочные знаки. т.е., * CONF * можно искать в AD, который будет возвращать все результаты, которые содержат "CONF". На основании результатов запросите EWS для соответствующего объекта Exchange. Вам нужно найти параметр, с помощью которого вы можете найти соответствующую запись 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 здесь.
Ответ 3
Неопределенный поиск по индексированному текстовому полю может быть выполнен только с помощью префикса (или суффикса...). Поэтому Exchange, вероятно, реализует запрос как LIKE 'CONF%'.
Я просмотрел документацию, и вы не можете ее обойти, - полное сканирование таблицы (что должно быть в случае% CONF%), по-видимому, не имеет смысла.
Ответ 4
Я также пытался искать GAL из PHP, используя php-ews. На веб-странице пользователь начинает вводить имя для поиска, как только введено 2 символа, вызов read_contacts.php производится с использованием введенных 2 символов. 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;
}
В большинстве случаев это, похоже, работает, т.е. "mi", "jo" возвращает Майка, Майкла или Джо, Джона, за исключением случаев, когда я посылал "Si" или "si", для Simon, затем ResolveNames возвращает первые 100 записей из GAL.
В настоящее время я увеличил минимальное количество символов для ввода до 3, то есть: "sim", и это работает. Проблема будет заключаться в том, когда мы получим штат с именами всего по 2 символа.
Я просто подумал, что поделился бы кодом, чтобы узнать, помогает ли он, и узнать, знает ли кто-нибудь, почему мой si не работает должным образом.
Я обращаюсь к Exchange 2010