<CharlieDigital/> Programming, Politics, and uhh…pineapples

21Oct/10Off

Programmatically Submitting Files to the SharePoint Content Organizer

The content organizer in SharePoint 2010 is an interesting feature, particularly from an application development perspective as it gives you a fairly competent rules builder (why does it post back when you select a content type?  Like seriously, Microsoft?) and routing engine, for free.  We built something similar in FirstPoint for SharePoint 2007, but it was quite a bit of work.  You can do all sorts of interesting things with this such as moving documents around based on metadata changes or externalizing the rules that determine where server generated documents should be routed to.

The content organizer can be accessed from the Official Files web service but it can also be accessed directly when building server applications such as event receivers or custom web services.  One common scenario, for example, is using an event receiver for moving a document to a different folder or library if a user changes a metadata field.  If I have a list of contacts organized into folders by last name (A-C, B-E, etc.), I'd want the system to automatically move a contact into the correct folder if a contact changes his or her last name.  Without the content organizer and externalized rules, you'd either have to hard code the routing rules or design and code a system to externalize the routing rules, both sub-optimal solutions compared to the content organizer.

Behind the scenes, content organizer users a class called OfficialFileCore, you'll need to add a reference to Microsoft.Office.Policy.dll (found in the ISAPI directory) to your project.  The following is some code that should give you an idea of how to call the OfficialFileCore.SubmitFile() method:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.Office.RecordsManagement.RecordsRepository;
using System.Collections;

// Namespace and class omitted for formatting purposes...

static void Main(string[] args)
{
    Microsoft.SharePoint.OfficialFileResult result = Microsoft.SharePoint.OfficialFileResult.UnknownError;
    string destination = null; // New location of the file is assigned to this string.

    using (SPSite site = new SPSite("http://moss.dev.com/"))
    using (SPWeb web = site.OpenWeb())
    using (new SPMonitoredScope("Official File Receiver", uint.MaxValue, new ISPScopedPerformanceMonitor[] { new SPSqlQueryCounter(100) }))
    {
        SPFile file = web.GetFile("http://moss.dev.com/dropofflibrary/test1.docx");
        byte[] bytes = file.OpenBinary();
        string fileType = file.Item.ContentType.Name;
        SPFieldCollection fields = file.Item.Fields;

        List<Microsoft.SharePoint.RecordsRepositoryProperty> properties
            = new List<Microsoft.SharePoint.RecordsRepositoryProperty>();

        // Create a RecordsRepositoryProperty for each metadata field.
        foreach (SPField field in fields)
        {
            try
            {
                string value = Convert.ToString(
                    field.GetFieldValue(Convert.ToString(file.Item[field.Title])));

                Console.Out.WriteLine("Name:{0}, Type:{1}, Value:{2}",
                    field.Title, field.TypeAsString, value);

                Microsoft.SharePoint.RecordsRepositoryProperty property =
                    new Microsoft.SharePoint.RecordsRepositoryProperty
                    {
                        Name = field.Title,
                        Type = field.TypeAsString,
                        Value = value
                    };

                properties.Add(property);
            }
            catch (Exception exception)
            {
                // Some fields fail; not sure if they're consequential yet!
                Console.Out.WriteLine(" - Failed to process field {0}", field.Title);
            }
        }

        result = OfficialFileCore.SubmitFile(web, bytes, properties.ToArray(), fileType,
            "http://moss.dev.com/dropofflibrary/test1.docx", "Charles", false, out destination);

        // Seems that you have to manually delete the file.
        file.Item.Delete();
    }

    Console.Out.WriteLine("1 > {0}", result);
    Console.Out.WriteLine("2 > {0}", destination);
}

In this case, the source library is the drop off library.  Note that if you programmatically add a file to the library, it doesn't actually get routed according to the content organizer rules; you'll still have to submit it manually in the UI or use the code outlined above to actually trigger the routing.

One final note: as far as I can tell, it seems that you have to manually delete the file from the source library once you successfully route the file.

Posted by Charles Chen

Filed under: .Net, SharePoint Comments Off
Comments (2) Trackbacks (0)
  1. awesome post, helped me customize my code to upload a file using a usercontrol and get it into the drop off library for routing. p.s the way im doing this is uploading to the document library direct(no routing), getting the SPFile, then injecting your code which submits it to the drop off library where it gets sent to the correct library. couldnt seem to figure out a way to have a file uploaded from a usercontrol go direct to the drop off library using your code as it has to be an SPFile..i couldnt cast the FileUpload.PostedFile to an SPFile obviously. anyways, im just wondering thats all…its working so maybe if its not broken, dont fix it? 🙂

    • Bruce,

      I haven’t tried it without creating an SPFile first. Seems that it needs one since one of the parameters is the current URL of the file (it puzzles me as well why this is necessary given that it doesn’t seem to do anything with it).

      One note is that this code seems to cough up on certain types of fields like term store fields.

      Gonna work on that and figure out what the deal is.


Trackbacks are disabled.