SharePoint对于文档库的操作有很多,但如果需要从非.NET环境的第三方系统操作SharePoint文档,可选项就不多了,常规做法是使用SharePoint提供的Webservice来操作。
虽然文档库也是列表,但webservice中的Lists.asmx主要用于操作普通数据列表,对于文档库中文档的操作则爱莫能助,这里可以使用Copy.asmx服务。Copy.asmx的设计功能是用来在不同的文档库之间拷贝文档文件,但这并不妨碍使用它来实现上传文档的功能。
Copy.asmx中实现文档拷贝上传的方法是Copy.CopyIntoItems,其方法声明为:
public uint CopyIntoItems (
string SourceUrl,
string[] DestinationUrls,
FieldInformation[] Fields,
byte[] Stream,
out CopyResult[] Results
)
各项参数的详细说明可以参考MSDN文档:http://msdn.microsoft.com/en-us/library/copy.copy.copyintoitems(v=office.14).aspx
使用此方法时,有一些要点需要注意:
1. SourceUrl与DestinationUrls的格式:
这两个参数中的url都必须是以http://或者https:// 开头的完整路径,例如:http://127.0.0.1/Shared Documents/javaUpload.txt ,其它相对于站点或者相对于文档库的相对路径都是不被支持的,但是url支持空格,Shared Document不必转换为Shared%20Document。
2. SourceUrl与DestinationUrls的值
DestinationUrls是上传的目标地址数组,对于上传来讲,一般也就只有一个地址,不必上传到多个位置。
SourceUrl参数是值拷贝的原地址,不得为null或空字符,SharePoint会跟踪这个地址,当查看文档属性的时候会出现拷贝源提示:
This item is a copy of http://127.0.0.1/Shared Documents/javaUpload.txt
( Go To Source Item | Unlink )
对于文档上传来讲,当然就没有拷贝源地址,这个时候SourceUrl可以设置为目标地址,也就是拷贝源与拷贝目标地址一致,不过这样会带来一个问题,就是无法通过此拷贝方法来上传并覆盖已经存在的文档,对于需要覆盖文档的情况,可以把SourceUrl设置为http://void(0),这样SharePoint就不会再跟踪拷贝源,查看的时候也不会提示拷贝源,而且可以上传并覆盖已存在的文档。
3. FieldInformation的值
FieldInformation是文档属性的数组,也就是list的field数组,这里的FieldInformation对象包含5个属性,可以参考MSDN文档:http://msdn.microsoft.com/en-us/library/copy.fieldinformation_members(v=office.14).aspx
这些参数其中最为重要的是参数为Id、DisplayName、Type、Value,value当然是需要设置的值了,而唯一确定一个字段的属性是Id和DisplayName,SharePoint会首先以Id进行确认,如果没有找到再以DisplayName查找,有的字段只能通过Id查找,因此保险的做法是给Id和DisplayName都赋值,而十分奇怪的是InternalName却似乎没有什么作用,此外Type也是必不可少的参数,如果Type参数设置错误,那么这个字段也是无效的(Note类型可以兼容Text类型)。关于SharePoint服务器端的逻辑可以用Reflector查看,代码位于C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\CONFIG\BIN\STSSOAP.DLL中的Microsoft.SharePoint.SoapServer. CopyImpl.此外,字段无法找到的错误既不会返回也不会抛出异常,字段值转换失败的错误则会返回失败代码和错误信息。如果一个字段触发操作失败,则所有的字段值都不会被提交。此时,文档可能已经上传成功,也可能上传失败,这取决于触发异常的位置。
4. CopyResult的值与输出
当上传文件成功,CopyResult的ErrorCode会返回Success,而ErrorMessage属性会返回null,当目标地址DestinationUr不存在等原因导致上传失败的时候,ErrorMessage属性会返回具体的错误信息,但是,很重要的一点就是:当FieldInformation中的字段找不到的时候,是不会返回任何异常或错误的,ErrorCode返回Success,显示操作已成功。
5. 关于ContentType
可能是由于ListItem的CopyFieldMask的影响(也可能是其它原因),上传的文档的ContentType总是文档库的默认ContentType,这一属性无法通过FieldInformation进行更改,关于这个问题只有在文档上传成功以后,通过Lists.asmx的UpdateListItem进行更改了,暂时没有找到其它解决办法。
6. 关于LinkToDocument内容类型
在各种Document的内容类型中有一个特殊的内容类型——LinkToDocument,这个ContentType仅创建对文档的引用链接,而不会产生新的文档,算是各种文档类型的异类了,处理的时候需要多加小心。(Document的ContentTypeId为0x0101;LinkToDocument的ContentTypeId为0x01010A)
毕竟Copy.CopyIntoItems是为拷贝而设计的,在上传文档的时候还是有诸多不便,使用起来也很是别扭,要想用的舒心,还是得自己动手了。