SharePoint开发中的最佳实践(续)
13.SharePoint中的非托管对象需要我们手动释放资源
SPGlobalAdmin、SPSite、SPWeb、SPFileStream等等一些对象需要进行手动释放资源。由于SharePoint中有这些非托管对象,所以我们编程的时候应该特别注意,如果有些资源没有释放,会造成内存溢出。并且很多时候我们自定义的程序是由IIS调用的,如果没有释放资源,可能会是IIS 崩溃,造成不必要的麻烦。
14.SharePoint中不能上传大小为0 KB的文件,由于SharePoint上传文档的时候会将这个文件的内容一并写进数据库的Content字段,如果文件的大小是0,则这个byte [] 将没有内容,所以不会成功。如果我们要对0KB的文件进行上传的话,我们需要使用程序进行特殊处理:
一是可以在这个文件中添加我们的标识信息,当取得其中的内容的时候我们也可以将标识信息去掉,然后就是内容信息。或者使用API也是可以处理添加0 KB 文件的。或者使用Explorer View进行上传也可以上传大小为0 KB的文件。
15.当SharePoint中list打开Version开关的时候,我们可以对文档的操作进行使用版本控制,并且可以根据不同时间的修改产生的不同的version来取得不同version的文档。在这里下载不同的version的文档有不同的地址,我们可以根据version来计算这个文档的地址。如果打开Major Version的时候version会按照1.0、2.0、、、递增,如果是打开Major和Minor Version的时候version会按照0.1、0.2、、、递增,当前的也就是version最大的文档的地址是正常的,历史的version的文档的地址是不同的,在站点url后面加上_vti_history/version的个位*512 + 小数点后的数字/文档url。
16.SharePoint中的内存泄漏问题
(1) 当使用 list.ParentWeb,或folder.ParentWeb 等等只要使用这个ParentWeb属性,那么这个ParentWeb是需要释放的。
(2) 同样道理,我们只要使用了web.Site属性,那么这个Site对象是需要释放的。
(3) 我们一般对这两个对象进行释放的时候,都是使用Dispose()方法,其实Dispose()方法内部也只是简单的调用了Close()方法,但是我们还是建议使用Dispose()方法进行释放。这样不会造成一些SharePoint API自身产生的一些错误。
(4) 使用OpenWeb()方法和SelfServiceCreateSite()方法时都会返回一个SPWeb对象,这些对象都需要进行手动释放。
(5) 我们使用索引器取得Site或是Web的时候,都需要进行手动释放,因为我们去的了SPWeb和SPSite都会在内存中申请相应的空间,但是由于是非托管的对象所以我们还是以需要进行手动释放的。
(6)当我们使用SPSite的LockIssue、Owner、SecondaryContact属性的时候,会隐式的调用RootWeb属性,所以我们需要对这个RootWeb对象进行释放。
(7)如果我们使用了SPSite的LockIssue、Owner、SecondaryContact属性的时候,会隐式的调用RootWeb属性,那么这样我们必须对rootweb这个对象进行释放。例如:
SPSite site = new SPSite(serverUrl);
String str = Site.LockIssue;
Site.RootWeb.Dispose();
Site.Dispose();
当web的ParentWeb属性为空的时候,我们使用的时候会调用OpenWeb方法来返回一个SPWeb对象,所以在程序最好释放ParentWeb的时候,我们需要判断一下ParentWeb对象是否为null,如果不为Null那就要对其进行释放。
(8) 当我们在try-catch-finally中使用Response.Redirect()方法进行页面重定向的时候,程序不会执行finally中的代码。因为在try中执行一个页面重定向的方法,会导致这个线程结束,并且产生一个异常,并且这个异常将会被运行时捕获,导致不会指定finally里面的代码。所以建议我们有页面跳转的时候要使用Using来释放相应的资源。例如:
不建议使用的方法
SPSite site = null
Try
{
Site = new SPSite(“http://serverurl”);
Response.Redirect(destUrl);
}
Catch
{}
Finally
{
If(site != null)
{
Site.Dispose();
}
}
建议使用的方法
Using(SPSite site = new SPSite(“http://serverurl”))
{
Response.Redirect(url);
}
如果坚持使用try-catch-finally那就必须在页面定向之前对非托管对象进行释放,例如:
SPSite site = null
Try
{
Site = new SPSite(“http://serverurl”);
Site.Dispose();
Response.Redirect(destUrl);
}
Catch
{}
Finally
{
If(site != null)
{
Site.Dispose();
}
}
(9) 我们使用UserProfile的时候可以返回一个PersonalSite,这个PersonalSite也是需要释放的
void PersonalSiteLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
UserProfile profile = profileManager.GetUserProfile("domain//username");
SPSite personalSite = profile.PersonalSite; //需要释放
personalSite.Dispose();
}
}
17.调用COM需要手动释放资源
我们使用Trados SDK是以COM的形式进行调用的,所以在这里存在一个对COM对象进行资源释放的问题,因为COM对象不会自己进行资源释放,我们只能通过显示的调用GC进行资源回收。例如:
Application app = new Application();
Marshal.FinalReleaseComObject(app);
app = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
这里需要进行两次调用
GC.Collect();
GC.WaitForPendingFinalizers();因为第一次只是对未释放的资源的统计,第二次才是真正的释放。第一次就是看有哪些COM对象的资源没有释放,而在第二则是根据第一次统计的结果进行对COM资源的回收。
18.SharePoint Dispose Check Tool(内存泄漏代码检查工具)
主要用来检查我们编写的exe或是dll文件内部是否有SharePoint 对象使用的内存泄漏,可以在 http://code.msdn.microsoft.com/SPDisposeCheck站点进行下载。
具体的使用方法:
安装这个检查工具,然后使用命令行运行这个exe,然后将要检查的exe或是dll拷贝到这个工具的安装路径下面,然后在这个SPDisposeCheck.exe sample.dll命令进行检查。
19.对于我们的系统,要有严格的异常处理机制和日志输出。在程序中输出日志,日志可以跟踪程序运行,当程序运行到一个地方,输出相应的日志,这样我们就可以根据日志的显示情况,知道程序运行的情况。方便定位程序出错的位置和修改。现在我们可以在服务器上直接调试,但是如果我们的系统做成产品,卖给客户的时候,我们是不可能在客户的环境上进行调试的,所以系统日志是必不可少的。主要是为了方便查找错误,然后解决问题。如果客户环境上出现问题,我们可以让客户将系统运行的日志给我们返回,这样我们可以根据日志就可以之后系统在客户端运行出现了什么错误,然后给予相应的解决方法即可。