Share via

ICustomRouter interface

Performs custom processing on documents before they are routed to the final location.

Namespace:  Microsoft.Office.RecordsManagement.RecordsRepository
Assembly:  Microsoft.Office.Policy (in Microsoft.Office.Policy.dll)


<SharePointPermissionAttribute(SecurityAction.LinkDemand, ObjectModel := True)> _
<SharePointPermissionAttribute(SecurityAction.InheritanceDemand, ObjectModel := True)> _
Public Interface ICustomRouter
Dim instance As ICustomRouter
[SharePointPermissionAttribute(SecurityAction.LinkDemand, ObjectModel = true)]
[SharePointPermissionAttribute(SecurityAction.InheritanceDemand, ObjectModel = true)]
public interface ICustomRouter


The custom router can also cancel default behavior and route the documents.

This topic includes two code examples.

The first code example is a custom router that inspects the content of a text file that is being saved and checks it for sensitive information.

The second example registers the custom router to the content organizer-enabled site.


using System;
using System.Collections;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using Microsoft.SharePoint;
using EcmDocumentRoutingWeb = Microsoft.Office.RecordsManagement.RecordsRepository.EcmDocumentRoutingWeb;
using EcmDocumentRouter = Microsoft.Office.RecordsManagement.RecordsRepository.EcmDocumentRouter;
using ICustomRouter = Microsoft.Office.RecordsManagement.RecordsRepository.ICustomRouter;
using CustomRouterResult = Microsoft.Office.RecordsManagement.RecordsRepository.CustomRouterResult;

namespace Microsoft.SDK.SharePointServer.Samples
    public class SampleDocumentRouter : ICustomRouter
        /// <summary>
        /// A sample custom router which inspects the content of a text file being saved for sensitive information
        /// If sensitive information is found, then the information is masked and saved by the custom router.
        /// </summary>
        /// <param name="contentOrganizerWeb">The Content Organizer that invoked the custom router.</param>
        /// <param name="recordSeries">Content type of the file being organized</param>
        /// <param name="userName">The name of the user who created the file. Value can be empty if the user no longer exists.</param>
        /// <param name="fileContent">Content of the file being saved.</param>
        /// <param name="properties">Metadata for the file being saved.</param>
        /// <param name="finalFolder">The final location that the content organizer determined for this file.</param>
        /// <param name="resultDetails">Any details that the custom router wants to furnish for logging purposes.</param>
        /// <returns>Whether the content organizer should continue to save the file in the designated location</returns>
        CustomRouterResult ICustomRouter.OnSubmitFile(
EcmDocumentRoutingWeb contentOrganizerWeb,
string recordSeries, // Content type name
string userName,
Stream fileContent,
Microsoft.SharePoint.RecordsRepositoryProperty[] properties,
SPFolder finalFolder,
ref string resultDetails)
if (contentOrganizerWeb == null)
    throw new ArgumentNullException("contentOrganizerWeb");
// We should have a Content Organizer enabled web 
if (!contentOrganizerWeb.IsRoutingEnabled)
    throw new ArgumentException("Invalid content organizer.");

//Change Domain\LoginName with the login name of a site user creating this file.
const string submitterLoginName = "Domain\\LoginName";
// Change MyFileName to the required file name. This will be used if this custom router needs to save the processed file to the final location.
string modifiedFileName = "MyFileName.txt";
// Read incoming content into a string so that we can look for ssn. 
// Do not close the stream that was passed in.
string fileContentString = string.Empty;
StreamReader sr = new StreamReader(fileContent);
    fileContentString = sr.ReadToEnd();
// regular expression to match social security numbers in file content.
Regex socialSecurityRegex = new Regex("([0-9]){3}-([0-9]){2}-([0-9]){4}");
MatchCollection matches = socialSecurityRegex.Matches(fileContentString);
if (matches.Count <= 0)
    // return a string which will be logged by the content organizer.
    resultDetails = "File was inspected and no sensitive data was found.";
    return CustomRouterResult.SuccessContinueProcessing;
    string submittingUserName = userName;
    if (string.IsNullOrEmpty(userName))
        // LoginName of the user creating the file
        submittingUserName = submitterLoginName;
    // We want to fix up the file content and save the file ourselves
    using (SPSite site = new SPSite(contentOrganizerWeb.DropOffZoneUrl))
        SPWeb web = site.OpenWeb();
        // User creating the file
        SPUser submittingUser = web.SiteUsers[submittingUserName];
        string fileName = modifiedFileName;
        // Create a Hashtable of properties which forms the metadata for the file
        Hashtable fileProperties = EcmDocumentRouter.GetHashtableForRecordsRepositoryProperties(properties, recordSeries);
        // Hide sensitive content in the file stream.
        fileContentString = socialSecurityRegex.Replace(fileContentString, "***-**-****");
        byte[] modifiedByteStream = Encoding.UTF8.GetBytes(fileContentString);
        // Modify content as required and then save the modified content ourselves.
        using (MemoryStream finalStm = new MemoryStream(modifiedByteStream))
finalStm.Write(modifiedByteStream, 0, modifiedByteStream.Length);
// Save the file here since we need to modify the file.
    true /*override versioning settings on the content organizer and create a new file*/, "");

        resultDetails = "File was inspected and sensitive data was found. File has been saved with a custom name.";
        return CustomRouterResult.SuccessCancelFurtherProcessing;


using System;
using Microsoft.SharePoint;
using Microsoft.Office.RecordsManagement;
using Microsoft.Office.RecordsManagement.RecordsRepository;

namespace Microsoft.SDK.SharePointServer.Samples
    /// <summary>
    /// Sample code to register an ICustomRouter implementation in a content organizer enabled web site.    
    /// </summary>
    public class CustomRouterRegistration
        static void Main(string[] args)
//Change http://SiteUrl to the absolute url of the content organizer enabled site where the custom router needs to be registered.
const string absoluteSiteUrl = "http://SiteUrl";
// Change Custom Router to the desired name to uniquely identify this custom router. 
// The name can be using to remove the registered router from the site and will be available in the edit rule page when configuring a rule.
const string customRouterName = "Custom Router";
// Assembly name of the ICustomRouter implementation
const string customRouterAssemblyName = "SampleDocumentRouter, Version=, Culture=neutral, PublicKeyToken=29af386697ceed40";
// Name of the class that implements the ICustomRouter interface.
const string customRouterClassName = "Microsoft.SDK.SharePointServer.Samples.SampleDocumentRouter";
using (SPSite contentOrganizerSiteCollection = new SPSite(absoluteSiteUrl))
    using (SPWeb contentOrganizerSite = contentOrganizerSiteCollection.OpenWeb())
        EcmDocumentRoutingWeb contentOrganizer = new EcmDocumentRoutingWeb(contentOrganizerSite);
        contentOrganizer.AddCustomRouter(customRouterName, customRouterAssemblyName, customRouterClassName);


See also


ICustomRouter members

Microsoft.Office.RecordsManagement.RecordsRepository namespace