赏梅斋

关注微软技术

博客园 首页 新随笔 联系 订阅 管理
  90 Posts :: 2 Stories :: 171 Comments :: 32 Trackbacks

公告

通常,调用应用程序无论何时使用新 SPSite 构造函数(任何签名),都应该在用完对象之后调用 Dispose() 方法。如果 SPSite 对象是从 GetContextSite() 中获得的,则该调用应用程序 应该释放对象。因为 SPWebSPSite 对象会保留通过此方式派生的内部列表,所以释放对象可能会导致 SharePoint 对象模型行为无法预料。SharePoint Foundation 在页面完成之后会在内部枚举此列表以正确释放对象。

SPSiteCollection 类

SPSiteCollection.Add 方法

SPSiteCollection.Add 方法将创建并返回新的 SPSite 对象。应该释放从 SPSiteCollection.Add 方法中返回的任何 SPSite 对象。

不良的编码实践

void SPSiteCollectionAddLeak()
{
    SPWebApplication webApp = new SPSite("http://www.msiw.net/;
    SPSiteCollection siteCollections = webApp.Sites;
    SPSite siteCollection = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\\User",
      "spirit@msiw.net");
    // SPSite siteCollection leak.
}
 

良好的编码实践

void SPSiteCollectionAddNoLeak()
{
    SPWebApplication webApp = new SPSite("http://www.msiw.net/;
    SPSiteCollection siteCollections = webApp.Sites;
    using (SPSite siteCollection = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\\User",
      "spirit@msiw.net"))
    {
    } // SPSite object siteCollection.Dispose() automatically called.
}

SPSiteCollection [ ] 索引运算符

SPSiteCollection [] 索引运算符会针对每次访问返回一个新的 SPSite 对象。将会创建 SPSite 实例,即使已经访问了该对象也不例外。以下代码示例演示了 SPSite 对象的不正确释放过程。

不良的编码实践 #1

void SPSiteCollectionIndexerLeak()
{
    using (SPSite siteCollectionOuter = new SPSite("http://www.msiw.net/"))
    {
        SPWebApplication webApp = siteCollectionOuter.WebApplication;
        SPSiteCollection siteCollections = webApp.Sites;

        SPSite siteCollectionInner = siteCollections[0];
        // SPSite siteCollectionInner leak.
    } // SPSite object siteCollectionOuter.Dispose() automatically called.
}

不良的编码实践 #2

使用 foreach 循环

void SPSiteCollectionForEachLeak()
{
    using (SPSite siteCollectionOuter = new SPSite("http://www.msiw.net/"))
    {
        SPWebApplication webApp = siteCollectionOuter.WebApplication;
        SPSiteCollection siteCollections = webApp.Sites;

        foreach (SPSite siteCollectionInner in siteCollections)
        {
            // SPSite siteCollectionInner leak.
        }
    } // SPSite object siteCollectionOuter.Dispose() automatically called.
}

良好的编码实践 #1

使用索引运算符

void SPSiteCollectionIndexerNoLeak()
{
    using (SPSite siteCollectionOuter = new SPSite("http://www.msiw.net/"))
    {
        SPSite siteCollectionInner = null;
        try
        {
            SPWebApplication webApp = siteCollectionOuter.WebApplication;
            SPSiteCollection siteCollections = webApp.Sites;

            siteCollectionInner = siteCollections[0];
        }
        finally
        {
            if (siteCollectionInner != null)
                siteCollectionInner.Dispose();
        }
    } // SPSite object siteCollectionOuter.Dispose() automatically called.
}

良好的编码实践 #2

使用 foreach 循环

void SPSiteCollectionForEachNoLeak()
{
    using (SPSite siteCollectionOuter = new SPSite("http://www.msiw.net/”))
    {
        SPWebApplication webApp = siteCollectionOuter.WebApplication;
        SPSiteCollection siteCollections = webApp.Sites;

        foreach (SPSite siteCollectionInner in siteCollections)
        {
            try
            {
                // ...
            }
            finally
            {
                if(siteCollectionInner != null)
                    siteCollectionInner.Dispose();
            }
        }
    } // SPSite object siteCollectionOuter.Dispose() automatically called.
}

SPSite.AllWebs 属性 (SPWebCollection)

SPSite.AllWebs.Add 方法

SPSite.AllWebs.Add 方法将创建并返回 SPWeb 对象。应该释放从 SPSite.AllWebs.Add 中返回的任何 SPWeb 对象。

不良的编码实践

void AllWebsAddLeak()
{
    using (SPSite siteCollection = new SPSite("http://www.msiw.net/"))
    {
        SPWeb web = siteCollection.AllWebs.Add("site-relative URL");
        // SPWeb object leaked.
    }  // SPSite object siteCollection.Dispose() automatically called.
}

良好的编码实践

void AllWebsAddNoLeak()
{
    using (SPSite siteCollection = new SPSite("http://www.msiw.net/"))
    {
        using (SPWeb web = siteCollection.AllWebs.Add("site-relative URL"))
        {
        } // SPWeb object web.Dispose() automatically called.
    }  // SPSite object siteCollection.Dispose() automatically called.
}

SPWebCollection.Add 方法

SPWebCollection.Add 方法将创建并返回需要释放的 SPWeb 对象。

不良的编码实践

void SPWebCollectionAddLeak(string strWebUrl)
{
    using (SPSite siteCollection = new SPSite("http://www.msiw.net/"))
    {
        using (SPWeb outerWeb = siteCollection.OpenWeb())
        {
            SPWebCollection webCollection = siteCollection.AllWebs; // No AllWebs leak just getting reference.
            SPWeb innerWeb = webCollection.Add(strWebUrl);  // Must dispose innerWeb.
            // innerWeb leak.
        } // SPWeb object outerWeb.Dispose() automatically called.
    }  // SPSite object siteCollection.Dispose() automatically called.
}

良好的编码实践

void SPWebCollectionAddNoLeak(string strWebUrl)
{
    using (SPSite siteCollection = new SPSite("http://www.msiw.net/"))
    {
        using (SPWeb outerWeb = siteCollection.OpenWeb())
        {
            SPWebCollection webCollection = siteCollection.AllWebs; // No AllWebs leak just getting reference.
            using (SPWeb innerWeb = webCollection.Add(strWebUrl))
            {
                //...
            }
        } // SPWeb object outerWeb.Dispose() automatically called.
    }  // SPSite object siteCollection.Dispose() automatically called.
}

SPSite.AllWebs [ ] 索引运算符

SPSite.AllWebs [] 索引运算符会在每次访问对象后返回一个新的 SPWeb 实例。索引操作过程中将会创建对象,即使已经访问了该对象也不例外。如果未正确关闭,则以下代码示例会将 SPWeb 对象保留在 .NET Framework 垃圾收集器中。

不良的编码实践

void AllWebsForEachLeak()
{
    using (SPSite siteCollection = new SPSite("http://www.msiw.net/"))
    {
        using (SPWeb outerWeb = siteCollection.OpenWeb())
        {
            foreach (SPWeb innerWeb in siteCollection.AllWebs)
            {
                // Explicitly dispose here to avoid out of memory leaks with large number of SPWeb objects.
            }
        } // SPWeb object outerWeb.Dispose() automatically called.
    }  // SPSite object siteCollection.Dispose() automatically called.
}

良好的编码实践 #1

使用 foreach 循环

void AllWebsForEachNoLeakOrMemoryOOM()
{
    using (SPSite siteCollection = new SPSite("http://www.msiw.net/"))
    {
        using (SPWeb outerWeb = siteCollection.OpenWeb())
        {
            foreach (SPWeb innerWeb in siteCollection.AllWebs)
            {
                try
                {
                    // ...
                }
                finally
                {
                    if(innerWeb != null)
                        innerWeb.Dispose();
                }
            }
        } // SPWeb object outerWeb.Dispose() automatically called.
    }  // SPSite object siteCollection.Dispose() automatically called.
}

良好的编码实践 #2

使用索引运算符

void AllWebsIndexerNoLeak()
{
    using (SPSite siteCollection = new SPSite("http://www.msiw.net/"))
    {
        using (SPWeb web = siteCollection.AllWebs[0])
        {
        } // SPWeb object web.Dispose() automatically called.
    }  // SPSite object siteCollection.Dispose() automatically called.
}

SPSite.OpenWeb 和 SPSite. SelfServiceCreateSite 方法

SPSite 对象的 OpenWeb() 方法和 SelfServiceCreateSite 方法(所有签名)将创建 SPWeb 对象并将其返回给调用方。此新对象未存储在 SPSite 对象中,并且未在 SPSite 类中的任何地方被释放。因此,应该释放通过这些方法创建的任何对象。

不良的编码实践

void OpenWebLeak()
{
    using (SPWeb web = new SPSite(SPContext.Current.Web.Url).OpenWeb())
    {
        // SPSite leaked !
    } // SPWeb object web.Dispose() automatically called.
}

良好的编码实践

void OpenWebNoLeak()
{
    using (SPSite siteCollection = new SPSite("http://www.msiw.net/"))
    {
        using (SPWeb web = siteCollection.OpenWeb())
        {
        } // SPWeb object web.Dispose() automatically called.
    }  // SPSite object siteCollection.Dispose() automatically called.
}

SPSite.RootWeb 属性

前面的指导指明了调用应用程序释放 SPSite.RootWeb 属性应该发生在即将释放使用该属性的 SPSite 对象之前。这不再是正式的指导。释放清理是由 SharePoint Foundation 和 SharePoint Server 自动处理的。此外,SPSite 属性 LockIssueOwnerSecondaryContact 在内部使用了 RootWeb 属性。按照 RootWeb 的更新的指导,每当使用其中的任意属性时对 SPSite.RootWeb 属性调用 Dispose 方法不再是可取的。

良好的编码实践

public void RootWebBestPractice()
{
    // New SPSite.
    using (SPSite siteCollection = new SPSite("http://www.msiw.net/"))
    {
        SPWeb rootWeb1 = siteCollection.RootWeb;
        // No explicit rootWeb1 dispose required.
    }  // siteCollection automatically disposed by implementing using().
    // rootWeb1 will be Disposed by SPSite.

    // SPContext and SPControl
    SPWeb rootWeb2 = SPContext.Current.Site.RootWeb;
    // Also would apply to SPControl.GetContextSite(Context);
    // No explicit rootWeb2 dispose required because it is obtained from SPContext.Current.Site.
}

 
posted on 2011-02-11 18:04 赏梅斋 阅读(...) 评论(...) 编辑 收藏