Wednesday, November 26, 2008

SharePoint API: A Client-side Object Model

One common issue (see question #2) that developers using Microsoft's SharePoint platform are faced with is that the SharePoint object model can only be used when the application is run on a server in the SharePoint farm.

The following is code that demonstrates using HubKey's Client-side API for SharePoint. This API wraps many of SharePoint Server 2007's Web Services (Lists Web Service, Webs Web Service, etc.) to provide a familiar object model that can be used on remote client machines without having to process XML requests and responses. In this case the code from the MSDN article How to: Upload a File to a SharePoint Site from a Local Folder was copied verbatim, and it compiles and runs successfully on a client computer, even though the SharePoint DLLs are not referenced or installed.

Update: You can download a demo copy of the API - click here for information.

Update II: The API now includes a demo application - see this post for details.



using System;
using System.IO;
// Using HubKey.Web.Services.SharePoint in place of Microsoft.SharePoint
using HubKey.Web.Services.SharePoint;
 
namespace HubKey.DevelopmentHole
{
    class Program
    {
        static void Main(string[] args)
        {
            Program program = new Program();
            program.RunDemo();
        }
 
        public void RunDemo()
        {
            string webUrl = "http://remoteserver";
            SPSite site = new SPSite(webUrl);
            SPWeb web = site.OpenWeb();
 
            //create a new document library
            Guid id = web.Lists.Add("Temp Doc Lib", "A temp document library.", SPListTemplateType.DocumentLibrary);
            SPList list = web.Lists[id];
 
            //add a field
            list.Fields.Add("Upload Source", SPFieldType.Text, false);
            list.Update();
 
            string fileUrl = webUrl + "/Temp Doc Lib/New Folder/test.txt";
            string localFileName = @"D:\Temp\test.txt";
 
            string localFileContents = "A temp file uploaded by HubKey's SharePoint client-side API.";
 
            File.WriteAllText(localFileName, localFileContents);
 
            //Upload the file using the API code from 'How to: Upload a File to a SharePoint Site from a Local Folder'
            //see http://msdn.microsoft.com/en-us/library/ms454491.aspx
            UploadFile(localFileName, fileUrl);
 
            //Check out
            SPFile file = web.GetFile(fileUrl);
            file.CheckOut();
 
            //update the title and new upload source field by using the file's SPListItem property...
            file.Item["Title"] = "A temp title";
            file.Item["Upload Source"] = "HubKey's SharePoint client-side API.";
            file.Item.Update();
 
            //Check in
            file.CheckIn("Checked in by HubKey's SharePoint client-side API");
 
            //Get the file contents
            string serverFileContents = web.GetFileAsString(fileUrl);
            System.Diagnostics.Debug.Assert(string.Equals(localFileContents, serverFileContents));
 
            //Tidy up
            list.Delete();
        }
 
        public void UploadFile(string srcUrl, string destUrl)
        {
            if (!File.Exists(srcUrl))
            {
                throw new ArgumentException(String.Format("{0} does not exist",
                    srcUrl), "srcUrl");
            }
 
            SPWeb site = new SPSite(destUrl).OpenWeb();
 
            FileStream fStream = File.OpenRead(srcUrl);
            byte[] contents = new byte[fStream.Length];
            fStream.Read(contents, 0, (int)fStream.Length);
            fStream.Close();
 
            EnsureParentFolder(site, destUrl);
            SPFile file = site.Files.Add(destUrl, contents);
            SPFolder folder = file.ParentFolder;
        }
 
        public string EnsureParentFolder(SPWeb parentSite, string destinUrl)
        {
            destinUrl = parentSite.GetFile(destinUrl).Url;
 
            int index = destinUrl.LastIndexOf("/");
            string parentFolderUrl = string.Empty;
 
            if (index > -1)
            {
                parentFolderUrl = destinUrl.Substring(0, index);
 
                SPFolder parentFolder
                    = parentSite.GetFolder(parentFolderUrl);
 
                if (!parentFolder.Exists)
                {
                    SPFolder currentFolder = parentSite.RootFolder;
 
                    foreach (string folder in parentFolderUrl.Split('/'))
                    {
                        currentFolder = currentFolder.SubFolders.Add(folder);
                    }
                }
            }
            return parentFolderUrl;
        }
    }
}

12 comments:

Tony said...

Very nice work.

Is the api free? Where to download the api?

Charles said...

Yeah, what Tony said.

txs8311 said...

Thanks - we're still working through some additional functionality and testing, but it's likely we'll have something available for download soon. If you're interested in participating in testing, drop us a line at info@hubkey.com or choose "HubKey SharePoint API" as your interest on HubKey's Contact Us form.

txs8311 said...

You can now download a beta copy of the API - choose "HubKey SharePoint API" as your interest on HubKey's Contact Us form.

Toni said...

Is it possible to retrieve information on the libraries on sharepoint with this api? For example of what type the metadata fields in the library are. (Checkbox, dropdownlist and so on).

"A person wants to upload a document. The client has to show metadata in the way it is shown on sharepoint."

Toni said...

Hi!
Two more questions..

Is form based authentication possible with this api?

Is the source code available?

thanks!

Toni said...

I need to get the type of the metainfo column on sharepoint with Frontpage RPC. Can anybody help me?

txs8311 said...

Toni - you'll need to use the Web Services (e.g. the Lists.GetList method) provided by SharePoint to accomplish this. HubKey's SharePoint API uses these web services to provide an object model that replicates some of the features of Microsoft's API - including providing a SPFieldCollection for objects like SPList (e.g. list.Fields) and SPListItem (e.g. file.Item.Fields["Division Code"].TypeAsString). It currently does not support forms authentication however - until it does you'll need to hand code the processing of the service requests and xml formatted results.

Toni said...

Ok. Thanks for the answer.
It would be great if you could send me source code. Then I could add my little hack, if not I wait for you to add form-based authentication. Good work!

sihaaam said...

a nice work

i'm looking for web service to list database informations for a web application and to list web applications of a sharepoint server, could you advice me?

thanks

Toni said...

Hi! The question of form based authentication again.. To work around the problem, is it possible to set the header of the requests in the api? Then I can post the cookie in that header.

Best regards,

Toni

txs8311 said...

Hi Toni

It's not supported, but the web services are public properties of SPSite, so you might be able to set the CookieContainer property for example. You'd also need to pass the authentication cookie to the Web's WebClient (FrontPageRPC object) object.

You can get the authentication cookie by using the authentication web service.

We have a commercially licensed release of the API that will be available soon that includes support for FBA among other features (e.g. adding new webs). It will also include source code so that you can customize and extend the library as needed.