SPWeb.Site, стоит ли на нем вызывать Dispose ()?

Обновлено 08.06.2009, 15:52: Краткий ответ НЕТ. Исходный вопрос:

Я не могу найти какой-либо справочной информации на 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)
     {
         ....
     }
}

Я посмотрел как метод Close () в рефлекторе для SPWeb, который вызывается SPWeb.Dispose (), и в нем нет ничего, что указывало бы на то, что фактическое поле члена SPSite удалено.

Обновление: 08.06.2009 13:47

По предложению Алекса

"Put it in a loop which runs 100 times and use the SPRequestStackTrace registry key described in Troubleshooting SPSite/SPWeb leaks in WSS v3 and MOSS 2007 to check that your test code is the source of the problem."

Я запустил следующий фрагмент кода, включенный в веб-часть:

 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. Было бы неплохо получить конкретный ответ от более осведомленного человека.

Обновление: 08.06.2009 14:52 По запросу Грега Я разработал назначения m_Site и, похоже, в конечном итоге он всегда передается в SPWeb через внутренние конструкторы. Например. SPWeb.OpenWeb передает this в новый SPWeb (). Так что я более уверен, что SPWeb.Site не удаляться, ведь в противном случае могут возникнуть проблемы.


person Edward Wilde    schedule 06.08.2009    source источник
comment
Глядя на это, непонятно. Я задал тот же вопрос, что и комментарий к сообщению Роджера Лэмба, но не получил ответа.   -  person Alex Angas    schedule 06.08.2009
comment
На мой взгляд, и это просто мнение, нет, вы никогда не должны выбрасывать этот объект. Почему? Ну, он возвращается через свойство из другого объекта. Если этот другой объект является одноразовым, вы должны избавиться от этого и позволить ему позаботиться о своих собственных ресурсах. Ничто из того, что вы читаете из свойства, не должно удаляться вашим собственным кодом, так как я считаю это ошибкой в ​​этой структуре.   -  person Lasse V. Karlsen    schedule 06.08.2009
comment
@ lasse-v-karlsen Я согласен с вами на 100%, однако в API SharePoint есть много причуд, и вам действительно нужно понимать их, иначе возникнет риск утечки памяти. Так что, хотя это может быть ошибка в API, я хотел бы понять, есть она или нет :)   -  person Edward Wilde    schedule 06.08.2009
comment
Путешествие Кейта Далби в попытки решить эту проблему для SPList.ParentWeb: решение проблем .net / 2008/08/10 / is-splistparentweb-a-leak   -  person Alex Angas    schedule 07.08.2009
comment
Хорошее обсуждение и эксперименты - извините, что пропустил! :)   -  person dahlbyk    schedule 20.08.2009
comment
@ Lasse-V-Karlsen Я считаю, что единственное свойство, которое возвращает SPSite, которое вам нужно удалить, - это Microsoft.Office.Server.UserProfiles.UserProfile.PersonalSite.   -  person dahlbyk    schedule 20.08.2009


Ответы (8)


Ответ Кирка правильный. Перед созданием SPWeb у вас должен быть какой-то дескриптор SPSite, и это тот же самый экземпляр SPSite, который будет у вас при вызове SPWeb.Site.

Давайте подумаем о последствиях этого - если вы не контролируете создание SPSite, но один из его дочерних веб-сайтов передается вам из внешнего кода, и вы удаляете сайт, когда управление возвращается вызывающему коду, вы мы удалили Сайт, с которым они не могут справиться! Поставьте себя на место вызывающего кода: вы передаете SPWeb в метод, и когда этот метод будет выполнен, используемый вами SPSite будет закрыт. Ответственность за очистку ресурсов, которые они выделяют, всегда лежит на создателе экземпляра. В этом случае не утилизируйте SPSite.

person Rex M    schedule 06.08.2009
comment
По той же теории SPLimitedWebPartManager тоже должен очищаться, но этого не происходит! blogs.msdn.com/rogerla/archive/2008/02/12/ Есть ли причина того или иного несоответствия в API? - person Alex Angas; 07.08.2009
comment
@Alex Я не понимаю, как это то же самое. В приведенном вами примере SPSite и SPWeb все еще нуждаются в явной очистке, а также другой веб, экземпляр которого создается SPLimitedWebPartManager. - person Rex M; 07.08.2009
comment
Очень хорошо поставил Рекса. Вы всегда должны думать о SPWeb как о принадлежащем SPSite, а не наоборот. Тем более, что при преждевременном удалении SPSite сначала вызывается Dispose () на всех SPWeb, созданных из него. Таким образом, я всегда * предполагаю, что SPSite будет удален кодом, который его создал. (* В вики-статье описаны все известные случаи, когда очистка SPSite - ваша работа.) - person dahlbyk; 20.08.2009
comment
Думаю, теперь я понял. Если я создам SPLimitedWebPartManager, моя задача - очистить его и связанное с ним свойство Web. Чего я не понимаю, так это того, что API не был предназначен для этого за меня. Думаю, еще один вопрос ... - person Alex Angas; 20.08.2009
comment
Я сомневаюсь, что LWPM намеренно пропускает SPWeb. Вероятно, это просто игнорировалось и никогда не будет исправлено, потому что это может нарушить код, устраняющий утечку. - person dahlbyk; 20.08.2009

Просто подумайте о том, что у меня в голове (иногда опасно) ...

Кажется, что у вас не может быть SPWeb без SPSite. Итак, если вы получили SPWeb, не пройдя через SPSite для его получения (либо создав новый SPSite, либо предоставленный вам), то вам, вероятно, не нужно беспокоиться об утилизации SPSite.

Однако это всего лишь предположение. Хороший вопрос!

person Kirk Liemohn    schedule 06.08.2009
comment
Дело в том, что поскольку это метод расширения для SPWeb, вызывающая сторона вполне могла создать объект SPSite. Однако у меня нет ссылки на объект SPSite, поэтому необходимо использовать SPWeb.Site. Это приводит к вопросу, нужно ли мне убирать за собой :) Я мог бы попросить вызывающего абонента включить SPSite (добавить его в список параметров), но я не хотел увеличивать параметры метода. - person Edward Wilde; 06.08.2009

Это не ясно. Есть блог Стефана, в котором говорится: «Убедитесь, что вы удаляете только те объекты SPSite и SPWeb, которые принадлежат вашему коду». Тогда есть этот поток от Майкла Уошама (Microsoft), который утверждает, что этот шаблон действительно просочился.

Если вы не можете найти другую ссылку или кто-то еще не знает, почему бы вам не протестировать ее на своем сервере разработки и не добавить свои результаты в качестве ответа на этот вопрос? Поместите его в цикл, который выполняется 100 раз, и используйте ключ реестра SPRequestStackTrace, описанный в Устранение неполадок с утечками SPSite / SPWeb в WSS v3 и MOSS 2007, чтобы убедиться, что ваш тестовый код является источником проблемы.

person Alex Angas    schedule 06.08.2009
comment
Хорошее предложение, я попробую и опубликую результаты. - person Edward Wilde; 06.08.2009
comment
Упомянутый поток MSDN использует антипаттерн возврата ссылки SPWeb из вспомогательного метода, совершая дополнительный (и более опасный) грех, связанный с обновлением SPSite в процессе. Вместо этого этот код следует преобразовать в методы, использующие аргумент SPSite / SPWeb: solutionizing.net/2009/01/06/elegant-spsite-elevation - person dahlbyk; 20.08.2009

Reflector сообщает нам, что это код, который запускается внутри объекта SPWeb, когда вы вызываете свойство Site:

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

Он не создает новый объект SPSite, а просто возвращает тот, который у него уже был, о чем при необходимости позаботится SPWeb.Dispose (). Таким образом, вы можете безопасно использовать его, и я бы не стал избавляться от него, чтобы зависимости SPWeb не испортились вам.

person Greg Hurlman    schedule 06.08.2009
comment
Я предполагаю, что это действительно зависит от того, как назначен m_Site. Использование анализа отражателя для отображения назначенного на m_Site показывает, что он назначен в закрытом члене SPWebConstructor (), который передается на сайт через список внутренних конструкторов SPWebs .... Итак, в конце концов SPWeb никогда не сообщает о SPSite. - person Edward Wilde; 06.08.2009

Вы пробовали проверить свою сборку с помощью SPDisposeCheck? Возможно, это подскажет, как решить вашу проблему.

person Flo    schedule 06.08.2009
comment
SPDisposeCheck проверяет только те ошибки на странице «Лучшие практики», как мне кажется. - person Alex Angas; 07.08.2009

Я часто использую этот шаблон в своем коде SharePoint в качестве практического правила, если вызов depose не приводит к сбою всего, что я его называю. Другое правило, которому я следую, - я стараюсь не создавать расширения, которые не вызывают чистого выигрыша в SPRequest объектах (объект SPRequest - это объект .net, который общается со всеми тяжелыми объектами com)

теперь разбиваю ваш пример

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

Ключевым моментом здесь является SPContext.Current.Site. SPContext будет очищаться после того, как он сам правильно работает (один из немногих объектов, которые это делают), поскольку мы знаем, что сайт очищается правильно, я ожидаю, что сети были очищены до, однако это далеко от правильный ответ на ваш вопрос. (обратите внимание, что у вас должна быть утечка веб-сайтов, которые вы получили через OpenWeb)

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

вам нужно заставить SPSite что-то делать с веб-частями.

  1. свойство 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
         }
     };
}
person Chris Dibbs    schedule 06.08.2009
comment
Я думаю, вы имеете в виду SPSecurity.RunWithElevatedPrivileges - CodeToRunElevated - это тип делегата. Тем не менее, повышение по умолчанию во вспомогательном методе кажется мне плохой идеей. И если вам действительно нужно повысить уровень, вам, вероятно, лучше использовать олицетворение: solutionizing.net/2009/01/06/elegant-spsite-elevation - person dahlbyk; 20.08.2009

У Стефана Гобнера есть отличная статья по этому поводу: Устранение неполадок, связанных с утечками SPSite / SPWeb в WSS v3 и MOSS 2007

... И обязательно используйте инструмент проверки SPDispose в вашей кодовой базе.

person Chris Ballance    schedule 06.08.2009

Вам необходимо удалить экземпляр SPSite / SPWeb, если это новый объект

eg

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

здесь using позаботится об удалении объекта, однако, если вы получили ссылку на объект из SPContext.Current, вы не должны явно удалять объект, поскольку ссылка должна быть доступна из SPContext.Current.

person Sachin    schedule 19.04.2011