18

更新于 2009 年 6 月 8 日 15:52简答NO原始问题:

我找不到任何关于SPWeb.Site处置指导的参考资料。我浏览了一些关于处置 SharePoint 对象的更流行的最佳实践文档:

不幸的是,这些指南都没有提到 SPWeb.Site。为了给出一些上下文,我正在编写一个公共扩展 API,它接受 SPWeb 作为方法的参数,即:

public static void GetWebPartFromCatalog(this SPWeb web, string webPartName)
{
     ......

     SPSite site = web.Site;
     ......

     **OR** ??

     using (SPSite site = web.Site)
     {
         ....
     }
}

我在 SPWeb 的反射器中查看了 Close() 方法,该方法由 SPWeb.Dispose() 调用,其中没有任何内容表明实际的 SPSite 成员字段已被处理。

更新:2009 年 6 月 8 日 13:47

亚历克斯的建议下

“将其放入一个运行 100 次的循环中,并使用在 WSS v3 和 MOSS 2007 中排除 SPSite/SPWeb 泄漏中描述的 SPRequestStackTrace 注册表项来检查您的测试代码是否是问题的根源。”

我运行了 webpart 中包含的以下代码:

 for (int i = 0; i < 100; i++)
 {
     using (SPWeb web = SPContext.Current.Site.OpenWeb(""))
     {
            SPSite site = web.Site;
            Debug.WriteLine(site.Url);
     }
 }

SharePoint 日志中未显示任何内容。

虽然我会犹豫从这个幼稚的实验中得出任何真正的结论,但这表明没有必要处置 SPWeb.Site。如果能从对此主题更了解的人那里得到具体的回答,那就太好了。

更新:2009 年 6 月 8 日 14:52 由 Greg 的评论提示,我计算出了 m_Site 的分配,看起来它最终总是通过内部构造函数传递给 SPWeb。例如,SPWeb.OpenWeb 将其传递new SPWeb()。所以我更确定 SPWeb.Site 不应该处置,如果是的话,确实会导致问题。

4

8 回答 8

8

柯克的回答是正确的。在创建 SPWeb 之前,您必须对 SPSite 有一些句柄,这与调用 SPWeb.Site 时将拥有的 SPSite 实例相同。

让我们考虑一下它的含义 - 如果您不控制 SPSite 的创建,但它的子网站之一是从外部代码交给您的,并且您处置该站点,当控制权返回给调用代码时,您已经处理了一个他们可能无法完成的站点!设身处地为调用代码着想:您将一个 SPWeb 传递给一个方法,当该方法完成时,您正在使用的 SPSite 已关闭。清理他们分配的资源始终是实例化者的责任。在这种情况下不要丢弃 SPSite。

于 2009-08-06T14:21:37.423 回答
5

只是想着我的头顶(有时很危险)......

如果没有 SPSite,您似乎就无法真正拥有 SPWeb。因此,如果您在没有通过 SPSite 的情况下获得了 SPWeb(通过新的 SPSite 或提供给您的 SPSite),那么您可能不需要担心处置 SPSite。

不过,这只是推测。好问题!

于 2009-08-06T12:19:09.143 回答
2

这不清楚。Stefan 的博客指出“您需要确保只处理您的代码拥有的 SPSite 和 SPWeb 对象”。然后是Michael Washam (Microsoft) 的这个线程,指出这种模式确实泄漏。

除非您可以找到其他参考资料或其他人知道,否则为什么不在您的开发服务器中对其进行测试并将结果添加为该问题的答案?将其置于运行 100 次的循环中,并使用在 WSS v3 和 MOSS 2007 中排除 SPSite/SPWeb 泄漏中描述的 SPRequestStackTrace 注册表项来检查您的测试代码是否是问题的根源。

于 2009-08-06T10:09:06.470 回答
2

Reflector 告诉我们,当您调用 Site 属性时,这是在 SPWeb 对象内运行的代码:

public SPSite Site
{
    get
    {
        return this.m_Site;
    }
}

它不是创建一个新的 SPSite 对象,只是返回它已经拥有的对象,如果需要,这将由 SPWeb.Dispose() 来处理。因此,您可以安全地使用它,并且我会避免丢弃它,以免 SPWeb 依赖项对您造成影响。

于 2009-08-06T13:12:09.227 回答
1

您是否尝试过使用SPDisposeCheck检查您的程序集?也许它会给你一个提示如何处理你的问题。

于 2009-08-06T10:04:06.463 回答
1

如果调用 depose 不会使我调用它的任何东西崩溃,我经常在我的 SharePoint 代码中使用这种模式作为经验法则。我遵循的另一条规则是我尽量不要创建不会导致对象净收益的扩展SPRequestSPRequest对象是与所有重量级 com 对象对话的 .net 对象)

现在分解你的例子

 for (int i = 0; i < 100; i++)
 {
     using (SPWeb web = SPContext.Current.Site.OpenWeb(""))
     {
            SPSite site = web.Site;
            Debug.WriteLine(site.Url);
     }
 }

这里的关键是SPContext.Current.SiteThe SPContextwill clean up after it's self correct (少数几个这样做的对象之一),因为我们知道该站点已正确清理我希望网络已清理干净,但这远非正确答案对你的问题。(请注意,您应该泄露通过 OpenWeb 获得的网络)

public static void GetWebPartFromCatalog(this SPWeb web, string webPartName)

您需要SPSite使用 Web 部件来完成任务。

  1. 如果 web 被处理,web.Site 属性实际上会在它自身之后进行清理。
  2. 为什么不直接传入 SPSite 对象,让函数的用户操心呢?在大多数情况下,我认为他们无论如何都会使用 SPContext.Current.Site 进行调用。
  3. 大多数时候我不得不担心权限问题,并不是我们的每个 dll 最终都在 GAC 中,所以当我编写一个新的扩展方法时,我最终不得不将它包装成一个SPSecurity.CodeToRunElevated

考虑到这些,我最终会将其写为 . . . 现在 Dispose 检查将在这种情况下进行,因为 SPSite 作为参数传入,因为它无法追踪它在哪个范围内被处理。

public static void GetWebPartFromCatalog(this SPSite site, string webPartName) {
     SPSecurity.CodeToRunElevated( () => {
         using(SPSite suSite = new SPSite(site.Id)){
             //do what you need to do
         }
     };
}
于 2009-08-06T14:12:48.277 回答
1

Stefan Gobner 对此有一篇出色的文章: Troubleshooting SPSite/SPWeb leaks in WSS v3 and MOSS 2007

...并确保在您的代码库上使用SPDispose 检查工具

于 2009-08-06T14:25:55.840 回答
0

如果是新对象,则需要删除 SPSite / SPWeb 实例

例如

using(SPSite site = new SPSite("url"))
{
    DoSomething;
}

此处using将负责删除对象,但是如果您从 SPContext.Current 获得对象的引用,则不应显式处置该对象,因为该引用应可从 SPContext.Current 获得。

于 2011-04-19T15:16:53.350 回答