Background: The current Management App I'm working on has an IIS application hosted in Atlanta as the frontend to a Windows SharePoint Services (WSS) document store hosted in Australia. The problem with this was that the upload would do a massive round-trip overseas and back again - so a large file (say 20MB would take well over an hour). The workaround to this was to host the page as an IFrame in our application and to host it on a WSS Server so uploads of large files could be done directly to WSS rather than via the IIS Server overseas. I used the following code in the hosted page to perform the uploads using the SharePoint 2007 object model.
/// <summary>
/// Upload documents using MOSS Object Model Directly, updates database with document information
/// After the upload of each document is complete.
/// </summary>
/// <param name="projectId"></param>
/// <param name="sourceStream"></param>
/// <param name="fileName"></param>
/// <returns></returns>
public static VoidResponse UploadDocument(UploadedFile uploadedFile,
string projectNumber, int projectId, int activityId, int documentTypeLookupId,
int constructionAuthorisationId, string subfolderPath)
{
//Core document information to be passed into MOSS
//and into the .NET Web Service to update the database
DocumentDto newDocument = new DocumentDto();
newDocument.ProjectNumber = projectNumber;
newDocument.Name = uploadedFile.GetName();
newDocument.SharepointListName = ConstructSharepointListName(newDocument.ProjectNumber);
//Snapshot path as combination of both the
newDocument.SharepointSnapshotPath = CurrentSnapshotPath;
if (string.IsNullOrEmpty(newDocument.SharepointFileRelativePath))
{
newDocument.SharepointFileRelativePath = newDocument.Name;
}
string queryOptions = FormatHelper.GetQueryOptions(projectNumber, CurrentSnapshotPath, subfolderPath);
//To Allow return of uploaded file details
VoidResponse response = new VoidResponse();
//Housing SPSite and SPWeb in using blocks so they are disposed correctly as per best practices
//in http://msdn.microsoft.com/en-us/library/aa973248.aspx
using (SPSite site = new SPSite(SharePointParameter.SharePointSiteUrl))
{
using (SPWeb web = site.OpenWeb()) //The SPSite already has the site url value.
{
try
{
web.AllowUnsafeUpdates = true; //Using AllowUnsafeUpdates because we are creating an SPWeb -
//otherwise will result in exception
//as per http://hristopavlov.wordpress.com/2008/05/16/what-you-need-to-know-about-allowunsafeupdates/
SPList list = web.Lists[newDocument.SharepointListName];
SPFileCollection fileCollection = null;
//Using query options as recommended by
//http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splist.aspx,
//same as the Web Services do in the LL framework.
SPQuery spQuery = new SPQuery();
spQuery.Query = queryOptions;
SPListItemCollection folderCollection = list.GetItems(spQuery);
//Folders are really just SPListItems with type of FilSPFileSystemObjectType.Folder
//Defensive: Folder not found exception
if (folderCollection.Count == 0) //Error condition - folder not found
throw new ConfigurationErrorsException(string.Format(Messages.Pcp_MOSS_FolderNotFoundError,
newDocument.SharepointSnapshotPath));
fileCollection = folderCollection[0].Folder.Files;
//Only perform duplicate check when it is turned on in configuration settings.
if (SharePointParameter.CheckForDuplicateFilesInMOSS)
{
//Check if file doesn't already exist.
foreach (SPFile file in fileCollection)
{
if (file.Name == newDocument.Name)
{
//Duplicate detected
response.IsSuccessful = false;
response.Messages.Add(new Message(string.Format(Messages.Pcp_DuplicateFileDetected,
file.Name)));
return response;
}
}
}
Stream fileStream = uploadedFile.InputStream;
byte[] contents = new byte[fileStream.Length];
fileStream.Read(contents, 0, (int)fileStream.Length);
fileStream.Close();
//Upload document itself. This will also give us the new Id to store in the database.
SPFile currentFile = null;
currentFile = fileCollection.Add(newDocument.Name, contents);
System.Security.Principal.WindowsImpersonationContext impersonationContext = null;
try
{
if (GetUseCurrentUserCredentialsForMOSSFlag()) //Impersonate if uploading document
{
impersonationContext =
((System.Security.Principal.WindowsIdentity)
HttpContext.Current.User.Identity).Impersonate();
}
//Upload file details to main PCPData database
PcpDataService.PcpDataService pcpDataService = new PcpDataService.PcpDataService();
pcpDataService.Url = DDKOnline.WssHostedWeb.Shared.SystemParameter.DDKOnlineDataServiceUrl;
pcpDataService.AddProjectDocument(projectId, activityId, constructionAuthorisationId,
currentFile.Item.ID.ToString(), newDocument.SharepointListName,
newDocument.SharepointSnapshotPath, newDocument.SharepointFileRelativePath,
documentTypeLookupId, newDocument.Name);
}
finally
{
if (GetUseCurrentUserCredentialsForMOSSFlag() && impersonationContext != null)
{
impersonationContext.Undo();
}
}
//Successful upload completed.
response.IsSuccessful = true;
response.Messages.Add(new Message(Messages.Pcp_SharePointUploadComplete));
}
catch (SPException spException)
{
//Error ocurred during upload
response.Errors.Add(new DDKOnline.Framework.Common.Response.Error(spException.Message));
response.IsSuccessful = false;
}
catch (Exception ex)
{
response.Errors.Add(
new Error(string.Format(Messages.Pcp_SharePointAccessFailed)));
ExceptionPolicy.HandleException(ex, SERVICE_EXCEPTION_POLICY);
response.IsSuccessful = false;
}
finally
{
if (web != null) web.AllowUnsafeUpdates = false;
}
}
}
return response;
}
/// <summary>
/// Generate query options to support storage within subfolders of current list
/// </summary>
public class FormatHelper
{
internal static string GetQueryOptions(string projectNumber, string CurrentSnapshotPath, string subFolderPath)
{
string folderPath = VirtualPathUtility.RemoveTrailingSlash(string.Format("{0}/{1}/{2}", projectNumber, CurrentSnapshotPath, subFolderPath));
string queryOptions = string.Format("<Query/><QueryOptions><Folder>{0}</Folder></QueryOptions>", folderPath);
return queryOptions;
}
}