Wednesday 30 January 2008

Uploading Files to MOSS 2007 via the Copy.asmx Web Service

Unlike the imaging web service (SharepointSite/_vti_bin/imaging.asmx), there is no "Upload" web method available for normal lists. There is a way around this lack of functionality in the standard MOSS lists.asmx web service.

You can upload files into your Sharepoint repository in one hit along with metadata (ie custom column information and values). You just have to Reference the SharepointSite/_vti_bin/copy.asmx (e.g. http://dev-moss/sites/home/PropertySharePoint/_vti_bin/copy.asmx) to get access to the Copy.CopyIntoItems() method. You then simply pass in the stream and Array of FileInfo objects (which have your metadata) into this method. I have seen several examples around that use the Http PUT method (e.g. http://www.sharepointblogs.com/ssa/archive/2006/11/30/wsuploadservice-web-service-for-uploading-documents-into-sharepoint.aspx)and and then grab the file back and update it with the meta data. My code sample below shows a much simpler way. I have not seen this technique is some of the larger Development guides such as SAMs MOSS 2007 Development Unleashed - they only give a passing mention to the copy service. MSDN also brushes over this service - http://msdn2.microsoft.com/en-us/copy.copy.copyintoitems.aspx



/// <summary>
///
/// </summary>
/// <param name="listName"></param>
/// <param name="destinationfolderPath"></param>
/// <param name="sourceFileSteam"></param>
/// <param name="fileName"></param>
/// <param name="fields"></param>
/// <returns>String with the destination Uri</returns>
public uint UploadFile(string listName, string destinationfolderPath, Stream sourceFileSteam, string fileName, SharepointCopyProxy.FieldInformation[] fields )
{
//Create folder if it doesn't exist
CreateFolder(listName, destinationfolderPath);

byte[] fileBytes = new byte[sourceFileSteam.Length];
sourceFileSteam.Read(fileBytes, 0, (int)sourceFileSteam.Length);
string[] destinationUri = {string.Format("{0}/{1}/{2}/{3}",_urlSiteRoot, listName, destinationfolderPath, fileName)}; //This may have issues as the listname may be different to the full path - may need to get value from folder path
SharepointCopyProxy.CopyResult[] result;

uint documentId = _copyWebService.CopyIntoItems("http://null", destinationUri, fields, fileBytes, out result);

if (result[0].ErrorMessage != null)
{
throw new System.ApplicationException("An error occurred uploading the file to Sharepoint.", new System.Exception(result[0].ErrorMessage));
}
return documentId;
}

19 comments:

Ofer Gal said...

I noticed you use "http://null" as the source.
I tried that too but It still shows the file as linked to "http://null"

Can you think of a way to unlink the new item?

If you put empty string it fails.

Anderson said...

Hi,

I think you can do that updating the field _CopySource in FieldInformation collection.

I'm looking for a way to update these fields but I'm not sure if it's possible.

Anderson

Ofer Gal said...

Based on http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.spbuiltinfieldid._copysource.aspx

_CopySource is read only

Anderson said...

I could update the "Title" field, which according to http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.spbuiltinfieldid.title.aspx is ReadOnly too.

Well, if you can't remove it, I suggest to put the same url for target and source.

Ofer Gal said...

I will give _CopySource a try.
What value should I put "" ?

Srinivasan said...

Dear david,
Is there any possible to download a file from document library using copy.asmx ?
i can able to upload the file using copy.asmx. But iam wondering is there any way to do download of document from document library ?

Unknown said...

Hi,

i used your code to upload the document in my Sharepoint library
and it give me an error

The request failed with HTTP status 401: Unauthorized.

my requirments are i have 2 servers one for application and one for sharepoint my website is in application server and from there i want to upload document in my sharepoint doc lib with some custom fileds values but i couldn't find any solution.

Anko Hanse said...

What works for me is to use the filename (without path) as the SourceUrl, i.e.

uint documentId = _copyWebService.CopyIntoItems(fileName, destinationUri, fields, fileBytes, out result);

In my experience, this is sufficient to get rid of the "This item is a copy of ..." line in the document properties view.
No need to set _CopySource.

Anko Hanse

Unknown said...

Great! thanks.

Saurabh K. Tripathi said...

thanks david

Eric Blais said...

Ali,

Maybe very late, but hope this helps someone else.

In my case I used this for my user name : domain\username and I was getting 401.

I changed credential constructor and passed the domain to the parameter and It solved my problem

Anonymous said...

Guys i've almost tried everything but i can't get rid of the link "Go To Source Item". Moreover, when you try to delete the item, a warning pop up tells you that the item is linked to some source.

I've tried set the _CopySource to almost any value but with no luck!

Why everything in SharePoint looks like an hack!?

Anonymous said...

Someone said before that if you put just he filename without the path, that link will go away.

I have not tried it

Anonymous said...

i've tried many combination but nothing worked for me. The link in the drop down context menu still there though it doesn't work...the _CopySource field has no effect.

Paul

Anonymous said...

Can someone please elaborate on how to handle the CreateFolder function?

//Create folder if it doesn't exist CreateFolder(listName, destinationfolderPath);

Do I have to use the list.asmx web service for that? Thanks.

Anonymous said...

Did anyone ever figure out how to remove the link to the source document reliably? I'm using the CopyIntoItemsLocal operation to restructure a Document Library, moving the documents into folders based on a metadata value (ProjectID). I want to do a real move, deleting the original document, but the destination document then ends up with a bad link back to its source. I have to move 5000+ docs, so it would be great to be able to unlink on the copy operation.

Thanks,
M.

David Klein said...

A basic example of the CreateFolder() method can be found here:
http://ddkonline.blogspot.com/2010/01/how-to-create-subfolders-within.html

Unknown said...

David,

Thank you for posting this article. I found it very helpful. Though I am still struggling to understand the fieldInformation array. How do you go about updating multiple metadata fields? Any direction would be greatly appreciated.

thanks in advance

Fabrice said...

For the source: use a single space as a source.
For me it works, I don't have the link anymore.

I read it there: http://platinumdogs.wordpress.com/2009/01/14/sharepoint-moss-creating-document-library-items-uploading-files-to-a-document-library/