因为Routing在Record Center中是控制文件流向的关卡,因此是很重要的一个功能.本文讲述如何创建一个Custom Router(router中文可能翻成路由吧).
在MOSS中创建一个Customer Router还是一个比较方便的工作,主要工作就是创建一个实现IRouter接口的类,主要流程在OnSubmitFile中实现.
class CustomRouting : IRouter
{
     public RouterResult OnSubmitFile(string recordSeries, string sourceUrl,string userName, ref byte[] fileToSubmit, ref RecordsRepositoryProperty[] properties,ref SPList destination, ref string resultDetails)    
     {        
          return RouterResult.SuccessContinueProcessing;    
     }
}
这里稍微说明一下返回值.一共有三种返回值,以防我的误导在这里用msdn原文:
RouterResult.SuccessContinueProcessing:   The router has successfully completed its processing, and the record repository continues with its processing of the document.
RouterResult.SuccessCancelFurtherProcessing:   The router has successfully completed its processing, but the record repository discontinues its processing of the document. The record repository returns a success value to the calling application, as well as the contents of the resultData parameter.
RouterResult.RejectFile:   The router did not complete its processing successfully. The record repository returns an error to the calling application, as well as the contents of the resultData parameter.
从我的经验一般直接了当的是使用SuccessContinueProcessing和RejectFile,如果你要自己控制文件存贮可以使用SuccessCancelFurtherProcessing.
这里我的例子是根据传入文件的url地址在Document Library创建相应的文件夹,然后将文件放入相应的文件夹.由于是例子,代码就很简单,只写关键功能了.
主体部分很简单,就是先拿一个值作为判断标准,然后用Handle进行处理
public RouterResult OnSubmitFile(...)
        {
            try
            {
                string status = GetStatus(properties);
                string contentType="Test";

                if (string.IsNullOrEmpty(status))
                {
                    Trace.WriteLine("You cannot send this kind of file to Record Center");

                    return RouterResult.RejectFile;
                }

                Handle(status, contentType, sourceUrl, fileToSubmit, properties, destination);

                return RouterResult.SuccessCancelFurtherProcessing;

            }
            catch (Exception ex)
            {
                resultDetails = "Failed to route record: " + ex.Message;
                Trace.WriteLine(resultDetails);
                return RouterResult.RejectFile;
            }
        }
取属性值的函数:
private string GetStatus(Microsoft.Office.RecordsManagement.RecordsRepository.RecordsRepositoryProperty[] properties)
        {
            foreach (Microsoft.Office.RecordsManagement.RecordsRepository.RecordsRepositoryProperty p in properties)
            {
                if (p.Name == "Category")       //////任意你要的字段
                {
                    return p.Value;
                }
            }
            return null;
        }
处理函数:
private void Handle(string status, string contentType, string sourceUrl, byte[] fileToSubmit, Microsoft.Office.RecordsManagement.RecordsRepository.RecordsRepositoryProperty[] properties, SPList destination)
        {
            // Create a new filename using the date & time
            string sFileName = Path.GetFileNameWithoutExtension(sourceUrl) + Path.GetExtension(sourceUrl);
            string[] pathSlit = sourceUrl.Split("/".ToCharArray());
            string path1 = pathSlit[2];  /////任意取其中的一个,我这里取两级
             string path2 = pathSlit[3];

            SPFolder oFolder = GetDestinationFolder(status, path1,path2, destination);

            // Add the document
            SPFile oFile = oFolder.Files.Add(sFileName, fileToSubmit);
            SPListItem oItem = oFile.Item;

             //////存属性值
            oItem["ContentTypeId"] = destination.ContentTypes[contentType].Id;
            oItem.Update();

            foreach (Microsoft.Office.RecordsManagement.RecordsRepository.RecordsRepositoryProperty p in properties)
            {
                if (oItem.Fields.ContainsField(p.Name))
                {
                    try
                    {
                        if (CopyField(p.Name, oItem))
                            oItem[p.Name] = p.Value;
                    }
                    catch (Exception ex)
                    {
                        Trace.WriteLine(string.Format("Failed to copy field '{0}': {1}", p.Name, ex.Message));
                    }
                }
            }

            oItem.Update();
        }

找文件和建文件夹的相关代码:
 private SPFolder GetDestinationFolder(string status, string path1, string path2, SPList destination)
        {
            //SPFolder ctFolder = FindFolder(path, destination.RootFolder.SubFolders);
            string rootPath = string.Empty;

            if (status == "Category1")  
            {
                rootPath = "Category1";
            }
            else  
            {
                rootPath = "Category2";
            }

            SPFolder ctFolder = FindFolder(rootPath, destination.RootFolder.SubFolders);

            if (ctFolder == null)
            {
                destination.RootFolder.SubFolders.Add(rootPath);
                ctFolder = FindFolder(rootPath, destination.RootFolder.SubFolders);
            }

            SPFolder destinationFolder1 = FindFolder(path1.ToUpper(), ctFolder.SubFolders);

            if (destinationFolder1 == null)
            {
                destinationFolder1 = ctFolder.SubFolders.Add(path1.ToUpper());
            }

            SPFolder destinationFolder = FindFolder(path2, destinationFolder1.SubFolders);

            if (destinationFolder == null)
            {
                destinationFolder = destinationFolder1.SubFolders.Add(path2);
            }

            return destinationFolder;
        }

        private SPFolder FindFolder(string name, SPFolderCollection oContainer)
        {
            foreach (SPFolder f in oContainer)
                if (f.Name == name) return f;

            return null;
        }

存属性值的函数,但这个不能保证把属性值全存进去.
 private bool OkToCopyField(string name, SPListItem oItem)
        {
            try
            {
                SPField oField = oItem.Fields.GetField(name);

                // Field does not exist in the destination content type
                if (oField == null) return false;

                // Can't copy readonly fields
                if (oField.ReadOnlyField) return false;

                // Can't chenge the content type
                if (oField.InternalName == "ContentType") return false;

                // Other fields types which cannot be copied
                if ((((oField.Type == SPFieldType.Invalid) || (oField.Type == SPFieldType.WorkflowStatus)) || ((oField.Type ==

SPFieldType.File) || (oField.Type == SPFieldType.Computed))) || (((oField.Type == SPFieldType.User) || (oField.Type == SPFieldType.Lookup))))
                    return false;
            }
            catch { return false; }

            return true;
        }
最后的部署我是用Feature的,就是写类public class FeatureReceiver: SPFeatureReceiver.这方面的文章已经不少,我就不罗嗦了.
至此,一个Custom Router已经做好了.虽然简单但若扩展还是很可以做一些功能的.这里最大的问题是原文件的字段值不能全部传入.这似乎是一个普遍性的问题,而且在<管理员手册>和mdsn中有模糊甚至略有矛盾的阐述.普通情况下是系统会专门建一个文件夹然后以xml的格式存进去,但当我们用自己的Routing时不是总是这样的.这个问题有待以后解决.创建新的Router如图: