May 11, 2016

SPSite constructor Exception The Web Application Could Not be Found


Description: When calling SPSite constructor

using (SPSite site = new SPSite(UrlString))
{
....
}

 The user will get the following FileNotFoundException:  
"The Web application at {url} could not be found. Verify that you have typed the URL correctly."
 
Given that the calling user is NOT a site collection admin or secondary admin. User has Owner read access on target site. User can access the site normally from browser.


Reason: I concluded that this is a low-level access issue. User does not have access to config db.


If you care to know how it happened in details then continue reading!

Digging for the error:
Okay, so you really wanted to know the details.. lets start by having a look from the behind the scenes at the code from Microsoft.SharePoint.dll:
 
The call starts from SPSite Constructors (with or without User token) where it tries to get local farm then pass it to another internal SPSite constructor:

.method public hidebysig specialname rtspecialname instance void .ctor (string requestUrl) cil managed
        {
                // Method begins at RVA 0x1e9b54
                // Code size 24 (0x18)
                .maxstack 8
                IL_0000: ldarg.0
                IL_0001: call class Microsoft.SharePoint.Administration.SPFarm Microsoft.SharePoint.Administration.SPFarm::get_Local()
                IL_0006: ldarg.1
                IL_0007: newobj instance void [System]System.Uri::.ctor(string)
                IL_000c: ldc.i4.0
                IL_000d: call class Microsoft.SharePoint.SPUserToken
Microsoft.SharePoint.SPSecurity::GetDefaultUserToken()
                IL_0012: call instance void Microsoft.SharePoint.SPSite::.ctor
(class Microsoft.SharePoint.Administration.SPFarm, class [System]System.Uri, bool,
class Microsoft.SharePoint.SPUserToken)

                IL_0017: ret
        } // end of method SPSite::.ctor



Check the highlighted lines. The SPFarm.Local will try to initialize a connection to local configuration
database (using .NET runtime security if it has permission), then return local farm of that db or null (if failed to read local config db). Internally, here is how get_Local() works:
SPConfigurationDatabase local = SPConfigurationDatabase.Local;

Since the account does not have access on config db, then SPFarm.Local returns null value. I also tested this part from a C# console using the same user account, calling SPFarm.Local returned null.

Back to SPSite constructor code. this constructor will pass the farm object to another internal instructor:

internal SPSite(SPFarm farm, Uri requestUri, bool contextSite, SPUserToken userToken)
                {
                        if (farm == null)
                        {
                                throw new FileNotFoundException(SPResource.GetString("WebApplicationLookupFailed", new object[]
                                {
                                        requestUri.OriginalString
                                }));
                        }
                        if (!requestUri.IsAbsoluteUri || (requestUri.Scheme !=
Uri.UriSchemeHttp && requestUri.Scheme != Uri.UriSchemeHttps))

                        {
                                throw new FileNotFoundException(SPResource.GetString("WebApplicationLookupFailed", new object[]
                                {
                                        requestUri.OriginalString
                                }));
                        }
                        ......
                        SPWebApplication sPWebApplication = SPWebApplication.Lookup(farm, requestUri, contextSite, out sPAlternateUrl, out sPSiteLookupInfo, out this.m_LookupRequiredContext);
                        if (sPWebApplication == null)
                        {
                                throw new FileNotFoundException(SPResource.GetString("WebApplicationLookupFailed", new object[]
                                {
                                        requestUri.OriginalString
                                }));
                        }
......

                }


From highlighted lines in code above, we can see that exception can be throw in 3 cases:
#1 When Farm object is null
#2 When Site uri argument is not absolute or the scheme is not either http nor https
#3 When Web application is null (when Web Application lookup fails with Alternate Url)
   
The reason in our case is #1 I believe. Check 1st highlighted line in Orange. The SPSite constructor will pass the local farm object to the internal SPSite constructor. Since the farm object is null, it will throw FileNotFoundError exception. The error message itself will be read from  “WebApplicationLookupFailed” resource key. This error message actually comes from 'Strings.cs' file.
As a quick test I used PowerShell to display the error message:

[Microsoft.SharePoint.SPResource]::GetString("WebApplicationLookupFailed")
Output:
The Web application at |0 could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.


The Lesson to be learned:

The user got a WebApplication no found exception, while the real exception is Access Denied in config db. Do not trust all exceptions to be straight forward, as SharePoint has its own way of interpreting stuff!




No comments:

Post a Comment