如果我们想要关注SharePoint网站中的存储使用情况的话,SharePoint中可以使用spSite.Usage获取当前网站集的存储占用情况(这是一个名为UsageInfo的结构,它的Storage属性就是网站集占用的字节数)。
但是通过这种方法我们只能得到网站集的存储使用情况,无法得到更细粒度比如网站、文档库、文件夹使用了多少存储空间(需要注意的是,一个文件所占用的存储空间不一定是这个文件的大小,如果你开启了版本控制的话,那么所有的版本都应该计算到占用的存储空间中)。
在SharePoint 2010 SP1中,新增了一个叫Storage Metric的功能(中文版不恰当地翻译成了“存储标准”),可以看到网站集中每一级别所使用的存储空间(详细介绍可以参考我之前写过的这篇Blog:SharePoint 2010 SP1新功能(存储标准))。
但遗憾的是,这个新增功能的涉及到的所有代码都是internal的,它在数据库里新增的两个表结构都很简单,但是那个存储过程比较复杂,也很难直接从这个方法去获取,因此,就只剩下了一个选择:反射。
通过反射的方法,我们可以调用SPSite中的内部方法GetStorageMetrics,它会返回一个SPStorageMetricsResult的类,里面的Children属性中是一个List<SPStorageMetricItem>,这一些东西都是internal的,但都可以通过反射来获取到。
我为SPSite扩展了一个同名的方法GetStorageMetrics,实现这个功能,完整的代码如下(单独的cs文件下载点我点我):
1: using System;
2: using System.Collections;
3: using System.Collections.Generic;
4: using System.Linq;
5: using System.Reflection;
6: using System.Text;
7: using Microsoft.SharePoint;
8:
9: namespace Erucy.Utilities
10: {
11: public class SPStorageMetricItem
12: {
13: public enum MetricType
14: {
15: Invalid = -1,
16: File = 0,
17: Folder = 1,
18: Web = 2
19: }
20:
21: public string DisplayName { get; private set; }
22: public Guid Id { get; private set; }
23: public DateTime LastModified { get; private set; }
24: public long? TotalSize { get; private set; }
25: public MetricType Type { get; private set; }
26: public string Url { get; private set; }
27: public Guid WebId { get; private set; }
28:
29: public SPStorageMetricItem(object metricObj)
30: {
31: this.DisplayName = (string)GetPropValue(metricObj, "DisplayName");
32: this.Id = (Guid)GetPropValue(metricObj, "Id");
33: this.LastModified = (DateTime)GetPropValue(metricObj, "LastModified");
34: this.TotalSize = (long?)GetPropValue(metricObj, "TotalSize");
35: this.Url = (string)GetPropValue(metricObj, "Url");
36: this.WebId = (Guid)GetPropValue(metricObj, "WebId");
37:
38: string itemType = Convert.ToString(GetPropValue(metricObj, "Type"));
39: switch (itemType)
40: {
41: case "File":
42: this.Type = MetricType.File;
43: break;
44: case "Folder":
45: this.Type = MetricType.Folder;
46: break;
47: case "Web":
48: this.Type = MetricType.Web;
49: break;
50: default:
51: this.Type = MetricType.Invalid;
52: break;
53: }
54: }
55:
56: private object GetPropValue(object obj, string propertyName)
57: {
58: PropertyInfo propInfo = obj.GetType().GetProperty(propertyName,
59: BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.ExactBinding);
60: return propInfo.GetValue(obj, null);
61: }
62: }
63:
64: public static class StorageMetricExtension
65: {
66: public static List<SPStorageMetricItem> GetStorageMetrics(this SPSite site, string root, int orderBy, bool isAscending)
67: {
68: MethodInfo getMetricMethod = typeof(SPSite).GetMethod("GetStorageMetrics",
69: BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.ExactBinding);
70: object metricResultObj = getMetricMethod.Invoke(site, new object[] { root, orderBy, isAscending });
71:
72: PropertyInfo childrenProperty = metricResultObj.GetType().GetProperty("Children",
73: BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.ExactBinding);
74: IList rawMetricItems = childrenProperty.GetValue(metricResultObj, null) as IList;
75:
76: List<SPStorageMetricItem> result = new List<SPStorageMetricItem>(rawMetricItems.Count);
77: foreach (object metricObj in rawMetricItems)
78: {
79: result.Add(new SPStorageMetricItem(metricObj));
80: }
81: return result;
82: }
83: }
84: }
其中的SPStorageMetricItem类和SharePoint内置的那个internal类基本上是一致的,可以获取到相关的信息,包括:
- DisplayName:名称
- Url:Url地址
- LastModified:最后修改时间
- Id:对象的Guid(如果对象是网站/列表的话,这个Id并不是网站/列表ID,而是他们的根文件夹的ID)
- WebId:所在网站的Id
- Type:类型,包括网站、文件夹、文件
- TotalSize:对象占用的存储空间,以字节为单位
在使用的时候很简单,有三个参数:
- root:根路径,方法会返回这个路径中所有子网站和子文件夹、文件所占用的大小空间,使用相对服务器的路径
- orderBy:排序(这个原本是一个internal的枚举,我就偷懒直接用int了),0是按照TotalSize排序,1是按照LastModified排序
- isAscending:正序或逆序
这个在使用的过程中会有如下几个需要考虑的问题:
1、因为使用了反射,所以速度会有点慢
2、必须是SharePoint 2010 SP1以及之后的版本(因为功能是在SP1才有的)
3、如果root参数不是网站的话(比如你想获取一个文档库中若干文件夹占用的存储空间),运行在非IIS进程中的时候会报错。这个和SharePoint底层那个COM的实现有关,没什么解决办法。