2009-08-06 11 views
18

Aggiornamento 06/08/2009 15:52: Risposta breve NO. domanda di carattere originale:SPWeb.Site, dovresti chiamare Dispose() su di esso?

Non riesco a trovare alcun riferimento che dia indicazioni su SPWeb.Site relativo allo smaltimento. Ho passato attraverso alcuni dei più popolari documentazione di migliori pratiche in materia di smaltimento di oggetti di SharePoint:

Purtroppo nessuna di queste linee guida menziona SPWeb.Site. Per dare un po 'di contesto, sto scrivendo un API di estensione pubblico che accetta uno SPWeb come argomento di un metodo e cioè:

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

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

    **OR** ?? 

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

Ho guardato come il metodo Close() in refelector per SPWeb, che si chiama da SPWeb.Dispose() e non vi è nulla in esso per indicare che il campo membro SPSite effettivo è stato eliminato.

Aggiornamento: 06/08/2009 13:47

A Alex's suggerimento

"Mettilo in un ciclo che corre 100 volte e utilizzare la chiave di registro SPRequestStackTrace descritto nella risoluzione dei problemi SPSite/SPWeb perdite in WSS v3 e MOSS 2007 per verificare che il codice di prova sia la fonte del problema. "

ho eseguito il seguente pezzo di codice incluso all'interno di un webpart:

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

Nulla sembrava nei registri di SharePoint.

Anche se esiterei a trarre qualsiasi conclusione reale da questo esperimento ingenuo, suggerirei che sia lo non lo necessario per smaltire SPWeb.Site. Sarebbe davvero bello ricevere una risposta concreta da qualcuno più informato su questo argomento.

Aggiornamento: 06/08/2009 14:52 Spinto dal commento di Greg Ho lavorato le cessioni di m_Site e sembra che è in ultima analisi, sempre passò nelle SPWeb tramite i costruttori interni. Per esempio. SPWeb.OpenWeb passa in questo al nuovo SPWeb(). Quindi sono più sicuro che SPWeb.Site dovrebbe non essere smaltito, infatti potrebbe causare problemi se lo fosse.

+0

Guardando in questo, non è chiaro. Ho fatto la stessa domanda come commento al post di Roger Lamb ma non ho avuto risposta. –

+0

Secondo me, ed è solo questo, un'opinione, no, non dovresti mai dover smaltire quell'oggetto. Perché? Bene, viene restituito attraverso una proprietà da un altro oggetto. Se quell'altro oggetto è usa e getta, dovresti disporre di * that * e lasciare che si prenda cura delle proprie risorse. Nulla di ciò che leggi da una proprietà dovrebbe essere eliminato dal tuo stesso codice, che costituirebbe un bug in quella struttura. –

+1

@ lasse-v-karlsen Sono d'accordo con te al 100%, tuttavia ci sono molte stranezze nell'API di SharePoint e hai davvero bisogno di capirle o rischiare di perdere memoria. Quindi, anche se potrebbe essere un bug nell'API, vorrei capire se è presente o meno :) –

risposta

8

Kirk's answer è corretto.È necessario avere un po 'di handle per uno SPSite prima di poter creare un SPWeb, e questa è la stessa istanza di SPSite che si avrà quando si chiama SPWeb.Site.

Pensiamo attraverso le implicazioni di ciò - se non controlli la creazione di SPSite, ma una delle sue reti secondarie ti viene consegnata da un codice esterno, e disponi il sito, quando il controllo viene restituito alla chiamata codice, hai eliminato un sito che potrebbe non essere fatto con! Mettetevi nei panni del codice di chiamata: passate un SPWeb in un metodo e, quando questo metodo viene eseguito, il SPSite che stavate usando è stato chiuso. È sempre responsabilità dell'installatore ripulire le risorse che allocano. Non smaltire il SPSite in questo caso.

+0

Secondo la stessa teoria SPLimitedWebPartManager dovrebbe ripulire anche se non lo fa! http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_160 C'è un motivo per questo o un'altra incoerenza nell'API? –

+0

@Alex Non vedo come sia lo stesso. Nell'esempio a cui ci si è collegati, SPSite e SPWeb devono entrambi essere esplicitamente ripuliti, * così come * l'* altro * web che viene istanziato da SPLimitedWebPartManager. –

+0

Molto ben messo Rex. Si dovrebbe sempre pensare a un SPWeb come "appartenente" a un SPSite, mai viceversa. Soprattutto perché lo smaltimento prematuro di un SPSite chiamerà prima Dispose() su tutti gli SPWeb creati da esso. Pertanto, presumo sempre che un SPSite sia disposto dal codice che lo ha creato. (* L'articolo wiki documenta tutti i casi noti in cui SPSite cleanup è il tuo lavoro.) – dahlbyk

1

Hai provato a controllare l'assemblea con SPDisposeCheck? Forse ti dà un consiglio su come gestire il tuo problema.

+1

SPDisposeCheck verifica solo quegli errori nella pagina "Best Practices", credo. –

2

Questo non è chiaro. C'è Stefan's blog che afferma "È necessario assicurarsi di disporre solo di oggetti SPSite e SPWeb di proprietà del proprio codice". Poi c'è lo this thread di Michael Washam (Microsoft) che afferma che questo modello ha delle perdite.

A meno che non si riesca a trovare un altro riferimento o qualcun altro lo sappia, perché non lo si verifica nel server di sviluppo e si aggiungono i risultati come risposta a questa domanda? Inseriscilo in un ciclo che viene eseguito 100 volte e utilizza la chiave di registro SPRequestStackTrace descritta in Troubleshooting SPSite/SPWeb leaks in WSS v3 and MOSS 2007 per verificare che il codice di prova sia la fonte del problema.

+0

Buon suggerimento, ti darò un vortice e pubblicherò i risultati. –

+1

Il thread MSDN a cui viene fatto riferimento utilizza l'antipattern di restituire un riferimento SPWeb da un metodo helper, commettendo il peccato aggiuntivo (e più dannoso) della creazione di un SPSite nel processo. Invece, quel codice dovrebbe essere refactored in metodi che consumano un argomento SPSite/SPWeb: http://solutionizing.net/2009/01/06/elegant-spsite-elevation/ – dahlbyk

5

Basta pensare fuori della parte superiore della mia testa (pericoloso a volte) ...

Sembra che non si può davvero avere uno SPWeb senza avere uno SPSite. Quindi, se hai ottenuto SPWeb senza passare attraverso SPSite per ottenerlo (o facendo un nuovo SPSite o uno che ti viene fornito), probabilmente non dovrai preoccuparti di smaltire l'SPSite.

Questa è solo una congettura, però. Buona domanda!

+0

Il motivo è che questo è un metodo di estensione per SPWeb, il il chiamante potrebbe aver creato l'oggetto SPSite. Tuttavia non ho un riferimento all'oggetto SPSite, quindi la necessità di utilizzare SPWeb.Site. Che portano alla domanda, ho bisogno di ripulire dopo di me :) Potrei chiedere al chiamante di includere SPSite (aggiungerlo all'elenco dei parametri) ma non volevo aumentare i parametri sul metodo. –

+0

@Edward questa è la risposta più corretta. Guarda il mio –

2

Riflettore ci dice che questo è il codice che viene eseguito all'interno dell'oggetto SPWeb quando si chiama la proprietà del sito:

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

Non è la creazione di un nuovo oggetto SPSite, solo restituendo quello che già aveva, che avrebbe essere a disposizione di SPWeb.Dispose(), se necessario. Quindi, puoi tranquillamente usarlo, e vorrei evitare di eliminarlo, per evitare che le dipendenze di SPWeb diventassero insopportabili.

+2

Suppongo che in realtà dipenda da come viene assegnato m_Site. L'analisi del riflettore per mostrare "assegnato da" su m_Site mostra che è assegnato nel membro privato SPWebConstructor() che viene passato nel sito tramite l'elenco SPWeb dei costruttori interni .... Quindi, alla fine, SPWeb non ha mai notizia di un SPSite . –

1

Io uso spesso questo modello nel mio codice SharePoint come regola empirica se chiamare il depose non blocca nulla che io chiamo. L'altra regola che seguo è che cerco di non creare estensioni che non causino un guadagno netto negli oggetti SPRequest (l'oggetto SPRequest è l'oggetto .net che comunica con tutti gli oggetti pesanti)

ora in rottura il vostro esempio

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

la chiave qui è la SPContext.Current.Site il SPContext pulirà dopo è di per sé in modo corretto (uno dei pochi oggetti che lo fa) dal momento che sappiamo che il sito è pulito correttamente mi aspetto che il ragnatele ottenuto pulito fino a, tuttavia questo è lontano dalla risposta corretta alla domanda. (Nota si deve perdere il ragnatele che hai via OpenWeb)

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

è necessario per ottenere il SPSite di fare cosa con le parti web.

  1. la proprietà web.Site, infatti, ripulisce se stessa dopo che il Web è stato eliminato.
  2. Perché non passare l'oggetto SPSite e lasciare che l'utente della funzione si preoccupi di esso? Nella maggior parte dei casi, penso che chiamerebbero SPContext.Current.Site comunque.
  3. maggior parte del tempo mi devo preoccupare di autorizzazioni, non tutti i nostri DLL finire nel GAC in modo che quando scrivo un nuovo metodo di estensione finisco per dover wrapper un SPSecurity.CodeToRunElevated

con quelli la mente finirei per scrivere questo come. . . ora disporre controllo si spegne in questo caso perché l'l'SPSite viene passato come argomento perché non può rintracciare nel perimetro è disposta in.

public static void GetWebPartFromCatalog(this SPSite site, string webPartName) { 
    SPSecurity.CodeToRunElevated(() => { 
     using(SPSite suSite = new SPSite(site.Id)){ 
      //do what you need to do 
     } 
    }; 
} 
+0

Penso che intendiate SPSecurity.RunWithElevatedPrivileges - CodeToRunElevated è il tipo delegato. Detto questo, elevare di default in un metodo di aiuto mi sembra una cattiva idea. E se hai bisogno di elevare, probabilmente stai meglio usando la rappresentazione: http://solutionizing.net/2009/01/06/elegant-spsite-elevation/ – dahlbyk

0

è necessario eliminare l'istanza SPSite/SPWeb se si tratta di un nuovo oggetto

esempio

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

qui usando si prenderà cura di eliminare l'oggetto se avete ottenuto il riferimento dell'oggetto da SPContext.Current non è necessario disporre esplicitamente l'oggetto poiché il riferimento deve essere disponibile da SPContext.Current.

Problemi correlati