2009-08-11 12 views
6

Todavía no estoy familiarizado con Inversion of Control (aunque estoy aprendiendo sobre esto ahora) así que si esa es la solución a mi pregunta, házmelo saber y obtendré volver a aprender sobre eso.ASP.NET MVC - Compartir estado de sesión entre controladores

Tengo un par de controladores que necesitan una variable de sesión, naturalmente, no ha pasado nada especial debido a cómo funciona la sesión en primer lugar, pero esto me hizo pensar cuál es la forma más limpia de compartir objetos relacionados entre dos controladores separados es. En mi caso específico, tengo un Controlador de carga y un Controlador de producto que funcionan en conjunto para cargar archivos de imagen. A medida que UploadController sube los archivos, los datos sobre la carga se almacenan en la sesión. Después de que esto suceda, necesito acceder a los datos de la sesión en el ProductController. Si creo una propiedad get/set para la variable Session que contiene mi información de carga en ambos controladores, podré acceder a esa información, pero al mismo tiempo estaré violando todo tipo de DRY, sin mencionar la creación de un, en el mejor de los casos, un diseño confuso donde un objeto es compartido y modificado por dos objetos completamente desconectados.

¿Qué es lo que sugiere?

Contexto exacta:

un archivo subido Ver mensajes un archivo a UploadController.ImageWithpreview(), que luego lee en el archivo publicado y lo copia en un directorio temporal. Después de guardar el archivo, otra clase produce una miniatura de la imagen cargada. La ruta al archivo original y a la miniatura generada se devuelve con un JsonResult a una devolución de llamada javascript que actualiza parte del contenido dinámico en un formulario en la página que puede ser "Guardado" o "Cancelado". Ya sea que la imagen cargada se guarde o se omita, necesito moverla o eliminarla y la miniatura generada del directorio temporal. Para facilitar esto, UploadController realiza un seguimiento de todos los archivos de carga y sus miniaturas en un objeto Queue mantenido por la sesión.

Volver a la vista: después de completar el formulario con una miniatura generada de la imagen que se cargó, el formulario se publica en ProductsController donde se identifica el archivo seleccionado (actualmente guardo el nombre de archivo en un campo Oculto, Me doy cuenta es una vulnerabilidad horrible), y luego copiado fuera del directorio temporal a una ubicación permanente. Idealmente, me gustaría simplemente acceder a la cola que he almacenado en la sesión para que el formulario no tenga que contener la ubicación de la imagen como lo hace ahora. Así es como visualicé mi solución, pero escucharé con entusiasmo cualquier comentario o crítica.

Respuesta

3

Me vienen a la mente un par de soluciones. Se podría utilizar una clase "SessionState" que mapea en la solicitud y/Obtiene la información como tal (que estoy haciendo esto de la memoria así que esto es poco probable para compilar y está destinado a transmitir el punto):

internal class SessionState 
{ 
    string ImageName 
    { 
    get { return HttpContext.Current.Session["ImageName"]; } 
    set { HttpContext.Current.Session["ImageName"] = value; } 
    } 
} 

Y luego desde el controlador, hacer algo como:

var sessionState = new SessionState(); 
    sessionState.ImageName = "xyz"; 
    /* Or */ 
    var imageName = sessionState.ImageName; 

como alternativa, puede crear un método de extensión del controlador:

public static class SessionControllerExtensions 
{ 
    public static string GetImageName(this IController controller) 
    { 
    return HttpContext.Current.Session["ImageName"]; 
    } 

    public static string SetImageName(this IController controller, string imageName) 
    { 
    HttpContext.Current.Session["ImageName"] = imageName; 
    } 
} 

a continuación, desde el controlador:

Esto es ciertamente SECO. Dicho esto, no me gusta particularmente ninguna de estas soluciones, ya que prefiero almacenar la menor cantidad de datos, si es que hay alguno, en sesión. Pero si su intención es retener toda esta información sin tener que cargar/discernir desde otra fuente, esta es la manera más rápida (más sucia) que se me ocurre para hacerlo.Estoy bastante seguro de que hay una solución mucho más elegante, pero no tengo toda la información sobre qué es lo que estás tratando de hacer y cuál es el dominio del problema.

Tenga en cuenta que al almacenar información en la sesión, tendrá que deshidratar/rehidratar los objetos mediante serialización y es posible que no obtenga el rendimiento que cree que es por hacerlo de esta manera.

Espero que esto ayude.

EDIT: En respuesta a la información adicional No está seguro de dónde se está buscando para implementar esto, pero el procesamiento de imágenes en "tiempo real" es una forma segura de ser golpeado con un ataque de denegación de servicio. Mi sugerencia es la siguiente: suponiendo que esto sea público y cualquiera pueda subir una imagen:

1) Permitir que el usuario cargue una imagen. Esta imagen entra en la cola de procesamiento para procesamiento en segundo plano por la aplicación o algún servicio. Además, el nombre de la imagen entra en la cola de procesamiento personal del usuario, probablemente una tabla en la base de datos. Se puede encontrar información sobre el procesamiento en segundo plano en una aplicación web @Schedule a job in hosted web server

2) Procese estas imágenes y, durante el procesamiento, muestre un "gráfico de procesamiento". Puede tener una solicitud de ajax en la página del producto que verifica las imágenes que se están procesando y trata de volver a cargarlas cada X segundos.

3) Mientras se está "procesando" una imagen, el usuario puede optar por no procesarla suponiendo que fue la que cargó la imagen. Esto está disponible en la (s) página (s) de producto que muestran la imagen o en una vista separada de "cola de usuario" que les permitirá eliminar la imagen de la consideración.

Así que terminas con algunos objetos más de dominio y esos objetos son administrados por la cola. Soy un firme defensor de la configuración de la convención por lo que el destino final de las imágenes del producto debe estar predefinido. Algo como:

images/products/{id} .jpg o, si es una colección, images/products/{id}/{sequence} .jpg.

No necesita saber el destino en el formulario. Es lo mismo para todas las imágenes.

La cola necesita saber dónde se cargó la imagen temporal y cuál era la identificación del producto. El trabajador de cola saca elementos de la cola, los procesa y los almacena en consecuencia.

Sé que esto suena un poco más "estructurado" de lo que originalmente pretendías, pero creo que es un poco más limpio.

+0

Gracias esta entrada. He agregado más información a mi pregunta original si eso es de más utilidad. –

+0

El procesamiento de la imagen es en tiempo real, pero existe dentro de un área de administración en el sitio web, por lo que el uso general es bastante mínimo. Como máximo, solo es probable que se procesen unas pocas imágenes por hora en toda la aplicación. Otro enfoque que también consideré fue simplemente hacer que el evento Session_End de la aplicación elimine todo el directorio temporal para la sesión actual, pero no estoy seguro de lo ideal que es. –

+0

Si su usuario ha subido una gran cantidad de imágenes que están procesando, no creo que pueda garantizar que se haga cuando su sesión caduque. Lo eliminaría una vez que se haya completado el "procesamiento". La (s) cadena (s) de trabajo (s) debe (n) mantenerse activa (s) siempre que la cola tenga elementos para procesar, por lo que es seguro asumir eso. Siempre que su grupo de aplicaciones no esté "dormido", su sistema debería continuar procesando bien. Estoy bastante seguro de que está cubierto en el artículo que he vinculado. – andymeadows

1

¿Hay una equivalencia completa entre UploadController y ProductController?

Como los archivos son cargados por UploadController, los datos sobre la carga se almacenan en la sesión. Después de que esto suceda, necesito acceder a los datos de la sesión en el ProductController.

Como he leído que UploadControl necesita acceso de lectura y escritura para Cargar datos, el ProductController solo necesita lectura.

Si eso es cierto, puede dejarlo en claro mediante el uso de un contenedor immuatable alrededor de la información de carga y haga que UploadController lo incluya en la sesión.

La sesión en sí es, por definición, un tablón de anuncios público compartido, desacopla las relaciones explícitas a costa de permitir que cualquiera pueda obtenerlas y ponerlas. Puede permitir que ProductController conozca UploadController y, por lo tanto, eliminar la necesidad de pasar la información de carga a través de la sesión. Mi instinto es que la información de carga es interesante para el público, por lo que usar Session es razonable.

No veo ninguna violación DRY aquí, estamos tratando explícitamente de separar las responsabilidades.

+0

No estoy seguro si esto califica más como un problema DRY o solo uno de comunicación de componentes mal definida. La sesión está obviamente diseñada para cerrar la brecha exacta que estoy tratando de llenar, simplemente no me siento particularmente limpio en este escenario. –

Cuestiones relacionadas