Inconspicuous SharePoint Quirks #5 – The Case of the Client Context

Cannot contact site at specified URL

The biggest advantage of SharePoint is probably the lack of useful official documentation. Thanks to it, numerous blogs and forums propose solutions and answers to more numerous problems. Some of them work, several don’t, as problem domain is always vastly huge when compared to the answer domain. For example, a simple combination of misbehaving USB driver + a command window open in non-Admin mode + an IIS session stored in-proc + neighbor’s dog’s wheezing bark + Saturn in conjunction with Mars in Aries constellation – all these could combinedly error an API out in SharePoint. And obviously no forum, let alone technical support, would be able to provide an answer to that. The programmer has to use the final weapon – perseverance.

So I was trying to use the ClientContext to get some data out of my sharepoint site, which is in a VM. Created a simple console project and the following code to get data from a site:

public Web GetRootWeb() {
Web rootWeb;
Uri uri = new Uri("http://sp:2010");
using (ClientContext clientContext = new ClientContext(uri) {
clientContext.Credentials = CredentialCache.DefaultNetworkCredentials;
clientContext.Load(clientContext.Web);
clientContext.ExecuteQuery();
rootWeb = clientContext.Web;
}
return rootWeb;
}

No matter what variations I tried – credentials, permissions, I always got the following error: “Cannot contact site at specified URL http://sp:2010″. Luckily I had another web application in the same server. And that worked. So something must be wrong with this sharepoint site. This site was a migration from 2007, so first I thought it could be a possibility.

Step 1: Inspect the closed-source code
The ClientRequestException was being thrown from the ClientContext.EnsureFormDigest() method. Having worked with open source for several years gives that irritable itch of peeping into others code. So I fired up .Net Reflector and inspected the method:

The first thing the method does is get an asmx file – its actually the _vti_bin/sites.asmx as the following method shows:

So does this service work against a soap query? Also notice the 2nd and 3rd highlights. Both conditions (actually 3) throw the same exception and error message. So which one failed here? Was a non 200 http code returned? Was the responseContentType not text/xml? Or was m_formDigestInfo null? Pretty much written by a programmer who does not know the fundamentals of debugging. And thats probably why Microsoft’s code is closed, so strangers like me cant code review it. As a best practice, error conditions and error messages should have a monogamous relationship or else a dna test is required to find out who is whose child.

Step 2: Rinse with a different agent – Use “Soap” UI
I fire up soap-UI 4.0 and add the wsdl. Since the site is behind NTLM Windows authentication, a challenge request pops up, I enter the credentials for the site (in this case the farmadmin account) and nope – it does not work. I get a 302 Found error and thats followed by a 401 Unauthorized in the same trace. Well 401 is not what I got before. I try the same with the second web app but that works fine again.

Step 3: Burp it out
After turning on both the http log and error log in the soapUI, I conclude that the credentials may not be passed correctly. After reading this thread, I fire up Burp Suite, goto Options tab, check the “do www authenticate” option, add the servers and the user name/password/domain combination, turn the interceptor off. Well, the 401 is not there anymore, because the BurpSuite makes sure that the header contains the username/password. But the 302 Found still happens.

Step 4: Always exchange dirty notes for good notes in the bank
Obviously IIS is doing some thing here. I replaced the sp:2010’s web.config with the second webapp’s web.config in-toto, recycle app pool and try to hit with soapUI. Voila, Im getting a successful connection now. So some line in the web.config is the culprit. Next I reverted the web.config and started aping section-by-section from the working web.config and I finally come to this line:

<!-- <sessionState mode="SQLServer" timeout="60" allowCustomSqlDatabase="true" sqlConnectionString="Data Source=db;Initial Catalog=SessionStateService_f84b37c3424f46afa09cdacd278a95fa;Integrated Security=True;Enlist=False;Connect Timeout=15" /> --?
<sessionState mode="InProc" cookieless="AutoDetect" timeout="20" />

This section is from the trouble-some site’s web.config. I uncomment the first line, comment the InProc mode line, recycle app pool and whoa! I get a successful connection. So the sessionState set to InProc mode is somehow influencing the soap query which is what the EnsureFormDigest uses and throws an ambiguous ClientRequestException.

I don’t know why a seemingly unrelated sessionState causes an issue with soap query when trying to connect via console application. Thats probably a reflection for another Christmas day. Atleast it works now from Console. I had to make a slight modification while trying to do the same from a web application. From console, the DefaultNetworkCredentials works fine, but from a web app, you have to use the actual site credentials to connect to the site.

The Title is a tribute to Perry Mason novels.

Follow

Get every new post delivered to your Inbox.

Join 189 other followers