2010-09-24 10 views
6

Qual è il modo corretto di disporre gli oggetti creati all'interno di una funzione? Mi sono imbattuto in questo metodo su un sito web.Come posso disporre oggetti SharePoint in modo sicuro nelle funzioni di PowerShell?

function get-spweb ([String]$webUrl=$(throw 'Parameter -webUrl is missing!')) 
{ 
    $site = get-SPSite $weburl 
    return $site.OpenWeb() 
    $site.Dispose() 
} 

Il metodo Dispose viene mai chiamato in questa funzione?

+0

Se vieni da mondo .NET - non c'è niente come "usare". Ma immagino di aver visto alcune richieste di funzionalità su ms connect. – stej

risposta

9

Per prima cosa, in realtà non si desidera che Dispose venga chiamato qui: quando si chiama Dispose su un'istanza di SPSite, tutti i Web restituiti tramite OpenWeb vengono eliminati perché sono "di proprietà" di tale SPSite!

Uno dei modelli utilizzati dai cmdlet di SharePoint 2010 è una sorta di "rimozione posticipata" che significa che le istanze SPWeb non vengono eliminate finché non viene completata la pipeline in cui sono coinvolte. Questo funziona così:

function Get-SPWeb { 
    param([uri]$Url) 

    begin { 
     # get SPSite that owns the passed Url 
     $site = new-object microsoft.sharepoint.spsite $url 
     # return specific SPWeb instance 
     $site.OpenWeb() 
    } 
    end { 
     # this disposes owning spsite AND the returned web 
     $site.Dispose() 
    } 
} 

Ora ecco come funziona in pratica (questa è una singola riga):

ps> get-spweb "http://localhost/sites/test" | foreach-object { 
    $_.Title = "New Name"; $_.update() 
} 

La prima porzione otterrà una singola SPWeb istanza e passarlo al ForEach-Object porzione. Solo quando foreach completa (e termina la modifica del titolo del web), il blocco finale corrispondente verrà chiamato in get-spweb, che dispone del sito e del web. Ciò che è importante è che l'intera pipeline è un singolo blocco di codice che viene eseguito in una singola chiamata.

Questo non sarà lavorare in modo interattivo come questo:

ps> $w = get-spweb "http://localhost/sites/test" # calls begin AND end 
ps> $w.title = "new name" 
ps> $w.update() # boom! web is already disposed 

Quindi, in questo ultimo esempio che avrebbe dovuto usare una diversa implementazione di get-SPWeb (uno che omette la testata, o evita con un parametro switch) e quindi dovresti smaltire il sito da solo.

Un altro dettaglio importante è che il lavoro interattivo in PowerShell con oggetti sharepoint causerà perdite di memoria. Per impostazione predefinita, powershell viene eseguito in MTA (apartment a più thread) e utilizzerà un pool di thread per eseguire i comandi. Ogni riga inserita utilizzerà un thread diverso. Ogni volta che si accede a un oggetto COM con un thread diverso, si perde una certa quantità di memoria dall'heap non gestito mentre un nuovo heap viene allocato per lo switch di contesto (senza che il vecchio venga liberato). Ciò può essere risolto avviando powershell.exe con l'interruttore -STA. Ciò garantirà che tutti i comandi e le pipeline vengano eseguiti con lo stesso thread, evitando la perdita di memoria. Detto questo, semplicemente chiudendo la console di PowerShell si riacquisterà tutta la memoria, ma gli script di lunga durata potrebbero far morire di fame i server della memoria se non si presta attenzione, eliminando SharePoint (qualsiasi altra cosa non gli piaccia rimanere affamata di working set. Questo è il motivo per cui l'approccio a linea singola funziona così bene nell'esempio precedente: l'oggetto è allocato e disposto nella stessa pipeline, e per estensione, lo stesso thread. Nessuna perdita

+0

Come questo si inserisce in 'Start-SPAssignment -Global' –

+0

@Lavinski Con l'assegnazione start/stop, le istanze non vengono eliminate alla fine di una pipeline. Vengono eliminati quando si chiama stop. – x0n

7

No, non perché non si esce prima dalla funzione prima di chiamare Dispose. Se si dispone di risorse che devono essere smaltiti quindi vorrei usare un blocco try/finally in questo modo:

$site = Get-SPSite $weburl 
try { 
# do stuff to $site until done with it 
} 
finally { 
    $site.Dispose() 
} 

La cosa bella, infine, è che lo smaltire verrà chiamato non importa come si esce dal blocco try (sia con successo, a causa di un errore o a causa di una dichiarazione di ritorno).

Problemi correlati