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.對於我們的系統,要有嚴格的異常處理機制和日誌輸出。在程序中輸出日誌,日誌可以跟蹤程序運行,當程序運行到一個地方,輸出相應的日誌,這樣我們就可以根據日誌的顯示情況,知道程序運行的情況。方便定位程序出錯的位置和修改。現在我們可以在服務器上直接調試,但是如果我們的系統做成產品,賣給客戶的時候,我們是不可能在客戶的環境上進行調試的,所以系統日誌是必不可少的。主要是爲了方便查找錯誤,然後解決問題。如果客戶環境上出現問題,我們可以讓客戶將系統運行的日誌給我們返回,這樣我們可以根據日誌就可以之後系統在客戶端運行出現了什麼錯誤,然後給予相應的解決方法即可。