This topic demonstrates how to search for a contact or distribution group using a search provider. This is the first step toward adding a contact or distribution group to the collection of groups exposed by the Groups property.

Search for Contacts

The following illustration shows the classes, methods, and events used in the process of searching for a contact or distribution group.

Search Providers

Search providers can be Web services or they can be locally hosted within an Microsoft Lync Server 2010 network topology. One search provider can exhibit latency where another search provider does not. An example of a Web service provider is the Microsoft Exchange service provider. If you use the Exchange service search provider, you can cancel a search if performance becomes an issue. In all cases, search providers are third-party products.

Lync 2010 API exposes a list of seven possible search providers through the SearchProviders enumeration. Of the seven possible search providers, you perform a search that returns full results using the providers that are fully synchronized with Microsoft Lync 2010. Attempting to perform a search using a partially synchronized search provider can return partial results. You discover the synchronization state of a search provider by calling into GetSearchProviderStatus(SearchProviders).

Caution note Caution

Attempting to call into GetSearchProviderStatus with the enumerators SearchProviders .OtherContacts, SearchProviders .WindowsAddressBookor SearchProviders .PersonalContactsraises an exception. These search providers are always fully synchronized.

You can perform a single search against one or more search providers with the exception of the SearchProviders.Expertsearch provider. The expert search provider must be used in a search operation individually. An Expert search is actually a HTTP query against a Web page. For this reason, it cannot be combined with other search providers in a search process.

One search provider can have advantages over another search provider because individual providers can support a different set of search options and search fields. You may choose to specify multiple search providers in a single search so that the combination of options and search fields are supported by your search request.

Expert Search

Expert search capability is available for Lync Server 2010 when an administrator has configured the server with an expert search query Url. If a search query Url has not been configured at the server, no results are returned in an expert search.

An expert search is a search for people using keywords instead of name, e-mail, alias, or company. The expert search depends upon the nature of the data store you are searching. A good example of such a data store is the Microsoft SharePoint data store. SharePoint indexed fields include fields describing skills, interests, responsibilities, knowledge, and authored documents.

An expert search query is a string composed of keywords such as first names, last names, business titles or responsibility areas. The following expert search example finds people whose SharePoint profile includes the strings "programming writer 2" and "Alvord"

Alvord "programming writer 2"

Note Note

The previous search example specified search values rather than search fields. Because of this, people results are returned where these search values exist in any searchable field. To return a smaller and more meaningful result set, you should create a search string containing full values. Include double-quotes around such elements as job titles to avoid returning irrelevant results.

For example, use "Alford" instead of "Al" and "programming writer 2" instead of programming writer 2.

Due to the complexity of an expert search operation, it can be difficult to determine the reason why an expert search can return no results. The Microsoft.Lync.Model . . :: . . SearchException class is designed to give you hints that help you find the reason for an expert search failure. Surround your call into ContactManager . . :: . . EndSearch with a try/catch block and catch the Microsoft.Lync.Model . . :: . . SearchException .

For information about SharePoint Expertise search syntax, see Enterprise Search Keyword Reference

Exchange Service

Exchange Service search is a web service that searches for people in the local user's Microsoft Outlook contact list.

Global Address List

The Global Address List (GAL) search is used to find people or Distribution Groups in an organization's Active Directory data store. Results can be returned from a search on a partial display name or e-mail address. f you iterate on the collection of results returned by SearchResults . . :: . . AllResults , you must get the type of result and cast the individual result to the corresponding class.

Windows AddressBook

Searches the Windows AddressBook.

Other Contacts and Personal Contacts

Limits a search to people contacts in a user's contact list. If the searched person is in the organization but not in the local user's contact list, no results are returned.

Search Options

The SearchOptions enumeration provides a default search option that does not restrict a search to a whole word match. SearchOptions returns both contacts and distribution groups, and returns all results in one asynchronous call back. You can change the behavior of a search by combining one or more search options in a search operation. For example, you may want to see only contacts in a result set. Not every supported search provider supports all of the search options enumerated by SearchOptions .

Search Fields

A search field is an index that a search provider uses to enable a search through its data store. Not all of the search fields enumerated by SearchFields are supported as indexes by individual search providers. If you specify a search on a search provider using a search field that is not supported as an index, no search results will be returned. If you are not sure if a search provider supports a specific search field, you can use the SearchFields .AllFieldsenumerator in the search. In this case, the search will be conducted on the search provider using whatever indexes are supported by the search provider.

Walkthrough: Search for a Contact

Start Contact Search

  1. Verify client state is signed in to the server. For information about signing in to Lync Server 2010, see Walkthrough: Sign In to Lync .

  2. Get the search string, search providers, search fields, and search options to be used in the search. You can specify a single SearchFields enumeration or you can use a bitwise-or operation to specify multiple SearchFields enumerators. A contact or group is returned if an attribute value matching any of the search fields is found.

  3. Call the BeginSearch method. Results are returned using the asynchronous callback method you supply as the fifth parameter of BeginSearch.

Processing Search Results

Execute the following steps in a delegated callback method invoked by ContactManager upon completion of a search.

  1. Check the IAsyncResult.IsCompletedproperty for a true value. If true , the search for a contact or group returned a complete result. If false , the operation did not complete but there can still be valid results. You should process any results regardless of the state of IsCompleted.

  2. Call EndSearch on the contact manager. An instance of SearchResults is returned.

  3. Iterate on the SearchResults . . :: . . Groups and SearchResults . . :: . . Contacts collections properties on the SearchResults instance. If you want to get contact information updates from the contacts found by the search, you must subscribe to contact information for each contact you are interested in.

Subscribe to Contact Information

A ContactSubscription whose contact collection includes contacts found in search results generates ContactInformationChanged events when a given contact has published updated information. To begin receiving these events for the contacts returned in a search result, do the following:

  1. Create a ContactSubscription by calling into CreateSubscription

  2. Add the contact to the new subscription by calling AddContact .

  3. Create an Array of ContactInformationType that specify the types of contact information to be returned in the ContactInformationChanged event.

  4. Start the new contact subscription by calling into Subscribe .

Examples

Search for a Contact

The following example declares a private class field that caches a list of SearchProvidersinstances that are synchronized and can accept user search requests.

C#  Copy imageCopy Code
private List<SearchProviders> myActiveSearchProviders = new
List<SearchProviders>();
private ContactSubscription _SearchResultSubscription =
_ContactManager.CreateSubscription();

The following example registers for the SearchProviderStatusChangedevent raised by ContactManager.

Tip Tip

You must register for this event while the client state is ClientState.SignedOut. After you register for this event, you can call BeginSignInon the client instance. You must perform these steps in this order so that your application is prepared to handle the events when they are raised. If you do not handle the event, you can query the status of a search provider by calling into GetSearchProviderStatusand passing the enumerator for the search provider you want the current status of.

C#  Copy imageCopy Code
_ContactManager.SearchProviderStateChanged +=
ContactManager_SearchProviderStateChanged;

The following example handles the SearchProviderStatusChangedevent. You must handle this event to obtain the current status of each user search provider. When the status of a search provider has changed to SearchProviderStatusType.SyncSucceeded, the SearchProvidersenumerator is added to the local application cache declared in the previous example.

C#  Copy imageCopy Code
void ContactManager_SearchProviderStateChanged(Object source,
SearchProviderStateChangedEventArgs data)
{
   if (data.NewStatus == SearchProviderStatusType.SyncSucceeded)
   {
	myActiveSearchProviders.Add(data.Provider);
   }
}

The following example verifies that the state of a LyncClient is ClientState . SignedIn. If signed in to the server, the example declares a callback delegate, sets search fields, and calls the search method. The search is specified as follows:

  • Uses the Exchange Service and Global Address List search providers if fully synchronized.

    You can use partially synchronized search providers but search results from such providers may not contain full results.

  • Use contact only results.

  • Use whole word search option.

  • Search restricted to a contacts display name and last name search fields.

  • Return a maximum of 10 results.

  • Set the asynchronous state value to the search string used for the search.

Important note Important

In order to provide a callback method with the specific contact you are looking for, you should provide an asynchronous state hint as the last parameter of the search (the state object).

C#  Copy imageCopy Code
		/// <summary>
		/// Search for a contact or group
		/// </summary>
		/// <param name="searchName">string. Name of contact
or group to search for</param>
		/// <param name="numResults">uint. Number of results
to return.</param>
		void SearchForGroupOrContact(string searchName, uint
numResults)
		{
			// Initiate search for entity based on name.

			if (_LyncClient.State == ClientState.SignedIn)
			{
				SearchFields searchFields =
_LyncClient.ContactManager.GetSearchFields();
				object[] _asyncState = {
_LyncClient.ContactManager, searchName };
				_LyncClient.ContactManager.BeginSearch(
					searchName
					, myActiveSearchProviders //Synchronized
providers
					, searchFields			//All availalble
search fields
					, SearchOptions.Default  
					, numResults			//Number of results
to return
					, SearchResultsCallback   //System.IAsyncResult
callback - used to obtain search results
					, _asyncState);
		}
	}

Process Search Results

The following example is invoked by ContactManagerafter completing a search process.

Important note Important

Search results can contain DistributionGroup instances. For information about expanding a distribution group result, see Walkthrough: Expand a Distribution Group .

C#  Copy imageCopy Code
		/// Handles callback containing results of a search
		/// </summary>
		/// <param name="source"></param>
		/// <param name="results"></param>
		/// <param name="_asyncOperation"></param>
		public void SearchResultsCallback(IAsyncResult ar)
		{
			if (ar.IsCompleted == true)
			{
				SearchResults results = null;
				object[] _asyncState = (object[])ar.AsyncState;
				try 
				{
					results =
((ContactManager)_asyncState[0]).EndSearch(ar);
					if (results.AllResults.Count != 0)
					{
						//subscribe
						SubscribeToSearchResults(results.Contacts);
				}
					else
					{
						MessageBox.Show("0 instances found for " +
_asyncState[1].ToString());
				}
			}
				catch (SearchException se)
				{
					MessageBox.Show("Search failed: " +
se.Reason.ToString());
			}
		}
	}

Subscribe to Contacts

The following example stops an on-going subscription, removes any contacts found in a prior search, adds new contact search results, and then re-starts the contact subscription.

  Copy imageCopy Code
		/// <summary>
		/// Adds contacts found via a search to a
ContactSubscription and raises
		/// ContactAddedEvent to UI.
		/// </summary>
		/// <param name="pContact">List[Contact]. The list of
contacts found in a search.</param>
		/// <param name="subscribeContext">string. The
context in which this method is called.</param>
		public void SubscribeToSearchResults(List<Contact>
pContactList)
		{
			try
			{
				if (_SearchResultSubscription == null)
				{
					_SearchResultSubscription =
_ContactManager.CreateSubscription();
			}
				else
				{
					//remove all existing search results
					_SearchResultSubscription.Unsubscribe();
					foreach (Contact c in
_SearchResultSubscription.Contacts)
					{
						_SearchResultSubscription.RemoveContact(c);
				}
			}

				//add the Contact to a ContactSubscription
			 
_SearchResultSubscription.AddContacts(pContactList);

				//Specify the Contact Information Types to be
returned in ContactInformationChanged events.
				ContactInformationType[] ContactInformationTypes =
{ ContactInformationType.Availability,
ContactInformationType.ActivityId };

				//Activate the subscription
			 
_SearchResultSubscription.Subscribe(ContactSubscriptionRefreshRate.High,
ContactInformationTypes);
		}
			catch (Exception) { }
	}

See Also