sp2 software services microsoft kit exchange ews development c# outlook vsto exchange-server exchangewebservices

c# - software - Al buscar la Lista global de direcciones, ¿hay alguna manera de hacer una búsqueda parcial y no solo un "startsWith"?



install exchange web services (4)

EDITAR: 4 de enero de 2016 - Se agregó código de muestra para buscar AD.

Lo que no funcionará

La búsqueda de la GAL a través de ResolveNames siempre usa la coincidencia de prefijo-cadena para la Resolución de nombre ambiguo (ARN). Aunque la documentación de EWS no dice esto explícitamente, la documentación de Exchange ActiveSync sí lo dice. EWS y Exchange ActiveSync son solo protocolos; ambos confían en ARN por debajo, por lo que estás atascado con la coincidencia de prefijos, ya sea que uses el protocolo ActiveSync o EWS.

Aquí está la cita relevante de la documentación de Exchange ActiveSync ( https://msdn.microsoft.com/en-us/library/ee159743%28v=exchg.80%29.aspx )

La cadena de consulta de texto que se proporciona al comando Buscar se usa en una coincidencia de cadena de prefijos

.

Lo que funcionará

Lo mejor que puede hacer depende de su caso de uso, pero aquí hay algunas ideas:

Busque Active Directory en su programa cliente (el programa que contiene el código que mostró en su pregunta)

Configure su propio servicio para buscar el GAL. Su programa de cliente se conectaría tanto a Exchange como a su servicio. O su servicio podría proxy EWS, por lo que el programa del cliente necesita conectarse solo a su servicio.

¿Cómo serviría obtener los datos GAL? Una forma sería usar EWS ResolveNames repetidamente, para obtener los datos GAL, 100 entradas a la vez y almacenar estos datos en caché en su servicio. Primero, recupera todas las "a" s, luego todas las "b" s, etc. Por supuesto, puede haber más de 100 "a" s en el GAL, por lo que solo obtener todas las "a" podría tomar múltiples búsquedas. - Construiría su siguiente cadena de búsqueda, basada en la última entrada devuelta de cada búsqueda. Esto puede ser lento y doloroso. Probablemente desee almacenar estos datos en caché en una base de datos y actualizarlos periódicamente.

También puede acceder a GAL a través de MAPI. Puede usar MAPI directamente ( https://msdn.microsoft.com/en-us/library/cc765775%28v=office.12%29.aspx ) o a través de una biblioteca auxiliar como Redemption ( http: //www.dimastr. com / redención / home.htm ). Si usa MAPI directamente o mediante Redención, necesitará instalar Outlook (o Exchange) en la computadora donde se está ejecutando su código. Debido a esta restricción, puede ser mejor no usar MAPI en su programa cliente, sino incluirlo en un servicio que se ejecuta en algún servidor y hacer que su programa cliente se conecte a ese servicio.

Muestra de código AD

Otra respuesta proporcionó código de muestra para buscar en Active Directory. Estoy agregando una muestra de código que puede ser más adecuada para uso genérico por personas que pueden encontrar esta pregunta a través de la búsqueda. Comparado con la otra muestra, el siguiente código tiene las siguientes mejoras:

  • Si la cadena de búsqueda contiene caracteres especiales (como paréntesis), se escapan, de modo que la cadena de filtro construida sea válida.

  • La búsqueda por solo samaccountname muchos no será suficiente. Si "David Smith" tiene el nombre de cuenta "dsmith", la búsqueda de "David" por samaccountname no lo encontraría. Mi ejemplo muestra cómo buscar por más campos y proporciona algunos de los campos que puede querer buscar.

  • Comenzar desde una raíz como "GC:" es más sólido que tratar de construir una entrada LDAP desde Domain.GetComputerDomain ().

  • Todos los IDisposable deben desecharse (usualmente utilizándolos en una construcción que los 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(); } } } }

Tengo el siguiente código para buscar en la libreta de direcciones global por una determinada cadena:

"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;

el problema es que parece estar haciendo una búsqueda de "comienza con", así que tengo un nombre llamado:

"CONF-123" aparecerá, pero si tengo un nombre "JOE-CONF", no lo hará.

¿Cómo puedo hacer una búsqueda de cadenas parcial en esta línea?

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

Esperaba que hubiera algo así como:

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

pero eso no parece funcionar.


Una búsqueda ambigua en un campo de texto indexado solo puede hacerse con el prefijo (o sufijo ...). Es por eso que Exchange probablemente implementa la consulta como LIKE ''CONF%''.

He revisado la documentación y no hay forma de evitarla: la exploración completa de la tabla (que debería ser el caso para% CONF%) no parece tener sentido.


Aunque la búsqueda de comodines no es posible en EWS, es posible en la búsqueda AD. Las consultas de AD admiten comodines. es decir, * CONF * se puede buscar en AD, que devolverá todos los resultados que contengan "CONF". En función de los resultados, consulte EWS para un Objeto de Intercambio correspondiente. Necesita encontrar un parámetro con el que pueda encontrar la entrada de EWS correspondiente. Supongo que la dirección de correo electrónico (nombre de usuario) debería ser suficiente para encontrar el objeto de intercambio correspondiente.

Fragmento de código de búsqueda 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(); }

Ejemplo de consulta AD aquí .


También he estado tratando de buscar el GAL desde PHP usando php-ews. En una página web, el usuario comienza a ingresar el nombre que se va a buscar, una vez que se han ingresado 2 caracteres, se realiza una llamada a read_contacts.php pasando los 2 caracteres ingresados. read_contacts.php utiliza la solicitud EWS ResolveNames para recuperar una lista limitada de contactos. El código luego filtra algunos criterios y también verifica que el displayName comienza con los caracteres ingresados. Esto luego devuelve la lista filtrada:

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

La mayoría de las veces esto parece funcionar, es decir: ''mi'', ''jo'' devuelve Mike, Michael o Joe, John, excepto cuando envié ''Si'' o ''si'', para Simon, entonces la llamada ResolveNames devuelve la primera 100 entradas de la GAL.

Por el momento, he aumentado el número mínimo de caracteres a ingresar a 3, es decir: ''sim'' y esto funciona. El problema será cuando tengamos personal con solo 2 nombres de personajes.

Solo pensé en compartir el código para ver si me ayuda y para ver si alguien sabe por qué mi ''si'' no funciona correctamente.

Estoy accediendo a Exchange 2010