Tuesday, October 23, 2007

Upload a File to a SharePoint Document Library - Part I

The following helper class demonstrates a few techniques that allow documents to be uploaded to a SharePoint document library programmatically without using the API or a custom web service. You don't need to specify a document library name, and it will create any folders specified in the URL as required. File meta data will be updated if any properties are passed.

To use this code add a reference to the SharePoint Lists service (/_vti_bin/Lists.asmx) and name it ‘ListsService’. The code was written against MOSS 2007.

To download files use the GetItem method of the SharePoint Copy service (/_vti_bin/Copy.asmx). While it’s possible to upload files using the CopyIntoItems method of this service, it won’t create folders as needed, and you’d probably want to remove the copy link that is created.

It's also possible to use Front Page Server Extensions and RPC calls to upload files with meta data - the code for which is a bit more efficient as it doesn't require web service calls. Using RPC calls is covered in Part II.

Update: You can download a comprehensive c# class library to automate RPC calls - including uploading files to a SharePoint document library. See this blog post for more information.

69 comments:

Nothing - the code above does use HTTP PUT to write the file, and if a simple write is all you want to do then you're right - that's all you need.

If you want to write meta data though you have to do a bit more than that. The code above goes a step beyond that, because it discovers the document library name from the URL, creates any folders, and persists the list information so it doesn't have to re-query the web service.

Yeah, could be a bit dodgy. For custom lists, you might want to take a look at the AddAttachment operation that the Lists web service provides. It won't work for uploading files to document libraries but it might be what you're after.

If all the bytes are getting uploaded, I would guess it's a machine related issue. Try testing on a different machine or user profile. Clearing your temporary internet files can sometimes fix browser problems. Also, there's a second post (Part II) that uses a different technique for uploading if you're convinced it's the code in this example.

Great code! I noticed that the version history is incremented by a version once the file metadata has been added. It would be nice if when uploading it would keep the same version when the initital file metadata is added (i.e. for custom content types/columns on the document library). Do you think that this is actually possible using your code?

Nice idea and good coding!I used another hack for uploading to a DocLib using existing Web Services: 1. Upload the file to an ImageLib with Imaging.Upload2. Copy/Move the file with Copy.CopyIntoItemsLocal

since it uses existing Web Services, it only needs ~70 lines of code.

Source and sample project is available at http://blog.janus.cx/archives/251-Uploading-any-file-to-a-SharePoint-DocumentLibraray-using-WebServices.html

I'm following the basic structure of the article to upload to a document library via HTTP PUT. It works great.

Here's one problem I'm having though ... if versioning is turned on for the document library AND require check out is set to yes for the document library, then after the doc is uploaded it remains checked out. See this URL for more details:

So you think solving this problem would be easy -- just use the Lists.CheckInFile web service call to execute the check in. However, this is not working. WSS is returning the following error:

The system cannot find the file specified. (Exception from HRESULT: 0x80070002)

After playing around some more, if I take the URL to the newly uploaded file (the same one I pass to CheckInFile) and paste that URL into a new browser window, the browser window returns a 404 PAGE NOT FOUND error. However, if open a new browser window, login to my SharePoint site, *then* paste the URL into the browser window, the document opens fine.

Thus, for new documents that have yet to be checked in, SP is apparently throwing a 404 unless you are already logged in. Thus, the CheckInFile web service call must be failing for the same reason.

Other ways you can think of to work around this? Can check in be done via a RPC call or something?

If you have some time, I was wondering what this was doing --if (updatesResponse.FirstChild.FirstChild.InnerText != "0x00000000") throw new Exception("Could not update properties.");

I get that exception randomly from users. Some times they can close out and redo it and it works. So, I'm guessing that "0x00000000" means that it was successful. But, is there anyway to determine why it wasn't?

Ben, format your DateTime fields in the ISO 8601 format with a time zone designator for the zero UTC offset after it (a 'Z'). The DateTime field should in the local time zone (i.e. not actually converted to UTC).

apg - the API is implemented through dlls that are installed on the server only. Even if you have the dlls installed on a client machine, you'll receive a FileNotFoundException when trying to connect to a remote server. This is because the "SharePoint object model can only be used when the application is run on a server in the SharePoint farm. It cannot be executed remotely." (See the first problem resolution in the SharePoint Development and Programming FAQ.)

An example of uploading a file that resides locally on the server using the API can be found here.

The code works, but I haven`t understood why some files are well uploaded, but another - otherwise!The code retruns me the error 409, when WebResponse response = request.GetResponse(); was executing! Could you please make me clear in this problem?

Take a look at my reply to the first comment in Part II of this post - hopefully that'll point you in the right direction re authorship. ID is an uniquifier assigned by SharePoint so you won't be able to specify that - the creation date/time is also written by SharePoint.

Hi,Please help a newbie: When I use VS2008, should I create a ServiceReference or a webreference to make this work?No matter what I try, I get this:(It is driving me nuts!)

"The type or namespace name 'ListsService' could not be found (are you missing a using directive or an assembly reference?) D:\SP_uploader_using_web_services\SP_uploader_using_web_services\Program.cs 69 13 SP_uploader_using_web_services"Thanks in advance!/Björn

When you create the Web Reference to the SharePoint Lists service (/_vti_bin/Lists.asmx) and name it ‘ListsService’, VS2008 automatically generates code with the default namespace (e.g. ConsoleApplication1) for your project (to change this, see the properties tab - right click on your project in the solution explorer). Couple of easy fixes: either change the default namespace to DevHoleDemo before adding the reference, or change the namespace from DevHoleDemo to your default namespace. You can also view the code that is generated when the reference is added by clicking the Show All Files button in the solution explorer, and then expanding the web references tree until you get to Reference.cs - you'll be able to see what namespace is being used in the generated code there.

Interestingly, if you upload a file where the document library does not exist you do not get an error. Something DOES get uploaded because if you then create the library, the url of it has a 1 appended (as if it found a conflicting name). Weird.

Hi,I tried uploading a document using this class, the document get uploaded with no issues. But how can I get the Id of the document uploaded. On the updateRespose i can only see ErrorCode node. No z:row node is returned.

Hi txs8311 and Björn,I get the same error as the "The type or namespace name 'UserProfileService' does not exist in the namespace 'CreateUserProfile.UserProfileService' (are you missing an assembly reference?)"

Can you pl elaborate what you meant by looking into the Reference.cs file. I don't think I understood properly.Thanks.Zullu

I added the namespace ConsoleApplication1.CreateUserProfile with the line "using ConsoleApplication1.CreateUserProfile;"

This will include the code that was generated automatically when I added a reference to the web service. If you show all files in the VS solution explorer (use the show all files button at the top) and then expand the reference until you see the code (reference.cs) you'll see the namespace you need to add.

txs8311,Thanks for your prompt reply.Yes, I am using the UserProfileService web service. But here I have the same problem as any other web service.I understand what you are trying to explaing here with your code. I already have that line "using CreateUserProfile.UserProfileService;" in my code, but I still get the same error.I am not sure why you are not a compile error while instantiating the "proxy" in line:UserProfileService proxy = new UserProfileService();I am stuck, can you provide some more help.Thanks in advance.Zullu

Hey! Has anyone had any trouble with file overwrite using this method? I have implemented this technique in my own document provider, however once I've uploaded once, any subsequent uploads do not overwrite. No exceptions are thrown, and I can step through the whole process, however the same file remains in WSS afterwards. How can this be?!

Hi,I used your file uploading code and it is working like a charm in MOSS2007/Win2003 environment. But when I tried the same thing in MOSS2007/Win2008/Vista environment, the Upload function throws "405 Method Not Allowed" error. Is there anything I have to change in the code in order to work with MOSS2007 hosted on Win2008.ThanksNK

Hi! I tried the solution but every time I run I receive a catch that says that it cannot find the list.I have tried different variations of the list but cannot get by the message.I changed the sharepoint location to my own and put in a structure that didn't exist. Other than that there are no changes.

A few people have noted that they cannot find the Lists object in their ListService object.

Error: The type or namespace name 'Lists' does not exist in the namespace 'ListsService' (are you missing an assembly reference?)

Make sure you add Lists.asmx service as a Web Reference, not a Service Reference. This MSDN article on Web Service Guidelines sheds some light on how to do that. http://msdn.microsoft.com/es-es/library/ms458094.aspx. Scroll down to Guidelines for Using the ASP.NET Web Services.

When uploading a document from CRM to SharePoint, the first version of the document is 2. This is because versioning is turned on and when you upload the document it is Version 1 and when you update the Meta data it is considered as Version 2. Is there a solution for this issue. I want the version to remain as 1.

Thanks for the great code! I have found it works well when used with a MOSS2007 server. However, when I try to implement it into a MOSS2010 environment I come across a problem. Everything seems to work fine until it comes time to update the metadata within the 'TryToUpload' function. The file uploads fine but when it tries to update the data at 'UpdateListItems' I get the error that the file doesn't exist when in fact it does.Has anyone had this problem? Any clues...PLEASE!!!

Earlier in the month I had posted about a problem with updating column data in MOSS2010 (where it had worked fine in 2007). The cause was that 2010 requires the doc ID where 2007 was happy with just a doc reference.

To fix this, I added a function to get the doc id and then added this to the update xml.

Love the post... it a wonderful piece of work.. Thank you so much.. it helped me a ton...

@vnroopa@gmail.com :

I am sure you would have fixed the error by now.. if anybody else faces the issue :

Check if the column names to which you are trying to update values are right. If it is a custom column, then sharepoint internally appends 00x20 in between for the spaces. Open the site in the sharepoint designer,check for the column name and put that here... it works like a charm..

just a quick query... the code you have given.. first uploads the doc and then updates the meta data where it creates new version of the doc... is there a way tat i can upload the doc with the properties inserted together without creating a new version ???