asp.net-mvc - mvc5 - viewmodel asp net mvc 4
ASP.Net MVC y estado: cómo mantener el estado entre las solicitudes (2)
Ha pasado un tiempo desde que publiqué la pregunta, que fue bastante matizada por mi poca experiencia y conocimiento de MVC. Aún así, recibí algunas aportaciones bastante útiles, que finalmente me llevaron a encontrar una solución y también a obtener una idea de MVC.
Lo que me sorprendió, en primer lugar, fue que podrías tener un controlador con un objeto fuertemente tipado como parámetro, como este:
public ActionResult DoSomething(MyClass myObject)...
Este objeto se originó desde el mismo controlador:
...
return View(myObject);
...
Esto me llevó a creer que el objeto vivió a lo largo de estos dos pasos, y que de alguna manera podría esperar que pudiera enviarlo a la vista, hacer algo y luego "mágicamente" regresarlo nuevamente al controlador.
Después de leer sobre el enlace del modelo, entendí que este no es el caso. La vista está completamente muerta y estática, y a menos que almacene la información en alguna parte, desaparecerá.
Volviendo al problema, que consistía en seleccionar y cargar archivos desde el cliente, y crear una lista de estos archivos para mostrar, me di cuenta de que, en general, hay tres maneras de almacenar información entre las solicitudes en MVC:
- Puede almacenar información en campos de formulario en la vista y publicarla en el controlador más tarde
- Puede persistir en algún tipo de almacenamiento, por ejemplo, un archivo o una base de datos
- Puede almacenarlo en la memoria del servidor mediante el acceso a los objetos que se encuentran en todas las solicitudes, por ejemplo, variables de sesión
En mi caso, básicamente tenía dos tipos de información para persistir: 1. Los metadatos del archivo (nombre del archivo, tamaño del archivo, etc.) 2. El contenido del archivo
El enfoque "por libro" probablemente sea almacenar los metadatos en campos de formulario y el contenido del archivo en un archivo o en db. Pero también hay otra manera. Como sé que mis archivos son bastante pequeños y solo habrá unos pocos, y esta solución nunca se implementará en una granja de servidores o similar, quería explorar la opción n. ° 3 de variables de sesión. Los archivos tampoco son interesantes para persistir más allá de la sesión; se procesan y descartan, por lo que no quería almacenarlos en mi db.
Después de leer este excelente artículo: Acceder a los datos de la sesión ASP.NET usando Dynamics
Yo estaba convencido. Simplemente creé una clase sessionbag como se describe en el artículo, y luego pude hacer lo siguiente en mi controlador:
[HttpPost]
public ActionResult AddImportFile(HttpPostedFileBase file)
{
ImportDataViewModel importData = SessionBag.Current.ImportData;
if (importData == null) importData = new ImportDataViewModel();
if (file == null)
return RedirectToAction("DataImport");
if (file.ContentLength > 0)
{
ImportDataFile idFile = new ImportDataFile { File = file };
importData.Files.Add(idFile);
}
SessionBag.Current.ImportData = importData;
return RedirectToAction("DataImport");
}
Soy plenamente consciente de que, en la mayoría de los casos, esta sería una mala solución. Pero para los pocos KB de memoria del servidor que ocupan los archivos y con la simplicidad de todo esto, creo que funcionó muy bien para mí.
La ventaja adicional de usar SessionBag es que si el usuario ingresó un elemento de menú diferente y luego regresó, la lista de archivos aún estaría allí. Este no sería el caso, por ejemplo, al elegir la opción de campos de formulario / almacenamiento de archivos.
Como observación final, me doy cuenta de que SessionBag es muy fácil de abusar, dada la simplicidad de uso. Pero si lo usa para lo que significa, es decir, datos de sesión, creo que puede ser una herramienta poderosa.
Como un experimentado desarrollador de ASP.Net que recién comencé a utilizar MVC, me cuesta un poco cambiar mi forma de pensar de la forma tradicional de "controlar el servidor y gestionar eventos" a la manera más dinámica de MVC. Creo que estoy llegando poco a poco, pero a veces la "magia" de MVC me saca de quicio.
Mi escenario actual es crear una página web que permita al usuario navegar por un archivo local, subirlo al servidor y repetirlo hasta que tenga una lista de archivos con los que trabajar. Cuando esté contento con la lista de archivos (que se mostrará en una cuadrícula en la página), hará clic en un botón para procesar los archivos y extraer algunos datos que se almacenarán en una base de datos.
La última parte no es tan importante, en este momento estoy luchando con algo tan trivial como crear una lista de archivos y persistir en esa lista entre las solicitudes. En el enfoque tradicional, esto sería extremadamente simple: los datos se conservarían en ViewState. Pero en MVC necesito pasar los datos entre el controlador y las vistas, y no entiendo completamente cómo se supone que funciona.
Creo que será mejor que publique mi intento bastante incompleto de codificar esto para explicar el problema.
Para mantener mis datos de lista de archivos, he creado un modelo de vista que básicamente es una lista de archivos tipeados, junto con algunos metadatos adicionales:
public class ImportDataViewModel
{
public ImportDataViewModel()
{
Files = new List<ImportDataFile>();
}
public List<ImportDataFile> Files { get; set; }
...
En la vista, tengo un formulario para buscar y cargar el archivo:
<form action="AddImportFile" method="post" enctype="multipart/form-data">
<label for="file">
Filename:</label>
<input type="file" name="file" id="file" />
<input type="submit" />
</form>
La vista usa el modelo de vista como su modelo:
@model MHP.ViewModels.ImportDataViewModel
Esto enviará el archivo a mi acción:
public ActionResult AddImportFile(HttpPostedFileBase file, ImportDataViewModel importData)
{
if (file.ContentLength > 0)
{
ImportDataFile idFile = new ImportDataFile { File = file };
importData.Files.Add(idFile);
}
return View("DataImport", importData);
}
Esta acción devuelve la vista de la página DataImport junto con la instancia viewmodel que contiene la lista de archivos.
Esto funciona bien hasta cierto punto, puedo buscar un archivo y subirlo, y puedo ver los datos del modelo de vista dentro de la acción, y luego también si pongo un punto de interrupción dentro de la vista y depuro "this.Model", todo es multa.
Pero luego, si intento cargar otro archivo, al poner un punto de interrupción dentro de la acción AddImportFile, el parámetro importData está vacío. Entonces la vista obviamente no está pasando la instancia actual de su modelo a la acción.
En las muestras de MVC que he pasado, la instancia del modelo se transfiere "mágicamente" al método de acción como parámetro, entonces, ¿por qué está vacía ahora?
Supongo que el verdadero problema es mi comprensión limitada de MVC, y que probablemente haya una solución muy simple para esto. De todos modos, estaría extremadamente agradecido si alguien pudiera señalarme en la dirección correcta.
Respecto a la carga
1) Tal vez considere un cargador de AJAX con HTML para permitir que su usuario seleccione varios archivos antes de enviarlos al servidor. Este cargador de archivos BlueImp Jquery AJAX es bastante sorprendente con una aplicación muy buena: Blueimp Jquery File Upload . Permitirá a los usuarios arrastrar y soltar o seleccionar múltiples archivos y editar el orden de los archivos, incluir / excluir, etc. Luego, cuando estén contentos, pueden presionar cargar para enviar a su controlador o cargar el controlador para procesarlo en el servidor.
2) Podrías hacer que cada carga persista en la base de datos, aunque estarías recargando toda la página y escribiendo un modelo de vista adicional y un código de afeitar para lograr el efecto de listado. Esto probablemente no va a ser receptivo ...
Respecto al mantenimiento de WebForms / MVC
Mantener el estado entre las solicitudes es algo de magia negra y vudú. Al ingresar a ASP.NET MVC, entiéndalo entendiendo que las aplicaciones web se comunican mediante solicitudes y respuestas. ¡Así que ve a abrazar la red como sin estado y desarrolla desde allí! Cuando su modelo se publica a través de su controlador, se combina con cualquier variable en el controlador. Sin embargo, antes de que desaparezca, puede almacenar sus contenidos en una base de datos para recuperarlos más tarde.
Las aplicaciones web no pueden mantener un estado verdadero como las aplicaciones de escritorio. Hay muchas maneras en que los marcos ajax y algunas herramientas de vudú emplean personas para simular el estado en el entorno HTTP. Y una simulación de estado es realmente solo una falsa mímica de estado. ASP.NET Web Forms intenta simular el estado de la mejor manera posible ocultando la naturaleza sin estado de HTTP del desarrollador. Puede experimentar muchos dolores de cabeza cuando intente utilizar su propio código AJAX junto con el código de marcado de Formularios Web y su propio marco Ajax.
Estoy muy contento de que estés aprendiendo MVC
Dejando a un lado todas las bromas, si obtienes la mentalidad de MVC / HTTP / Apatridia, será muy fácil aplicar los patrones a otros marcos súper populares como Ruby on Rails, SpringMVC (java), Django (python), CakePHP, etc ... Esta fácil transferencia de conocimiento lo ayudará a convertirse en un desarrollador mucho mejor y obtener REALMENTE bien en Ajax.
Estoy muy contento de que estés aprendiendo MVC 3, he realizado algunas prácticas en empresas muy grandes que tenían estos grandes y locos proyectos ASP.NET Web Forms con código volando por todas partes solo para cambiar unos pocos valores numéricos en la base de datos. (-_- '') Me sentí como si estuviera usando unas tijeras para tejer el calcetín de un bebé. Un movimiento incorrecto fácil, y todo se rompió. Parecía que se desarrollaba en PHP, sales sudando y no estás muy seguro de qué pasó y en qué línea. Era casi imposible depurar y actualizar.