Tuesday, March 13, 2007

Move file in event handler causes "No item exists" Error

I have been playing around with an event handler that moves files after they have been uploaded to a document library. This is useful in scenarios where you want people to upload files (or post infopath forms) to a library, then analyze the meta data and move it to another library automatically based on what the user chose in the meta data.

A cool example of how we may use this is an infopath form where the user's details are getting pulled from a database, including his "state" attribute. The event handler, when seeing the user is from a specific state, moves the document to a document library where it will be accessabile only by the people in the same state. This way alerts can be set be state and a seperate workflow can be developed for each state and so on.

The code is actually easy. I don't use the SPFile.MoveTo() function since it doesn't support moving to other sites, and that may be required. So I wrote a function that gets the source file (SPFile) and the target folder (SPFolder), copies the file by reading it's stream and then deletes the source file. This ofcourse can be improved in the future.

private static void MoveFile(SPFile fileToMove, SPFolder targetFolder)



Stream s = fileToMove.OpenBinaryStream();

        targetFolder.Files.Add(fileToMove.Name, s);





The problem I discovered that even though I was running the code in the ItemAdded event, the code would run when the file is uploaded. This causes a big problem, since sharepoint 2007, after uploading the file checks if there are any properties (meta data) it needs to ask the user for, and redirects him to the meta data entry screen. But my event handler already deleted the file!

So every time the user uploads a file, he will see:
"No item exists at http://site/web/library/Forms/EditForm.aspx?Mode=Upload&CheckInComment=&ID=23&RootFolder=/web/library&Source=http://site/library/Forms/view.aspx. It may have been deleted or renamed by another user."

I have tried using the "ItemCheckedIn" event instead, with no luck - it is not called when a file is uploaded. It looks like the sequence of events is:

  • ItemAdding

  • ItemAdded

  • ItemUpdating (this is after the user enters the metadata)

  • ItemUpdated

So from this we can conclude (and I tested to confirm) that if you want to move a file on upload, do it in the ItemUpdated event, or the ItemUpdating event.

The problem is, if the user presses "Cancel" in the metadata window, the file will remain in the library, since the "Updating" events didn't trigger.

What to do? I honestly don't know. It seems we cannot develop an event handler that moves files automatically and will trap all documents uploaded, without causing errors on the screen for the user.


Anders Rask said...

Hi, it sounds strange that the ItemAdded event would check for meta data, since this check is already done *before* the page is posted (as with normal ASP.NET Page.IsValid); are you sure that this is what triggers the redirect?

In my experience with list item event handlers, small things can wreck havoc on the code (like calling SPContext which will just exit the code without throwing an exception!).

Also deleting the file will probably cause an ItemDeleted or ItemUpdated/-ing event (depending on library type) so i would recommend disabling eventfiring using

//do update/delete

to avoid redirects.

If you post more code maybe others can chime in :-)

Anders Rask

Anonymous said...

This would be more work than a simple event handler, but have you considered trying a WorkFlow for this? You could use a state workflow, and under the condition that either the item is updated (the MetaData is submitted) or X amount of time has passed, the WorkFlow would move to the next state, where it would move it to another document library.

Unknown said...

This is not true.
If you didn't add additional columns to the document library, only itemadded is performed.

You have to check the item if the editform is going to be displayed, otherwise you have to handle the moving in itemadded.

Another issue if you have multiple columns:
If the user clicks cancel inside the editform, itemupdated is not performed, so the document is not moved.

But even if you have multiple columns, when you perform the multiple upload the editform is not going to be displayed...

Conclusion: You can not determine where you have to move your document.