I was recently building a system for a client that needed to store lots of documents.  Normally I would have handled this by either storing the data in a BLOB field in the database or as a file on the disk.  The difference this time is the that the customer wanted to be able to rollback to prior versions, see changes to the files, and do full text searching in the documents.

Since this client was a small business there was one more requirement beyond that, there was no money for additional software besides the copies of SQL Server and Windows 2003 that were purchased for the rest of the project.

The solution I built used the freely downloadable version of Sharepoint for Windows Server 2003 called Windows Sharepoint Services.

Since we wanted to wrap most of the functionality inside of your application we checked out the SDK.

Sharepoint exposes both a set of managed classes and a web service API.  The web service API was the most attractive to me because I wanted to be able to easily access the files in Sharepoint from multiple sources in the future.  The problem I found was no simple interface to do some of the basic things I wanted to

After some digging I found some C# examples of wrapping the managed classes so I converted them and extended them to VB and made them generic so other developers could easily access Sharepoint. 

The other thing that these web services let me do was to return my byte arrays that allowed me to interact with the files as if they were physical files on the disk.  Even though the files did not exist in a simple folder location on the server the users still needed to be able to download the latest version from inside of their browser.  To do this I whipped up a simple HTTP handler in VB that grabed the request, called the web services and streamed the bits to the client just as if they were requesting the file directly from a physical file on the web server.  More on HTTP handlers and VB in a future post.

If you are looking for a simple web service interface into Windows Sharepoint Services below is the code that I used:

Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Data
Imports System.Diagnostics
Imports System.Web
Imports System.Web.Services
Imports Microsoft.SharePoint
Imports Microsoft.SharePoint.WebControls

<System.Web.Services.WebService(Namespace:="http://sharepoint.microsoft.com/samples/")> _
Public Class SPFiles
 Inherits System.Web.Services.WebService

 <WebMethod()> _
 Public Sub CheckIn(ByVal fileUrl As String, ByVal comments As String, ByVal fileContents() As Byte)
  Dim file As SPFile = GetFile(fileUrl)
 
  file.SaveBinary(fileContents)
  file.CheckIn(comments)
 End Sub

 <WebMethod()> _
 Public Function GetCheckOutStatus(ByVal fileUrl As String) As String
  Dim file As SPFile = GetFile(fileUrl)

  Return file.CheckOutStatus.ToString()
 End Function

 <WebMethod()> _
 Public Function CheckOut(ByVal fileUrl As String) As Byte()
  Dim file As SPFile = GetFile(fileUrl)

  file.CheckOut()
  Return file.OpenBinary()
 End Function

 <WebMethod()> _
 Public Function GetLatestVersion(ByVal fileUrl As String) As Byte()
  Dim file As SPFile = GetFile(fileUrl)

  Return file.OpenBinary()
 End Function

 <WebMethod()> _
 Public Sub UndoCheckout(ByVal fileUrl As String)
  Dim file As SPFile = GetFile(fileUrl)

  file.UndoCheckOut()
 End Sub

 <WebMethod()> _
 Public Sub Rename(ByVal Folder As String, ByVal CurrentFileName As String, ByVal NewFileName As String)
  Dim file As SPFile = GetFile(Folder + "/" + currentFileName)

  file.CopyTo(Folder + "/" + newFileName, True)

  Dim site As SPWeb = targetWebSite
  Dim srcList As SPList = site.Lists(Folder)
  Dim listItems As SPListItemCollection = srcList.Items
  Dim i As Integer

  For i = listItems.Count - 1 To 0 Step -1
   If listItems(i).File.Name = currentFileName Then
    listItems.Delete(i)
   End If
  Next i
 End Sub

 <WebMethod()> _
 Public Sub Delete(ByVal Folder As String, ByVal FileName As String)
  Dim site As SPWeb = targetWebSite
  Dim srcList As SPList = site.Lists(Folder)
  Dim listItems As SPListItemCollection = srcList.Items
  Dim i As Integer

  For i = listItems.Count - 1 To 0 Step -1
   If listItems(i).File.Name = FileName Then
    listItems.Delete(i)
   End If
  Next i
 End Sub

 <WebMethod()> _
 Public Function Search(ByVal searchText As String) As String
  Dim results As SPSearchResultCollection = targetWebSite.SearchDocuments(searchText)
  Dim count As Int32

  count = results.Count - 1

  Dim i As Int32
  Dim returnValue As String = ""

  For i = 0 To count
   If i = 0 Then
    returnValue = results.Item(i).Title
   Else
    returnValue += "~" & results.Item(i).Title
   End If
  Next i

  Return returnValue
 End Function

 <WebMethod()> _
 Public Function UploadDocument(ByVal fileName As String, ByVal fileContents() As Byte, ByVal targetFolder As String) As String

  If fileContents Is Nothing Then
   Return "Null Attachment"
  End If

  Dim folder As SPFolder = targetWebSite.GetFolder(targetFolder)
  Dim newFile As SPFile = folder.Files.Add(fileName, fileContents)

  Return newFile.Title + " created " + newFile.TimeCreated.ToLongDateString()
 End Function

#Region "Private Members"
 Private ReadOnly Property targetWebSite() As SPWeb
  Get
   If m_web Is Nothing Then
    m_web = SPControl.GetContextWeb(Context)
   End If
  
   Return m_web
  End Get
 End Property

 Private m_web As SPWeb

 Private Function GetFile(ByVal fileUrl As String) As SPFile
  Dim file As SPFile = targetWebSite.GetFile(fileUrl)
  
   If Not file.Exists Then
    Throw New System.IO.FileNotFoundException(String.Format("File {0} not found", fileUrl))
   End If
  
  Return file
 End Function
#End Region
End Class