根据某个“众所周知”的原因,当我们使用SharePoint的CSOM(客户端对象模型)上载文件的时候,推荐使用SaveBinaryDirect取代FileCollection.Add的方法(详细原因可以参考:Uploading files using Client Object Model in SharePoint 2010)。但是今天发现,如果网站集设置了配额模版,并且网站的使用空间已经达到/超过存储配额的时候,SaveBinaryDirect在某种情况下会出现奇怪的行为:
如果我们使用overwrite参数的那个重载的时候,如果overwrite为true(强行覆盖服务器端同名文件),如果超出了配额限制,会产生一个代号507的WebException,提示我们空间不足(这个正常);但是当我们使用overwrite为false的时候,会产生一个ClientRequestException,并提示我们已经存在同名文件(这就很奇怪了)。
通过对Microsoft.SharePoint.Client.dll反编译,我们会发现SaveBinaryDirect某些情况下并没有考虑到这种情况:
红框那个位置就是这个异常的来源,可以看到只要HttpStatusCode不是PreconditionFailed(412),就会返回文件名已存在的异常(使用ETag的是另外一个重载)。
根据实际测试可以发现,当网站集已经达到/超过配额的时候,和文件重名的时候,Http状态码确实都是412,这两种情况下唯一的分别就是在Response的Header中,一个名字叫X-MSDAVEXT_Error的头,前者的时候是“589923”后面跟着详细的错误描述(就是我们从页面中上载文档时看到的那个已达到配额的异常文字),后者是589951后面跟着详细的错误信息。实际上,我们可以从这篇文档([MS-WEBDAV]: Service Error Code)中看到这两种情况分别是“Quota Exceeded”和“A file with the same name exists”。
因此只能说微软在做这个API的时候没有考虑到这种情况,所以如果需要的话,我们只能自己重写这个方法(中间会用到一次反射调用一个internal方法),代码如下:
2: {
new Uri(ctx.Url), serverRelUrl)).AbsoluteUri;
4:
5: WebRequestExecutor webRequestExecutor = ctx.WebRequestExecutorFactory.CreateWebRequestExecutor(ctx, absolutePath);
false;
;
;
9:
10: Stream requestStream = webRequestExecutor.GetRequestStream();
byte[0x400];
true)
13: {
int num = stream.Read(numArray, 0, 0x400);
int num1 = num;
if (num <= 0)
17: {
break;
19: }
20: requestStream.Write(numArray, 0, num1);
21: }
22: requestStream.Flush();
23: requestStream.Close();
24:
,
26: BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.ExactBinding);
new WebRequestEventArgs(webRequestExecutor) });
28:
try
30: {
31: webRequestExecutor.Execute();
if (webRequestExecutor.StatusCode != HttpStatusCode.Created && webRequestExecutor.StatusCode != HttpStatusCode.OK)
33: {
object[2];
35: responseContentType[0] = webRequestExecutor.ResponseContentType;
36: responseContentType[1] = webRequestExecutor.StatusCode;
, responseContentType));
38: }
39: }
catch (WebException webEx)
41: {
42: WebException webException = webEx;
as HttpWebResponse;
null || response.StatusCode != HttpStatusCode.PreconditionFailed)
45: {
throw;
47: }
))
49: {
new Exceptions.ServerFullException();
51: }
else
53: {
));
55: }
56: }
57: }