2010-09-24 17 views
12

tengo una clase estática con una propiedad get estática, y en este inmueble, hago esto:C#: Adición de contexto a Parallel.ForEach() en ASP.NET

// property body 
{ 
    // HttpContext.Current is NOT null 
    ... 

    Parallel.ForEach(files, file => 
    { 
     // HttpContext.Current is null 
     var promo = new Promotion(); 
     ... 
    }); 
    ... 

    // HttpContext.Current is NOT null 
} 

Esta clase estática no lo hace experimentado inicialización de tipo hasta que una vista use esta propiedad.

El problema es que el constructor estático Promotion 's, que se inicializa la primera vez que un new Promotion() se crea dentro del Parallel.ForEach(), utiliza HttpContext.Current. Cuando se crea una instancia de promo dentro del alcance de este Parallel.ForEach(), HttpContext.Current es null y new Promotion() por lo tanto, se produce una excepción.

HttpContext.Current no es nulo dentro de la propiedad de obtención estática porque no se llama hasta que la vista lo usa (y por lo tanto hay un HttpContext.Current).

Si Promotion utiliza HttpContext.Current en sus instancias, en vez de sus miembros estáticos, probablemente podría pasar sólo HttpContext.Current en el new Promotion() constructor:

var context = HttpContext.Current; 
Parallel.ForEach(files, file => 
{ 
    var promo = new Promotion(context); 
}); 

Pero desde static miembros de Promoción necesitan HttpContext.Current, no puedo . Probablemente podría rediseñar la clase Promotion para cambiar los miembros estáticos que lo necesitan para ser miembros de instancia, pero son estáticos por una razón: habría una gran penalización de rendimiento si todos los miembros que estaban estáticos debieran definirse en su lugar en cada instancia cada vez que se creó una instancia de new Promotion.

¿Cuáles son las posibles soluciones para esto? No me di cuenta HttpContext.Current sería nulo dentro del alcance de Parallel.ForEach().

+0

miembros estáticos de Promoción se inicializarán solo una vez, cuando se toque el código de la clase ... ¿Cómo podrían depender de 'HttpContext.Current'? –

+0

¿Está bajo su control el código fuente de 'Promoción'? –

Respuesta

11

HttpContext.Current es nulo porque se ejecuta en "subprocesos no web". Si bifurcaste algún código usando new Thread(...), sería exactamente lo mismo. El TPL algo oculta esto, pero aún necesita darse cuenta de que cada iteración en su Parallel.ForEach potencialmente puede ejecutarse en un hilo diferente, y tratarlo en consecuencia.

En particular, si desea utilizar alguna clase o método fuera de la solicitud web (y Parallel.ForEach es tal uso) simplemente no puede usar HttpContext.Current. Una solución es pasar explícitamente el HttpContext (o HttpContextBase para una mejor comprobabilidad) en el constructor (o como un parámetro de método)

En pocas palabras: debe salir del uso de HttpContext.Current estáticamente.

0

Como señala Mauricio, el HttpContext.Current depende del hilo que se está ejecutando actualmente. Me parece inusual que un constructor estático depende del valor inherentemente transitorio como HttpContext.Current, pero quizás esa no era su idea.

Si puede cambiar la clase Promotion, esa sería la primera opción que consideraría.

De lo contrario, debe forzar la inicialización de tipo para Promotion en un punto donde HttpContext.Current sigue siendo válido. Para saber qué fuerzas escribe inicialización, lea this Jon Skeet blog post.

Una opción podría ser crear un objeto ficticio Promotion, (solo una vez en todo el programa debería ser suficiente). Si esa no es una opción, puede intentar leyendo la propiedad con reflexión. No sé si esas fuerzas escriben inicialización, pero supongo que sí.

4

Simplemente pase cualquier contexto que tenga desde fuera de Parallel.ForEach invoca cualquier función que llame dentro que dependa de dicho contexto.

var context = HttpContext.Current; 
Parallel.ForEach(items, item => 
    { 
     DoSomething(item, context); 
    } 
); 



private static void DoSomething(item, context = null) { 
    if (context == null) context = HttpContext.Current; 

    ... 
} 

me gustaría tener de reserva en nulo por lo que no tiene que preocuparse acerca de pasar todo el contexto de todo el tiempo. Solo me aseguro de recordar que mis funciones necesitan contexto cuando llamo desde otro hilo, y luego le doy una bofetada a ese bebé allí mismo.

0

No funciona, porque dentro del foreach, se crea un nuevo subproceso, por lo que el contexto es nulo. Incluso al crear un método DoSomething para establecer el contexto actual, el contexto sigue siendo nulo.

Cuestiones relacionadas