2009-08-06 11 views
18

Actualizado el 06/08/2009 15:52: Respuesta corta NO. Pregunta original:SPWeb.Site, ¿debería llamar a Dispose() en él?

No puedo encontrar ninguna referencia que proporcione orientación sobre SPWeb.Site con respecto a la eliminación. He pasado por algunos de los más populares documentación de las mejores prácticas sobre la disposición de objetos de SharePoint:

Desafortunadamente ninguna de estas directrices mencionar SPWeb.Site. Para dar un poco de contexto, estoy escribiendo una API de extensión público que acepta un SPWeb como un argumento a un método, es decir:

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

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

    **OR** ?? 

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

He mirado como el método Close() en refelector para SPWeb, que se llama por SPWeb.Dispose() y no hay nada en él que indique que el campo real del miembro de SPSite está dispuesto.

Actualización: 06/08/2009 13:47

En Alex's sugerencia

"Póngalo en un bucle que se ejecuta 100 veces y usar la clave de registro SPRequestStackTrace se describe en Solución de problemas SPSite/SPWeb gotea en WSS v3 y MOSS 2007 para verificar que el código de prueba sea la fuente del problema ".

Me corrió el siguiente fragmento de código incluido dentro de un elemento Web:

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

Nada apareció en los registros de SharePoint.

Si bien dudaría en sacar conclusiones reales de este ingenuo experimento, sugeriría que es no necesario para deshacerse de SPWeb.Site. Sería realmente agradable obtener una respuesta concreta de alguien más informado sobre este tema.

Actualización: 06/08/2009 14:52 Impulsado por el comentario de Greg trabajé a cabo las tareas de m_Site y parece que es en última instancia, siempre se pasa a través de los constructores SPWeb internos. P.ej. SPWeb.OpenWeb pasa en este a SPWeb nuevo(). Así que estoy más seguro de que SPWeb.Site debería no eliminarse, de hecho podría causar problemas si fuera así.

+0

Al considerar esto, no está claro. Hice la misma pregunta que un comentario a la publicación de Roger Lamb, pero no tuve respuesta. –

+0

En mi opinión, y es solo eso, una opinión, no, nunca debería tener que deshacerse de ese objeto. ¿Por qué? Bueno, se devuelve a través de una propiedad de otro objeto. Si ese otro objeto es desechable, debe eliminar * ese * y dejar que se encargue de sus propios recursos. Nada de lo que lees de una propiedad debe ser eliminado por tu propio código, que, para mí, constituiría un error en ese marco. –

+1

@ lasse-v-karlsen Estoy de acuerdo con usted al 100%, sin embargo, hay muchas peculiaridades en la API de SharePoint y realmente necesita comprenderlas o arriesgarse a perder memoria. Así que, si bien puede ser un error en la API, me gustaría saber si está allí o no :) –

Respuesta

8

Kirk's answer es correcta.Debe tener algún control para un SPSite antes de poder crear un SPWeb, y esa es la misma instancia de SPSite que tendrá cuando llame a SPWeb.Site.

Analicemos las implicaciones de eso: si no controla la creación de SPSite, pero una de sus redes secundarias se entrega desde un código externo, y usted dispone del sitio, cuando se devuelve el control a la llamada código, ¡usted ha eliminado un Sitio que quizás no haya terminado! Ponte en el lugar del código de llamada: pasas un SPWeb a un método, y cuando se hace ese método, el SPSite que estabas usando ha sido cerrado. Siempre es responsabilidad del instalador limpiar los recursos que asignan. No deseche SPSite en este caso.

+0

Por la misma teoría SPLimitedWebPartManager debería limpiar también pero no! http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_160 ¿Hay alguna razón para esto o otra incoherencia en la API? –

+0

@Alex No veo cómo es lo mismo. En el ejemplo al que se vinculó, tanto SPSite como SPWeb aún deben limpiarse explícitamente *, así como * el * otro * web que es instanciado por el SPLimitedWebPartManager. –

+0

Muy bien poner Rex. Siempre debe pensar en un SPWeb como "perteneciente" a un SPSite, nunca al revés. Especialmente porque deshacerse prematuramente de un SPSite primero llamará a Dispose() en todos los SPWebs creados a partir de él. Como tal, siempre * asumo que un SPSite será eliminado por el código que lo creó. (* El artículo wiki documenta todos los casos conocidos en los que la limpieza de SPSite es su trabajo). – dahlbyk

1

¿Ha intentado comprobar su montaje con SPDisposeCheck? Tal vez le da un consejo sobre cómo manejar su problema.

+1

SPDisposeCheck solo verifica esos errores en la página 'Mejores prácticas', creo. –

2

Esto no está claro. Hay Stefan's blog que indica ". Debe asegurarse de que solo descarta los objetos SPSite y SPWeb que posee su código". Luego está el this thread de Michael Washam (Microsoft) que establece que este patrón tiene fugas.

A menos que pueda encontrar otra referencia o que alguien más sepa, ¿por qué no la prueba en su servidor de desarrollo y agrega los resultados como respuesta a esta pregunta? Colóquelo en un bucle que se ejecuta 100 veces y use la clave de registro SPRequestStackTrace descrita en Troubleshooting SPSite/SPWeb leaks in WSS v3 and MOSS 2007 para verificar que el código de prueba sea el origen del problema.

+0

Buena sugerencia, voy a dar un giro y publicar los resultados. –

+1

El subproceso MSDN al que se hace referencia utiliza el antipatrón de devolver una referencia SPWeb de un método auxiliar, cometiendo el pecado adicional (y más dañino) de actualizar un SPSite en el proceso. En su lugar, ese código se debe refactorizar en métodos que consuman un argumento SPSite/SPWeb: http://solutionizing.net/2009/01/06/elegant-spsite-elevation/ – dahlbyk

5

Sólo de pensar en la parte superior de la cabeza (a veces peligroso) ...

Parece que realmente no se puede tener un SPWeb sin tener un SPSite. Por lo tanto, si tiene SPWeb sin pasar por SPSite para obtenerlo (ya sea al hacer un nuevo SPSite o recibir uno), entonces probablemente no tenga que preocuparse por eliminar el SPSite.

Esto es sólo una conjetura, sin embargo. ¡Buena pregunta!

+0

Esto es porque este es un método de extensión para SPWeb, el quien llama pudo haber creado el objeto SPSite. Sin embargo, no tengo una referencia al objeto SPSite, de ahí la necesidad de usar SPWeb.Site. Lo que me lleva a la pregunta, ¿tengo que limpiarlo? :) Podría pedirle a la persona que llama que incluya SPSite (agréguelo a la lista de parámetros) pero no quería aumentar los parámetros en el método. –

+0

@Edward esta es la respuesta más correcta. Mira el mio. –

2

Reflector nos dice que este es el código que se ejecuta dentro del objeto SPWeb cuando se llama a la propiedad del sitio:

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

No es la creación de un nuevo objeto SPSite, que acaban de volver del que ya tenía, lo que haría estar a la SPWeb.Dispose() para cuidar, si es necesario. Por lo tanto, puede usarlo con seguridad, y evitaría deshacerse de él, no sea que las dependencias de SPWeb se vuelvan inseguras.

+2

Supongo que realmente depende de cómo se asigna m_Site. Usando el análisis de reflector para mostrar "asignado por" en m_Site muestra que está asignado en el miembro privado SPWebConstructor() que se pasa en el sitio a través de la lista SPWebs de constructores internos ... Así que al final SPWeb nunca novedades en un SPSite . –

1

A menudo utilizo este patrón en mi código de SharePoint como regla general si llamar a depose no bloquea nada de lo que yo llamo. La otra regla que sigo es intentar no crear extensiones que no causen una ganancia neta en objetos SPRequest (el objeto SPRequest es el objeto .net que habla con todos los objcets de peso pesado)

ahora rompiendo abajo tu ejemplo

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

la clave aquí es la SPContext.Current.Site el SPContext va a limpiar después de que sea auto correctamente (uno de los pocos objetos que lo hace) ya que sabemos que el sitio se limpia correctamente espero que las bandas se llevó limpiado, sin embargo, esto está lejos de ser la respuesta correcta a tu pregunta. (Tenga en cuenta que debe tener fugas de las bandas que tienes a través de OpenWeb)

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

que necesita para obtener la SPSite que hacer algo con las piezas de la tela.

  1. la propiedad web.Site de hecho limpia después de sí mismo si la web está dispuesta.
  2. ¿Por qué no pasar el objeto SPSite y dejar que el usuario de la función se preocupe por ello? En la mayoría de los casos, creo que llamarían usando SPContext.Current.Site de todos modos.
  3. mayoría de las veces tengo que preocuparse acerca de los permisos, no todo el mundo de nuestros dlls terminan en la GAC ​​así que cuando escribo un nuevo método de extensión termino tener que envoltorio que un SPSecurity.CodeToRunElevated

con los de importa que terminaría escribiendo esto como. . . Ahora Desechar el cheque se apagará en este caso porque la SPSite el que se pasa como argumento porque no puede rastrear en qué ámbito se dispone en.

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

Creo que te refieres a SPSecurity.RunWithElevatedPrivileges - CodeToRunElevated es el tipo de delegado. Dicho esto, elevar por defecto en un método de ayuda me parece una mala idea. Y si necesita elevarse, probablemente sea mejor que use la suplantación: http://solutionizing.net/2009/01/06/elegant-spsite-elevation/ – dahlbyk

0

es necesario eliminar la instancia SPSite/SPWeb si se trata de un objeto nuevo

por ejemplo

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

aquí usando se encargará de eliminar el objeto sin embargo, si usted tiene la referencia del objeto de SPContext.Current no debe explicitar el objeto ya que la referencia debería estar disponible desde SPContext.Current.

Cuestiones relacionadas