I was working on a solution at work where they wanted to tag and approve all documents submitted to the site. SharePoint 2010’s Content Organizer seemed like it would meet their needs. I turned on approval for the drop off library and made the default content type be document. That way when a external user submitted a document, they would just hit save and then the internal user who is approving it, would change it’s content type, fill out the metadata, and approve it. Then the content organizer routing kicks in and puts it in the correct location.
This all worked great when working with a single document. What didn’t work well is if you have several documents that needed to have the same metadata applied, approved, and routed. I turned to Batch Edit on CodePlex for this piece. I had used it before and with a few tweaks it worked great. I ran into two issues though in this scenario.
- Batch Edit didn’t allow me to edit the content types, so we still had to go to each item individually to change it’s content type
- Batch Edit had no way to approve the items
- When saving an item programmatically in SharePoint, the routing rules did not process the item until the timer job ran (typically set to run at night once a day).
I wrote some code to fix #1 which was pretty straight forward and I can include the code here on the blog if someone leaves a comment saying they want it. #2 involved adding a second button to the page that says save and approve and a little extra code on the save to check if that button was pressed and approve the item. #3 was a lot harder than I thought it would be to get resolved.
Initially I was using OfficialFileCore.SubmitFile(). After realizing there were some additional permissions needed (Records Center Web Service Submitters SP group) I actually got it working. It seems that OfficialFileCore.Submit() is mainly used to put a file INTO the drop off library and run the routing rules against that file. The issue was that the files I needed to push through were already in the drop off library, and when using the OfficialFileCore.SubmitFile(), it made an extra copy of those files in the drop off library with a random name that I would somehow need to figure out and delete. This is not exactly what I wanted and seemed overly complicated.
Remember that timerjob that runs nightly to process items in the drop off library and send emails out about items missing metadata, it’s called the Content Organizer Processing job (Microsoft.Office.RecordsManagement.Internal.RecordsRepositoryJobDefinition). I reflectored it and found it was calling an internal method named ProcessWaitingFiles which was looping through all of the files and calling another internal method named ProcessWaitingFile(SPListItem, bool). This second one was really interesting to me since it only required the SPListItem needing to process and a bool which is whether or not moderation is enabled on the library. Using reflection I was able to call this method and my files in the drop off library got routed just like I was doing them individually.
Here’s the code:
private void ProcessDropOffLibraryItem(SPWeb web, SPListItem item, bool listRequiresModeration) { EcmDocumentRoutingWeb routingWeb = new EcmDocumentRoutingWeb(web); Type clsSPRequest = typeof(EcmDocumentRoutingWeb).Assembly.GetType("Microsoft.Office.RecordsManagement.RecordsRepository.EcmDocumentRoutingWeb", true); System.Reflection.MethodInfo processWaitingFile = clsSPRequest.GetMethod("ProcessWaitingFile", BindingFlags.Instance | BindingFlags.NonPublic); try { object result = processWaitingFile.Invoke(routingWeb, new object[] { item, listRequiresModeration }); } catch (System.Reflection.TargetInvocationException ex) { string message = string.Format("Unable to route file {0}: {1}", item.File.ServerRelativeUrl, ex.Message); SPCriticalTraceCounter.AddDataToScope(67, "SP2010 BatchEdit", 1, message + ": " + ex.StackTrace); } }
Thanks,
I was just going through this same process when I came across your code.
I’m sure I speak for others when I say I’d like to see what you did to fix #1.
My solution was to create a new button to manipulate the content type, mostly b/c I wanted to leave the batch edit code “clean”.
Thanks
-KK
Yea, what you did makes sense. I had already fixed a few things in Batch Edit so I just modified the code. I added a dropdownlist control for the top that displayed all of the content types available for the list.
Then I check upon saving that if you changed the content type then instead of redirecting to settings or closing the modal I redirected to batchedit again with the new contenttypeid in the querystring so the end user sees the updated fields and can easily proceed.
I am speaking at the Charlotte SharePoint Saturday event coming soon about this and some other work I’ve been doing. So be on the look out on my blog and i’ll post my slidedeck and you can see some screenshots of my implementation.
You rock this was very helpful!
Hi Steve,
I am trying to do the same thing but using the SPFile.SendToOfficialFile method. During the SendTo operation I am trying to retain the file properties like Created By, Created Time etc. Although the CT is coming in fine but the created and modified information is modified. Is there a way to preserve this info?
Regards,
Fahad
I don’t believe that information can be preserved. Sorry.
Pingback: Process items in a Drop Off library using PowerShell | Bart's Hideout
Hi Steve, do you know what the 2013 flavour of “Microsoft.Office.RecordsManagement” is, I have been looking for the last hour and cant find it.
Thanks…Mark
Many thanks for this great post ! Save me a lot of time.