19 04 2013
SPSite, FileNotFoundException and the Server Object Model in Console Applications and PowerShell Scripts
For a beginner SharePoint developer, there can be a fair amount of confusion around the seemingly trivial task of building a C# Console Application to connect to a SharePoint site and to learn the object model. You merely include a reference to the Microsoft.SharePoint.dll assembly, instantiate an object, passing in your site URL and you’re off. Right? Well, hopefully, but you might also get the oft-thrown ‘FileNotFoundException’ when trying this out for the first time (or even, the first time in a while if you’ve been somewhat absent from doing this, or have been rolling around in the delights of PowerShell too long).
First of all you need to ensure your Visual Studio Console Application project is set to build to x64 (or AnyCPU) – this is because your application must be able to load the 64-bit Microsoft.SharePoint.dll assembly (this is the first, legit reason for a FileNotFoundException, it literally can’t find a (64 bit version of a) file.
(Hint: On CodePlex is there’s an amazing toolkit known as CKS Dev (Community Kit for SharePoint) which includes, amongst many other very productive features, a ‘SharePoint Console App’ project template, which streamlines most of this project setup process for you. Definitely something to install if you do a lot of SharePoint Development of any kind). As of time of writing, the Project Templates have yet to be imported in the Visual Studio 2012 but still work grand in the Visual Studio 2010 version).
Next the problem usually is permissions – the security context of your console application (literally, the account you’re logged in as) must have access to the SharePoint environment, and more specifically, the configuration database of your environment.
Lastly, the SharePoint site you’re trying to connect to MUST be local to the server on which you’re running the console application. And it does not matter which Alternate Access Mapping URL you try to connect to.
And this last reason is the main reason for my article. Why must the site be local?
So what’s with this Server Object Model, and why must code that uses it run solely on the server that hosts SharePoint? Also, when you do use this, have you noticed a significant delay when you first open that SPSite connection?
The answer lies in the SPSite object. It has many constructors (6 in total, currently as of SharePoint 2013), but they all essentially do the same thing. Internally, your request to ‘open’ a SharePoint site is passed right down to SharePoint’s internal data connection layer (a native DLL with the obscure name ‘owssvr.dll’), which knows some very specific information about the system that is running your console application. This file can only be found on environments which have had SharePoint installed on them (another reason for the famous FileNotFoundException? Perhaps, but there is also a COMException that can be raised for when this dll can’t be found)
Whichever constructor you choose to use, the SharePoint internal code ‘asks’ the local server where the configuration database is. It needs to do this because it has to ask it in which content database the SharePoint Site Collection with URL http://xyz or with Guid abcdef-… exists.
Therefore, if you try to write a simple console application, and pass in the the URL to a SharePoint site that it NOT on your development server, you are basically asking SharePoint to find a Site that is registered on your local server.
This story is exactly the same if you try to run a PowerShell script against a SharePoint Site URL that is not a part of the server’s SharePoint Farm (there is an exception to this, namely for Office 365 hosted SharePoint Online).
If you do actually intend to run your application on another server, then make sure the site collection URL is a parameter for your application somehow.
If you need to interact with SharePoint and run a program that will NOT be running on the SharePoint server itself, then you will need to learn either the Managed Client Object Model, or one of the many Web Services that are now available (Classic (asmx) Web Services reference, ListData.svc REST endpoint, SharePoint 2013 REST _api [awesome, check this one out]).
But for now, I hope that clears a few things up for new developers.