Can only call SharePoint 2007 web service using WCF client after calling with ASMX Web Reference

1

I have a web app that calls the SharePoint 2007 Lists.asmx service using a WCF endpoint. In an all day attempt to determine why it was receiving a 500 response when calling the GetListItems method, I discovered that it starts succeeding after I execute a query in U2U Caml Query Builder. That is, after executing a U2U query, the web app stops getting the 500 response and can successfully retrieve list items using its WCF service reference until I do an iisreset.

In response to that discovery, I created a console app that does a simple call to GetListItems via a WCF Service Reference. What I've narrowed it down to is the call from the WCF service reference only works after making a call from a legacy .net 2.0 Web Reference proxy. Here's the example code from my console app (which I have been running within VS on the web server):

string listName = "Reusable Content";
string viewName = String.Empty;
string rowLimit = null;

//Always Works
XmlDocument doc = new XmlDocument();
ListsAsmx.Lists oldSvc = new ListsAsmx.Lists();
oldSvc.Credentials = new System.Net.NetworkCredential("user1", "passwrod", "mydomain");
XmlNode result = oldSvc.GetListItems(listName, viewName, doc.CreateElement("Query"), doc.CreateElement("ViewFields"), rowLimit, doc.CreateElement("QueryOptions"), null);


//Only works after the above succeeds
string query = "<Query></Query>";
string viewFields = "<ViewFields></ViewFields>";
string queryOptions = "<QueryOptions></QueryOptions>";

ListsService.ListsSoapClient svc = new ListsService.ListsSoapClient();

svc.ClientCredentials.Windows.ClientCredential.UserName = "user1";
svc.ClientCredentials.Windows.ClientCredential.Domain = "passwrod";
svc.ClientCredentials.Windows.ClientCredential.Password = "mydomain";

svc.GetListItems(listName, viewName, XElement.Parse(query), XElement.Parse(viewFields), rowLimit, XElement.Parse(queryOptions), null);

So if I comment out sv2.GetListItems(...) and do an iisreset, I get the 500 response from svc.GetListItems(...). What's interesting is that it doesn't matter where the Web Reference call originates. When I discovered it using U2U Caml Query Builder, U2U was originating on my local dev machine, and the WCF client call was originating on the web server. The code above also succeeds even if I don't explicitly set the credentials for svc (presumably because it's automatically using my user's credentials). Below is the config for ListsSoapClient. Can you help me understand what's happening here and how to get svc to succeed on its own?

        <binding name="ListsSoap2" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="500000" maxBufferPoolSize="524288" maxReceivedMessageSize="500000" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
            <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="5120000" maxNameTableCharCount="16384" />
            <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Ntlm" />
            </security>
        </binding>
    </basicHttpBinding>
</bindings>
<client>
    <endpoint address="http://devpladmin.mydomain.com/_vti_bin/Lists.asmx"
        binding="basicHttpBinding" bindingConfiguration="ListsSoap2"
        contract="ListsService.ListsSoap" name="ListsSoap" />
</client>

Edit

Additional Info:
This is logged in the event viewer when I receive the 500:

Exception information: 
Exception type: FileLoadException 
Exception message: Could not load file or assembly 'Microsoft.SharePoint.intl, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' or one of its dependencies. Either a required impersonation level was not provided, or the provided impersonation level is invalid. (Exception from HRESULT: 0x80070542) 

Request information: 
Request URL: https://devpladmin.mydomain.com:443/_vti_bin/Lists.asmx 
Request path: /_vti_bin/Lists.asmx 

Thread information: 
Thread ID: 10 
Thread account name: MYDOMAIN\user1 
Is impersonating: False 
Stack trace:    at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.Load(String assemblyString)
at Microsoft.SharePoint.CoreResource..cctor()
.net
wcf
web-services
sharepoint-2007
asked on Stack Overflow Feb 11, 2014 by xr280xr • edited Feb 11, 2014 by xr280xr

1 Answer

1

Thanks to the error revealed in the Event Viewer and the blog post by Jerry Orman, Mystery of the SharePoint "White Screens", I've resolved the issue. In short, I needed to add a behavior to my WCF client endpoint allowing the server to impersonate the given user:

    <behaviors>
       <endpointBehaviors>
          <behavior name="SPServiceBehavior">
              <clientCredentials>
                    <windows allowedImpersonationLevel="Impersonation" allowNtlm="True"/>
              </clientCredentials>
          </behavior>
       </endpointBehaviors>
    </behaviors>  

So my best guess is this: The Lists.asmx service uses Microsoft.SharePoint.intl.dll. Loading Microsoft.SharePoint.intl.dll requires impersonation of an authorized user (perhaps because it is not marked as a safe control? I don't know about this). After resetting IIS, the assembly is not loaded. If I call the Lists.asmx service with my WCF proxy, without explicitly specifying an allowedImpersonationLevel of Impersonation, it defaults to Identification and gives the impersonation error above from the event viewer when trying to load Microsoft.SharePoint.intl.dll. The Lists service handles that exception and responds with a 500 response to make sure you, as a web service consumer, have no idea what the problem actually may be**. However, if I first call the service with the .NET 2.0 Web Reference proxy, it evidently does (this is my assumption) cause the server to impersonate the given user and the Microsoft.SharePoint.intl.dll assembly loads. Now if I use my WCF proxy, the assembly is already loaded and impersonation is not required. This explanation may not be quite right, but adding the behavior above got my WCF Service Reference to work.

John Saunders, I appreciate your efforts. Thanks!

**Come on...I can't go through all this and not rag on SharePoint at least once.

answered on Stack Overflow Feb 11, 2014 by xr280xr • edited Jun 20, 2020 by Community

User contributions licensed under CC BY-SA 3.0