SPWeb.Site, следует ли вам называть Dispose()?
Обновлено 06/08/2009 15:52: короткий ответ НЕТ. Оригинальный вопрос:
Я не могу найти ссылку, которая дает рекомендации по SPWeb.Site относительно утилизации. Я рассмотрел некоторые из наиболее популярных рекомендаций по удалению объектов SharePoint:
К сожалению, ни одно из этих рекомендаций не упоминает SPWeb.Site. Чтобы дать некоторый контекст, я пишу публичный API расширений, который принимает SPWeb в качестве аргумента для метода i.e.:
public static void GetWebPartFromCatalog(this SPWeb web, string webPartName)
{
......
SPSite site = web.Site;
......
**OR** ??
using (SPSite site = web.Site)
{
....
}
}
Я посмотрел как метод Close() в refelector для SPWeb, который вызывается SPWeb.Dispose(), и в нем нет ничего, чтобы указать, что фактическое поле члена SPSite удалено.
Обновление: 06/08/2009 13:47
В предложение Alex
"Поместите его в цикл, который выполняется 100 раз и использует раздел реестра SPRequestStackTrace, описанный в разделе" Устранение неполадок SPSite/SPWeb в WSS v3 и MOSS 2007, чтобы проверить, что ваш тестовый код является источником проблемы ".
Я запустил следующий фрагмент кода, включенный внутри веб-части:
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. Было бы очень полезно получить конкретный ответ от кого-то, кто более информирован по этому вопросу.
Обновление: 06/08/2009 14:52
Подготовлено Greg Comment Я разработал назначения m_Site и, похоже, он в конечном счете всегда передается в SPWeb через внутренние конструкторы. Например. SPWeb.OpenWeb переходит в этот к новому SPWeb(). Поэтому я уверен, что SPWeb.Site должен быть не удален, действительно может вызвать проблемы, если это было.
Ответы
Ответ 1
Ответ Кирка правильный. Перед созданием SPWeb вы должны иметь дескриптор SPSite, и это тот же самый экземпляр SPSite, который вы будете иметь при вызове SPWeb.Site.
Подумайте о последствиях этого - если вы не контролируете создание SPSite, но один из его дочерних веб-страниц передается вам из внешнего кода, и вы удаляете сайт, когда управление возвращается вызывающему коду, вы разместили сайт, с которым они не могут быть выполнены! Поместите себя в боксы вызывающего кода: вы передаете SPWeb в метод, и когда этот метод будет выполнен, SPSite, который вы использовали, был закрыт. Ответственность за очистку ресурсов, которые они выделяют, всегда является обязанностью instanciator. Не используйте SPSite в этом случае.
Ответ 2
Просто размышляя над моей головой (иногда опасно)...
Кажется, что у вас действительно нет SPWeb без SPSite. Итак, если вы получили SPWeb, не пройдя через SPSite, чтобы получить его (либо с помощью нового SPSite, либо с помощью одного из них), вам, вероятно, не нужно беспокоиться об утилизации SPSite.
Это просто гипотеза. Хороший вопрос!
Ответ 3
Это не ясно. Существует блог Stefan, в котором указано . Вам нужно убедиться, что вы только размещаете объекты SPSite и SPWeb, которыми принадлежит ваш код.. Тогда есть этот поток от Michael Washam (Microsoft), в котором говорится, что этот шаблон просачивается.
Если вы не можете найти другую ссылку или кто-то другой знает, почему бы вам не протестировать ее на своем сервере разработки и не добавить свои результаты в качестве ответа на этот вопрос? Поместите его в цикл, который выполняется 100 раз и использует раздел реестра SPRequestStackTrace, описанный в Устранение утечек SPSite/SPWeb в WSS v3 и MOSS 2007 для проверки что ваш тестовый код является источником проблемы.
Ответ 4
Отражатель говорит нам, что это код, который выполняется внутри объекта SPWeb при вызове свойства Site:
public SPSite Site
{
get
{
return this.m_Site;
}
}
Он не создает новый объект SPSite, просто возвращает тот, который у него уже есть, и, если необходимо, он будет работать с SPWeb.Dispose(). Таким образом, вы можете безопасно использовать его, и я бы не захотел избавиться от него, чтобы зависания SPWeb ни на что не мешали вам.
Ответ 5
Вы пытались проверить свою сборку с помощью SPDisposeCheck? Возможно, это дает вам подсказку, как справиться с вашей проблемой.
Ответ 6
Я часто использую этот шаблон в своем коде 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
, чтобы сделать что-то с веб-частями.
- свойство web.Site действительно очищает после себя, если веб-сайт расположен.
- Почему бы просто не передать объект SPSite и не позволить пользователю функции беспокоиться об этом?
В большинстве случаев я бы подумал, что они будут звонить с использованием SPContext.Current.Site в любом случае.
- В большинстве случаев мне приходится беспокоиться о разрешениях, но не все наши DLL попадают в GAC, поэтому, когда я пишу новый метод расширения, мне приходится обертывать его
SPSecurity.CodeToRunElevated
С этими соображениями я в конечном итоге напишу это как., теперь Dispose check будет отключен в этом случае, потому что 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
}
};
}
Ответ 7
У Стефана Гобнера есть отличная статья:
Устранение утечек SPSite/SPWeb в WSS v3 и MOSS 2007
... И не забудьте использовать инструмент проверки SPDispose на вашей кодовой базе.
Ответ 8
Вам нужно удалить экземпляр SPSite/SPWeb, если это новый объект
например,
using(SPSite site = new SPSite("url"))
{
DoSomething;
}
здесь использование позаботится об удалении объекта
однако, если у вас есть ссылка на объект из SPContext.Current, вы не должны явно указывать объект, поскольку ссылка должна быть доступна из SPContext.Current.