Anyone who has used Microsoft Search Server or the search.asmx Query service in Sharepoint to search a site of any size has probably run into the System.ServiceProcess.TimeoutException error. This is caused by the search failing to complete within 10 seconds at which point sharepoint throws this exception.
Anyone who has then Googled this error will probably have found out that this 10 second limit is (amazingly) hard coded into the QueryService class and so cannot be extended. The only suggestion I have seen for getting round this is to write your own webservice which uses the same classes as QueryService to perform a search and so that is what I have done.
I should point out that this is not really my code, I used Reflector to decompile the QueryService class and then made some modifications to get it to compile (see notes), so this really is the same code that search.asmx uses.
To make use of this code:
1. Download and unzip the files
To: c:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI
3. Install Guardian.SearchServer.dll into the GAC. The easiest way to do this is to copy the dll to C:\Windows\Assembly
That’s it, just use this searchWithTimeout.asmx in the same way you would have used search.asmx; add a service reference then call the QueryEx method passing in the same queryXml along with the timeout in milliseconds:
var searchServiceQuery = new SearchServer.SearchWithTimeoutSoapClient(); searchServiceQuery.ClientCredentials.Windows.ClientCredential.Domain = ConfigurationManager.AppSettings["SearchServer.Domain"]; searchServiceQuery.ClientCredentials.Windows.ClientCredential.UserName = ConfigurationManager.AppSettings["SearchServer.Username"]; searchServiceQuery.ClientCredentials.Windows.ClientCredential.Password = ConfigurationManager.AppSettings["SearchServer.Password"]; searchServiceQuery.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation; searchServiceQuery.ClientCredentials.Windows.AllowNtlm = true; //Verify that the Search Server is up and running if (string.Compare(searchServiceQuery.Status(), "ONLINE", true) != 0) throw new Exception("The Search Server isn't online."); var timeout = int.Parse(ConfigurationManager.AppSettings["SearchServer.TimeoutInMilliseconds"]); var searchResults = searchServiceQuery.QueryEx(query, timeout); searchServiceQuery.Close();
In the assembly in which you reference the webservice you need to change the Config setting in System.ServiceModel\bindings\basicHttpBinding\binding
to set the mode to “TransportCredentialOnly” and the Transport clientCredentialType to “Windows” or “NTLM” (this is the same as with the original Search Server webservice, more info here). This should look as follows:
<security mode="TransportCredentialOnly"> <transport clientCredentialType="Windows" proxyCredentialType="None" realm="" /> <message clientCredentialType="UserName" algorithmSuite="Default" /> </security>
My webservice only has a subset of the methods that can be found on search.asmx/QueryService, this is because the missing methods used classes which were internal to Microsoft.Office.Server.Search.dll so I couldn’t reproduce their functionality. If you need the other methods then reference both webservices.
The methods I have reproduced are:
I have only tested Status and QueryEx, so I would be keen to hear from anyone on whether the other methods work as expected.
I have also had to make the following changes (all of them because the original code used internal classes):
- removed some logging code that was in the original webservice
- changed an exception type
- exceptions do not load messages from the resource file