因为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如图: