asp.net-mvc - RIP Tutorial · from: asp-net-mvc It is an unofficial and free asp.net-mvc ebook...
Transcript of asp.net-mvc - RIP Tutorial · from: asp-net-mvc It is an unofficial and free asp.net-mvc ebook...
Tabla de contenido
Acerca de 1
Capítulo 1: Empezando con asp.net-mvc 2
Observaciones 2
Versiones 2
Examples 3
Hola MVC! 3
Capítulo 2: ActionResult 6
Observaciones 6
Examples 6
Regresar una página de visualización 6
Devolver un archivo 6
Devuelve un json 7
Capítulo 3: ActionResult 8
Examples 8
Ver resultado 8
PartialViewResult 8
RedirectResult 9
RedirectToRouteResult 9
ContentResult 10
JsonResult 10
Capítulo 4: ActionResult 12
Sintaxis 12
Examples 12
Métodos de acción 12
Asignación de parámetros de acción-método 13
Llamando a un ActionResult en otro ActionResult 13
Capítulo 5: Anotaciones de datos 14
Introducción 14
Examples 14
Atributos básicos de validación utilizados en ViewModel 14
Modelo 14
Ver 14
Controlador 15
Validación remota 15
Validación remota utilizada para verificar si el contenido que se ingresa en el control de 15
RequiredAttribute 17
StringLengthAttribute 17
Atributo de rango 18
Atributo de expresión regular 18
Comparar atributo 19
Atributo de validación personalizado 20
Aquí está su DotNetFiddle Demo 21
Modelo EDMx - Anotación de datos 21
Anotaciones de datos para la primera implementación de la base de datos (código de modelo 22
Capítulo 6: Áreas 24
Introducción 24
Observaciones 24
Examples 24
Crear una nueva área 24
Configurar RouteConfig.cs 24
Cree un nuevo controlador y configure areanameAreaRegistration.cs maproute 24
Capítulo 7: Asp.net mvc enviar correo 26
Examples 26
Formulario de contacto en Asp MVC 26
Enviando correo electrónico desde la clase 27
Capítulo 8: Ayudantes html 29
Introducción 29
Examples 29
Ayudante HTML personalizado - Nombre para mostrar 29
Ayudante personalizado - botón Enviar de envío 29
Lista exhaustiva de ejemplos de HtmlHelper que incluye salida HTML 30
HtmlHelper.Action() 30
HtmlHelper.ActionLink() 30
@HtmlHelper.BeginForm() 30
Ayudantes HTML estándar con sus salidas HTML 30
Ayudante personalizado - Botón de radio renderizado con etiqueta 31
Ayudante personalizado - Selector de fecha y hora 32
Capítulo 9: Dockerización de la aplicación ASP.NET 33
Examples 33
Dockerfile y Nuget 33
Soporte POSTGRESQL. 33
Dockerización 34
Capítulo 10: Empaquetado y Minificación 36
Examples 36
Minificación 36
Ejemplo usando minificación 36
Guiones y paquetes de estilo 36
Capítulo 11: Enrutamiento 38
Introducción 38
Examples 38
Enrutamiento personalizado 38
Añadiendo ruta personalizada en mvc 39
Atributo de enrutamiento en MVC 39
Conceptos básicos de enrutamiento 40
Ruta de todo 41
Ruta completa para habilitar el enrutamiento del lado del cliente 42
Atributo de enrutamiento en áreas 42
Capítulo 12: Extensiones Ajax MVC 44
Introducción 44
Parámetros 44
Observaciones 45
Examples 45
Ajax Action Link 45
Formas de Ajax 45
Capítulo 13: Filtros de accion 46
Examples 46
Un filtro de acción de registro. 46
Filtro de acción de Control de sesión - solicitud de página y ajax 46
Ubicaciones de uso del filtro de acción (global, controlador, acción) 47
Atributo de manejador de excepciones 49
Capítulo 14: Html.AntiForgeryToken 51
Introducción 51
Sintaxis 51
Observaciones 51
Precaución 51
Examples 51
Uso básico 51
Maquinilla de afeitar (YourView.cshtml) 51
Controlador (YourController.cs) 52
Deshabilitar el control heurístico de identidad 52
Validando todas las publicaciones 52
Uso anticipado: aplique el filtro antiforgery predeterminado para cada POST 54
Uso de AntiForgeryToken con la solicitud de Ajax de Jquery 55
Capítulo 15: Html.RouteLink 56
Parámetros 56
Examples 56
Ejemplo básico usando el texto de enlace y el nombre de la ruta 56
Capítulo 16: Inyección de dependencia 57
Observaciones 57
Examples 58
Configuraciones de Ninject 58
Utilización de las interfaces. 59
Inyección de dependencia del constructor 60
Dependencia codificada 60
parámetro DI 60
Inyección De la Dependencia De Ninject 60
Capítulo 17: jQuery Ajax Call Con Asp MVC 65
Examples 65
Publicar objetos JavaScript con jQuery Ajax Call 65
Capítulo 18: Manejo de errores Http 67
Introducción 67
Examples 67
Configuración básica 67
Capítulo 19: Maquinilla de afeitar 69
Introducción 69
Sintaxis 69
Observaciones 69
Examples 69
Añadir comentarios 69
Mostrar HTML dentro del bloque de código Razor 70
Sintaxis basica 71
Escapando a @ personaje 72
Crear clases y métodos en línea usando funciones @ 72
Agregando un atributo personalizado con - (guión) en el nombre 73
Plantillas de editor 73
Pase el contenido de Razor a un @helper 75
Compartir @helpers a través de vistas 75
Capítulo 20: Modelo de enlace 77
Introducción 77
Observaciones 77
Examples 77
Enlace de valor de ruta 77
Enlace de cadena de consulta 77
Atadura a objetos 78
Ajax vinculante 78
Generic, enlace basado en modelo de sesión 78
Prevenir el enlace en PostModel 80
Subir archivo 81
Validación de campos de fecha manualmente con formatos dinámicos utilizando el cuaderno de 81
Capítulo 21: Modelo de validación 83
Examples 83
Validar modelo en ActionResult 83
Eliminar un objeto de la validación 83
Mensajes de error personalizados 84
Creando mensajes de error personalizados en el modelo y en el controlador 84
Validación de modelos en JQuery. 85
Capítulo 22: MVC vs Formularios Web 87
Introducción 87
Sintaxis 87
Observaciones 87
Examples 87
Ventajas de los formularios web ASP .NET 87
Ventajas de una aplicación web basada en MVC 88
Desventajas 88
Razor View Engine VS ASPX View Engine 88
Capítulo 23: Operación CRUD 90
Introducción 90
Observaciones 90
Examples 90
Crear - Parte del controlador 90
Crear - Ver parte 91
Detalles - parte del controlador 92
Detalles - Ver parte 93
Editar - parte del controlador 94
Eliminar - parte del controlador 95
Capítulo 24: Plantillas de visualización y editor 97
Introducción 97
Examples 97
Plantilla de pantalla 97
Plantilla de editor 98
Capítulo 25: Registro de errores 101
Examples 101
Atributo simple 101
devolviendo página de error personalizada 101
Cree un ErrorLogger personalizado en ASP.Net MVC 102
Capítulo 26: Reglas de reescritura de IIS 105
Examples 105
Forzar HTTPS usando la regla de reescritura 105
Capítulo 27: T4MVC 106
Introducción 106
Examples 106
Llamando a una acción 106
Capítulo 28: Usando múltiples modelos en una vista 109
Introducción 109
Examples 109
Uso de múltiples modelos en una vista con ExpandoObject dinámico 109
Capítulo 29: Validación automática del lado del cliente a partir de atributos 112
Observaciones 112
Examples 112
Modelo 112
configuración de web.config 112
Paquetes Nuget Requeridos 112
Vista de formulario 112
Configuración del paquete 113
Global.asax.cs 114
Capítulo 30: ViewData, ViewBag, TempData 115
Introducción 115
Sintaxis 115
Examples 115
¿Qué son ViewData, ViewBag y TempData? 115
Ciclo de vida de TempData 117
Capítulo 31: Vistas parciales 119
Introducción 119
Sintaxis 119
Examples 119
Vista parcial con modelo. 119
Vista parcial a una cadena - para contenido de correo electrónico, etc. 119
Html.Partial Vs Html.RenderPartial 120
Capítulo 32: Web.config cifrado 122
Examples 122
Cómo proteger su archivo web.config 122
Creditos 123
Acerca de
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version from: asp-net-mvc
It is an unofficial and free asp.net-mvc ebook created for educational purposes. All the content is extracted from Stack Overflow Documentation, which is written by many hardworking individuals at Stack Overflow. It is neither affiliated with Stack Overflow nor official asp.net-mvc.
The content is released under Creative Commons BY-SA, and the list of contributors to each chapter are provided in the credits section at the end of this book. Images may be copyright of their respective owners unless otherwise specified. All trademarks and registered trademarks are the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/es/home 1
Capítulo 1: Empezando con asp.net-mvc
Observaciones
El patrón arquitectónico Modelo-Vista-Controlador (MVC) separa una aplicación en tres componentes principales: el modelo, la vista y el controlador. El marco MVC de ASP.NET proporciona una alternativa al patrón de formularios web de ASP.NET para crear aplicaciones web. El marco de ASP.NET MVC es un marco de presentación ligero y altamente comprobable que (al igual que con las aplicaciones basadas en Web Forms) se integra con las características existentes de ASP.NET, como las páginas maestras y la autenticación basada en membresía. El marco MVC se define en el ensamblado System.Web.Mvc.
El marco MVC incluye los siguientes componentes:
Modelos Los objetos modelo son las partes de la aplicación que implementan la lógica para el dominio de datos de la aplicación. A menudo, los objetos del modelo recuperan y almacenan el estado del modelo en una base de datos. Por ejemplo, un objeto Producto podría recuperar información de una base de datos, operar en ella y luego escribir información actualizada en una tabla de Productos en una base de datos de SQL Server. En aplicaciones pequeñas, el modelo es a menudo una separación conceptual en lugar de una física. Por ejemplo, si la aplicación solo lee un conjunto de datos y lo envía a la vista, la aplicación no tiene una capa de modelo físico y clases asociadas. En ese caso, el conjunto de datos asume el rol de un objeto modelo.
•
Vistas . Las vistas son los componentes que muestran la interfaz de usuario (UI) de la aplicación. Normalmente, esta IU se crea a partir de los datos del modelo. Un ejemplo sería una vista de edición de una tabla de Productos que muestra cuadros de texto, listas desplegables y cuadros de verificación según el estado actual de un objeto Producto.
•
Controladores Los controladores son los componentes que controlan la interacción del usuario, trabajan con el modelo y, en última instancia, seleccionan una vista para representar que muestra la interfaz de usuario. En una aplicación MVC, la vista solo muestra información; El controlador maneja y responde a la entrada e interacción del usuario. Por ejemplo, el controlador maneja los valores de cadena de consulta y pasa estos valores al modelo, que a su vez podría usar estos valores para consultar la base de datos.
•
Versiones
Versión Versión .NET Fecha de lanzamiento
MVC 1.0 .NET 3.5 2009-03-13
MVC 2.0 .NET 3.5 / 4.0 2010-03-10
MVC 3.0 .NET 4.0 2011-01-13
MVC 4.0 .NET 4.0 / 4.5 2012-08-15
https://riptutorial.com/es/home 2
Versión Versión .NET Fecha de lanzamiento
MVC 5.0 .NET 4.5 2013-10-17
MVC 5.1 .NET 4.5 2014-01-17
MVC 5.2 .NET 4.5 2014-08-28
MVC 6.0 .NET 4.5 2015-11-18
Core MVC 1.0 .NET 4.5 2016-07-12
Core MVC 1.1 .NET 4.5 2016-11-18
Examples
Hola MVC!
ASP.NET MVC es un framework de aplicaciones web de código abierto. MVC en sí es un patrón de diseño que se basa en tres componentes principales: model-view-controller .
Modelo : los modelos reflejan los objetos de su negocio y son un medio para pasar datos entre controladores y vistas.
Vista : las vistas son las páginas que representan y muestran los datos del modelo al usuario. Las vistas de ASP.NET MVC se escriben normalmente utilizando la sintaxis de Razor.
Controlador : los controladores manejan las solicitudes HTTP entrantes de un cliente y, por lo general, devuelven uno o más modelos a una vista apropiada.
Las características de ASP.NET MVC:
Ideal para desarrollar aplicaciones complejas pero ligeras.1. Proporciona un marco extensible y conectable que se puede reemplazar y personalizar fácilmente. Por ejemplo, si no desea utilizar el motor de visualización Razor o ASPX integrado, puede utilizar cualquier otro motor de visualización de terceros o incluso personalizar los existentes.
2.
Utiliza el diseño basado en componentes de la aplicación al dividirla lógicamente en los componentes Modelo, Vista y Controlador. Esto permite a los desarrolladores gestionar la complejidad de los proyectos a gran escala y trabajar en componentes individuales.
3.
La estructura MVC mejora el desarrollo basado en pruebas y la capacidad de prueba de la aplicación, ya que todos los componentes pueden diseñarse en función de la interfaz y probarse utilizando objetos simulados. Por lo tanto, ASP.NET MVC Framework es ideal para proyectos con un gran equipo de desarrolladores web.
4.
Admite todas las funciones vastas de ASP.NET, como Autorización y autenticación, Páginas maestras, Enlace de datos, Controles de usuario, Membresías, Enrutamiento de ASP.NET, etc.
5.
No utiliza el concepto de estado de vista (que está presente en ASP.NET). Esto ayuda en la 6.
https://riptutorial.com/es/home 3
creación de aplicaciones que son ligeras y dan control total a los desarrolladores.
Aplicación MVC simple
Vamos a crear una aplicación MVC simple que muestra detalles personales. Crea un nuevo proyecto MVC usando Visual Studio. Agregue un nuevo modelo llamado Person a la carpeta de modelos como sigue:
public class Person { public string Surname { get; set; } public string FirstName { get; set; } public string Patronymic { get; set; } public DateTime BirthDate { get; set; } }
Agregar un nuevo controlador a la carpeta Controladores:
public class HomeController : Controller { //Action Method public ActionResult Index() { // Initialize model Person person = new Person { Surname = "Person_SURNAME", FirstName = "Person_FIRSTNAME", Patronymic = "Person_PATRONYMIC", BirthDate = new DateTime(1990, 1, 1) }; // Send model to View for displaying to user return View(person); } }
Finalmente, agregue Ver a / Vistas / Inicio / carpeta llamada Index.cshtml :
@* Model for this view is Person *@ @model Hello_MVC.Models.Person <h2>Hello @Model.FirstName !</h2> <div> <h5>Details:</h5> <div> @Html.LabelFor(m => m.Surname) @Html.DisplayFor(m => m.Surname) </div> <div> @Html.LabelFor(m => m.FirstName) @Html.DisplayFor(m => m.FirstName) </div> <div> @Html.LabelFor(m => m.Patronymic) @Html.DisplayFor(m => m.Patronymic)
https://riptutorial.com/es/home 4
</div> <div> @Html.LabelFor(m => m.BirthDate) @Html.DisplayFor(m => m.BirthDate) </div> </div>
Lea Empezando con asp.net-mvc en línea: https://riptutorial.com/es/asp-net-mvc/topic/769/empezando-con-asp-net-mvc
https://riptutorial.com/es/home 5
Capítulo 2: ActionResult
Observaciones
Un ActionResult es el mejor punto de vista como un punto final web en MVC. Se puede acceder al método Ever ActionResult escribiendo la dirección web adecuada según lo configurado por su motor de enrutamiento.
Examples
Regresar una página de visualización
Este ActionResult devuelve una página de vista de Razor. Bajo la plantilla de enrutamiento estándar, este método ActionResult se alcanzaría en http: // localhost / about / me
La vista se buscará automáticamente en su sitio en ~/Views/About/Me.cshtml
public class AboutController : Controller { public ActionResult Me() { return View(); } }
Devolver un archivo
Un ActionResult puede devolver FileContentResult especificando la ruta del archivo y el tipo de archivo según la definición de extensión, conocido como tipo MIME.
El tipo MIME se puede configurar automáticamente según el tipo de archivo usando el método GetMimeMapping , o se puede definir manualmente en el formato adecuado, por ejemplo, "texto / plano".
Como FileContentResult requiere que se FileContentResult una matriz de bytes como una secuencia de archivos, System.IO.File.ReadAllBytes se puede usar para leer el contenido de los archivos como una matriz de bytes antes de enviar el archivo solicitado.
public class FileController : Controller { public ActionResult DownloadFile(String fileName) { String file = Server.MapPath("~/ParentDir/ChildDir" + fileName); String mimeType = MimeMapping.GetMimeMapping(path); byte[] stream = System.IO.File.ReadAllBytes(file); return File(stream, mimeType); } }
https://riptutorial.com/es/home 6
Devuelve un json
El resultado de la acción puede devolver Json.
1. Devolviendo a Json para transmitir json en ActionResult
public class HomeController : Controller { public ActionResult HelloJson() { return Json(new {message1="Hello", message2 ="World"}); } }
2. Devolver contenido para transmitir json en ActionResult
public class HomeController : Controller { public ActionResult HelloJson() { return Content("Hello World", "application/json"); } }
Lea ActionResult en línea: https://riptutorial.com/es/asp-net-mvc/topic/6246/actionresult
https://riptutorial.com/es/home 7
Capítulo 3: ActionResult
Examples
Ver resultado
public ActionResult Index() { // Renders a view as a Web page. return View(); }
Los métodos de acción generalmente devuelven un resultado que se conoce como un resultado de acción. La clase ActionResult es la clase base para todos los resultados de acción. El ActionInvoker decide qué tipo de resultado de acción devolver según la tarea que realiza el método de acción.
Es posible ser explícito sobre qué tipo devolver, pero generalmente no es necesario.
public ViewResult Index() { // Renders a view as a Web page. return View(); }
PartialViewResult
public ActionResult PopulateFoods() { IEnumerable<Food> foodList = GetAll(); // Renders a partial view, which defines a section of a view that can be rendered inside another view. return PartialView("_foodTable", foodVms);; }
Los métodos de acción generalmente devuelven un resultado que se conoce como un resultado de acción. La clase ActionResult es la clase base para todos los resultados de acción. El ActionInvoker decide qué tipo de resultado de acción devolver según la tarea que realiza el método de acción.
Es posible ser explícito sobre qué tipo devolver, pero generalmente no es necesario.
public PartialViewResult PopulateFoods() { IEnumerable<Food> foodList = GetAll(); // Renders a partial view, which defines a section of a view that can be rendered inside another view.
https://riptutorial.com/es/home 8
return PartialView("_foodTable", foodVms); }
RedirectResult
public ActionResult Index() { //Redirects to another action method by using its URL. return new RedirectResult("http://www.google.com"); }
Los métodos de acción generalmente devuelven un resultado que se conoce como un resultado de acción. La clase ActionResult es la clase base para todos los resultados de acción. El ActionInvoker decide qué tipo de resultado de acción devolver según la tarea que realiza el método de acción.
Es posible ser explícito sobre qué tipo devolver, pero generalmente no es necesario.
public RedirectResult Index() { //Redirects to another action method by using its URL. return new RedirectResult("http://www.google.com"); }
RedirectToRouteResult
public ActionResult PopulateFoods() { // Redirects to another action method. In this case the index method return RedirectToAction("Index"); }
Los métodos de acción generalmente devuelven un resultado que se conoce como un resultado de acción. La clase ActionResult es la clase base para todos los resultados de acción. El ActionInvoker decide qué tipo de resultado de acción devolver según la tarea que realiza el método de acción.
Es posible ser explícito sobre qué tipo devolver, pero generalmente no es necesario.
public RedirectToRouteResult PopulateFoods() { // Redirects to another action method. In this case the index method return RedirectToAction("Index"); }
En caso de que desee redirigir a otra acción con un parámetro, puede usar la sobrecarga RedirectToAction :
public ActionResult SomeActionWithParameterFromThisController(string parameterName) { // Some logic
https://riptutorial.com/es/home 9
} ..................... ..................... ..................... return RedirectToAction("SomeActionWithParameterFromThisController", new { parameterName = parameter });
ContentResult
public ActionResult Hello() { // Returns a user-defined content type, in this case a string. return Content("hello world!"); }
Los métodos de acción generalmente devuelven un resultado que se conoce como un resultado de acción. La clase ActionResult es la clase base para todos los resultados de acción. El ActionInvoker decide qué tipo de resultado de acción devolver según la tarea que realiza el método de acción.
Es posible ser explícito sobre qué tipo devolver, pero generalmente no es necesario.
public ContentResult Hello() { // Returns a user-defined content type, in this case a string. return Content("hello world!"); }
Puede saber más sobre esto aquí: Asp.Net Mvc: ContentResult vs. string
JsonResult
public ActionResult LoadPage() { Student result = getFirst(); //Returns a serialized JSON object. return Json(result, JsonRequestBehavior.AllowGet); }
Los métodos de acción generalmente devuelven un resultado que se conoce como un resultado de acción. La clase ActionResult es la clase base para todos los resultados de acción. El ActionInvoker decide qué tipo de resultado de acción devolver según la tarea que realiza el método de acción.
Es posible ser explícito sobre qué tipo devolver, pero generalmente no es necesario.
public JsonResult LoadPage() { Student result = getFirst(); //Returns a serialized JSON object.
https://riptutorial.com/es/home 10
return Json(result, JsonRequestBehavior.AllowGet); }
Lea ActionResult en línea: https://riptutorial.com/es/asp-net-mvc/topic/6487/actionresult
https://riptutorial.com/es/home 11
Capítulo 4: ActionResult
Sintaxis
// El método ActionResult devuelve una instancia que deriva de ActionResult. Puede crear un método de acción que puede devolver cualquier instancia que esté ajustada en el tipo de ActionResult apropiado.
•
// Los tipos de retorno de ActionResult incorporados son:•
Ver(); // ViewResult renderiza una vista como una página web•
Vista parcial(); // PartialViewResult presenta una vista parcial, que se puede utilizar como parte de otra vista.
•
Redirigir (); // RedirectResult redirige a otro método de acción utilizando su URL.•
RediectToAction (); RedirectToRoute (); // RedirectToRouteResult redirige a otro método de acción.
•
Contenido(); // ContentResult devuelve un tipo de contenido definido por el usuario.•
Json (); // JsonResult devuelve un objeto JSON serializado.•
JavaScript (); // JavaScriptResult devuelve un script que puede ejecutarse en el lado del cliente.
•
Expediente(); // FileResult devuelve una salida binaria para escribir en la respuesta.•
// EmptResult representa un valor de retorno que se utiliza si el método de acción debe devolver un resultado nulo.
•
Examples
Métodos de acción
Cuando el usuario ingresa una URL, por ejemplo: http://example-website.com/Example/HelloWorld , la aplicación MVC usará las reglas de enrutamiento para analizar esta URL y extraer la ruta secundaria, que determinará el controlador, la acción y los posibles parámetros. Para la url anterior, el resultado será / Example / HelloWorld, que, de manera predeterminada, los resultados de las reglas de enrutamiento proporcionan el nombre del controlador: Ejemplo y el nombre de la acción: HelloWorld.
public class ExampleController: Controller { public ActionResult HelloWorld() {
https://riptutorial.com/es/home 12
ViewData["ExampleData"] = "Hello world!"; return View(); } }
El método ActionResult anterior "HelloWorld" representará la vista llamada HelloWorld, donde luego podemos usar los datos de ViewData.
Asignación de parámetros de acción-método
Si hubiera otro valor en la URL como: / Example / ProcessInput / 2, las reglas de enrutamiento amenazarán el último número como un parámetro pasado a la acción ProcessInput del controlador Ejemplo.
public ActionResult ProcessInput(int number) { ViewData["OutputMessage"] = string.format("The number you entered is: {0}", number); return View(); }
Llamando a un ActionResult en otro ActionResult
Podemos llamar a un resultado de acción en otro resultado de acción.
public ActionResult Action1() { ViewData["OutputMessage"] = "Hello World"; return RedirectToAction("Action2","ControllerName"); //this will go to second action; } public ActionResult Action2() { return View(); //this will go to Action2.cshtml as default; }
Lea ActionResult en línea: https://riptutorial.com/es/asp-net-mvc/topic/6635/actionresult
https://riptutorial.com/es/home 13
Capítulo 5: Anotaciones de datos
Introducción
Podemos agregar validaciones a nuestra aplicación al agregar Anotaciones de datos a nuestras clases modelo. Las anotaciones de datos nos permiten describir las reglas que queremos que se apliquen a las propiedades de nuestro modelo, y ASP.NET MVC se encargará de hacerlas cumplir y mostrar los mensajes apropiados a los usuarios.
Examples
Atributos básicos de validación utilizados en ViewModel
Modelo
using System.ComponentModel.DataAnnotations; public class ViewModel { [Required(ErrorMessage="Name is required")] public string Name { get; set; } [StringLength(14, MinimumLength = 14, ErrorMessage = "Invalid Phone Number")] [Required(ErrorMessage="Phone Number is required")] public string PhoneNo { get; set; } [Range(typeof(decimal), "0", "150")] public decimal? Age { get; set; } [RegularExpression(@"^\d{5}(-\d{4})?$", ErrorMessage = "Invalid Zip Code.")] public string ZipCode {get;set;} [EmailAddress(ErrorMessage = "Invalid Email Address")] public string Email { get; set; } [Editable(false)] public string Address{ get; set; } }
Ver
// Include Jquery and Unobstructive Js here for client side validation @using (Html.BeginForm("Index","Home") { @Html.TextBoxFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name) @Html.TextBoxFor(model => model.PhoneNo) @Html.ValidationMessageFor(model => model.PhoneNo)
https://riptutorial.com/es/home 14
@Html.TextBoxFor(model => model.Age) @Html.ValidationMessageFor(model => model.Age) @Html.TextBoxFor(model => model.ZipCode) @Html.ValidationMessageFor(model => model.ZipCode) @Html.TextBoxFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) @Html.TextBoxFor(model => model.Address) @Html.ValidationMessageFor(model => model.Address) <input type="submit" value="submit" /> }
Controlador
public ActionResult Index(ViewModel _Model) { // Checking whether the Form posted is valid one. if(ModelState.IsValid) { // your model is valid here. // perform any actions you need to, like database actions, // and/or redirecting to other controllers and actions. } else { // redirect to same action return View(_Model); } }
Validación remota
Validación remota utilizada para verificar si el contenido que se ingresa en el control de entrada es válido o no, enviando una solicitud ajax al lado del servidor para verificarlo.
Trabajando
RemoteAttribute funciona al realizar una llamada AJAX desde el cliente a una acción del controlador con el valor del campo que se está validando. La acción del controlador luego devuelve una respuesta JsonResult indica el éxito o el fracaso de la validación. Devolviendo true de su acción indica que la validación pasó. Cualquier otro valor indica falla. Si devuelve false , se utiliza el mensaje de error especificado en el atributo. Si devuelve algo más, como una cadena o incluso un entero, se mostrará como el mensaje de error. A menos que necesite que su mensaje de error sea dinámico, tiene sentido devolver verdadero o falso y dejar que el validador use el mensaje de error especificado en el atributo.
https://riptutorial.com/es/home 15
ViewModel
public class ViewModel { [Remote("IsEmailAvailable", "Group", HttpMethod = "POST", ErrorMessage = "Email already exists. Please enter a different email address.")] public string Email{ get; set; } }
Controlador
[HttpPost] public JsonResult IsEmailAvailable(string Email) { // Logic to check whether email is already registered or Not. var emailExists = IsEmailRegistered(); return Json(!emailExists); }
Live Demo Fiddle
Puede pasar propiedades adicionales del modelo al método del controlador utilizando la propiedad AdditionalFields de RemoteAttribute . Un escenario típico sería pasar la propiedad de ID del modelo en forma de 'Editar', de modo que la lógica del controlador pueda ignorar los valores del registro existente.
Modelo
public int? ID { get; set; } [Display(Name = "Email address")] [DataType(DataType.EmailAddress)] [Required(ErrorMessage = "Please enter you email address")] [Remote("IsEmailAvailable", HttpMethod="Post", AdditionalFields="ID", ErrorMessage = "Email already exists. Please enter a different email address.")] public string Email { get; set; }
Controlador
[HttpPost] public ActionResult Validate(string email, int? id) { if (id.HasValue) { return Json(!db.Users.Any(x => x.Email == email && x.ID != id); } else { return Json(!db.Users.Any(x => x.Email == email); } }
Demostración de trabajo - Campos adicionales
Nota adicional
https://riptutorial.com/es/home 16
El mensaje de error predeterminado es comprensiblemente vago, por lo que siempre recuerde anular el mensaje de error predeterminado cuando use el RemoteAttribute .
RequiredAttribute
El atributo Required especifica que una propiedad es requerida. Se puede especificar un mensaje de error al usar la propiedad ErrorMessage en el atributo.
Primero agregue el espacio de nombres:
using System.ComponentModel.DataAnnotations;
Y aplicar el atributo en una propiedad.
public class Product { [Required(ErrorMessage = "The product name is required.")] public string Name { get; set; } [Required(ErrorMessage = "The product description is required.")] public string Description { get; set; } }
También es posible utilizar recursos en el mensaje de error para aplicaciones globalizadas. En este caso, el ErrorMessageResourceName debe especificarse con la clave de recurso de la clase de recurso (archivo resx ) que debe ErrorMessageResourceType en el ErrorMessageResourceType :
public class Product { [Required(ErrorMessageResourceName = "ProductNameRequired", ErrorMessageResourceType = typeof(ResourceClass))] public string Name { get; set; } [Required(ErrorMessageResourceName = "ProductDescriptionRequired", ErrorMessageResourceType = typeof(ResourceClass))] public string Description { get; set; } }
StringLengthAttribute
El atributo StringLength especifica la longitud mínima y máxima de los caracteres permitidos en un campo de datos. Este atributo se puede aplicar en propiedades, campos públicos y parámetros. El mensaje de error se debe especificar en la propiedad ErrorMessage en el atributo. Las propiedades MinimumLength y MaximumLength especifican el mínimo y el máximo respectivamente.
Primero agregue el espacio de nombres:
using System.ComponentModel.DataAnnotations;
Y aplicar el atributo en una propiedad.
https://riptutorial.com/es/home 17
public class User { // set the maximum [StringLength(20, ErrorMessage = "The username cannot exceed 20 characters. ")] public string Username { get; set; } [StringLength(MinimumLength = 3, MaximumLength = 16, ErrorMessage = "The password must have between 3 and 16 characters.")] public string Password { get; set; } }
También es posible utilizar recursos en el mensaje de error para aplicaciones globalizadas. En este caso, el ErrorMessageResourceName debe especificarse con la clave de recurso de la clase de recurso (archivo resx ) que debe ErrorMessageResourceType en el ErrorMessageResourceType :
public class User { [StringLength(20, ErrorMessageResourceName = "StringLength", ErrorMessageResourceType = typeof(ResoucesKeys))] public string Username { get; set; } [StringLength(MinimumLength = 3, MaximumLength = 16, ErrorMessageResourceName = "StringLength", ErrorMessageResourceType = typeof(ResoucesKeys))] public string Password { get; set; } }
Atributo de rango
El atributo Range puede decorar cualquier propiedad o campo público y especifica un rango en el que un campo numérico debe estar entre para ser considerado válido.
[Range(minimumValue, maximumValue)] public int Property { get; set; }
Además, acepta una propiedad opcional ErrorMessage que se puede usar para configurar el mensaje recibido por el usuario cuando se ingresan datos no válidos:
[Range(minimumValue, maximumValue, ErrorMessage = "{your-error-message}")] public int Property { get; set; }
Ejemplo
[Range(1,100, ErrorMessage = "Ranking must be between 1 and 100.")] public int Ranking { get; set; }
Atributo de expresión regular
El atributo [RegularExpression] puede decorar cualquier propiedad o campo público y especifica una expresión regular que debe coincidir para que la propiedad se considere válida.
https://riptutorial.com/es/home 18
[RegularExpression(validationExpression)] public string Property { get; set; }
Además, acepta una propiedad opcional ErrorMessage que se puede usar para configurar el mensaje recibido por el usuario cuando se ingresan datos no válidos:
[RegularExpression(validationExpression, ErrorMessage = "{your-error-message}")] public string Property { get; set; }
Ejemplo (s)
[RegularExpression(@"^[a-z]{8,16}?$", ErrorMessage = "A User Name must consist of 8-16 lowercase letters")] public string UserName{ get; set; } [RegularExpression(@"^\d{5}(-\d{4})?$", ErrorMessage = "Please enter a valid ZIP Code (e.g. 12345, 12345-1234)")] public string ZipCode { get; set; }
Comparar atributo
El atributo de Compare compara dos propiedades de un modelo.
El mensaje de error se puede especificar usando la propiedad ErrorMessage o usando archivos de recursos.
Para usar el atributo Compare incluya using para el siguiente espacio de nombres:
using System.ComponentModel.DataAnnotations;
Luego puedes usar el atributo en tu modelo:
public class RegisterModel { public string Email { get; set; } [Compare("Email", ErrorMessage = "The Email and Confirm Email fields do not match.")] public string ConfirmEmail { get; set; } }
Cuando se valida este modelo, si Email y ConfirmEmail tienen valores diferentes, la validación fallará.
Mensajes de error localizados
Al igual que con todos los atributos de validación, es posible usar mensajes de error de archivos de recursos. En este ejemplo, el mensaje de error se cargará desde los recursos del archivo de Resources , el nombre del recurso es CompareValidationMessage :
public class RegisterModel { public string Email { get; set; }
https://riptutorial.com/es/home 19
["Email", ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "CompareValidationMessage")] public string ConfirmEmail { get; set; } }
Evitar cadenas en nombres de propiedades
Para evitar utilizar la cadena para el valor de la propiedad, en C # 6+ puede usar la palabra clave nameof :
public class RegisterModel { public string Email { get; set; } [Compare(nameof(Email), ErrorMessage = "The Email and Confirm Email fields do not match.")] public string ConfirmEmail { get; set; } }
Marcadores de posición en mensajes de error
Puede utilizar marcadores de posición en sus mensajes de error. El marcador de posición {0} se reemplaza con el nombre de visualización de la propiedad actual y {1} se reemplaza con el nombre de visualización de la propiedad relacionada:
public class RegisterModel { [Display(Name = "Email")] public string Email { get; set; } [Display(Name = "Confirm Email")] [Compare("Email", ErrorMessage = "The '{1}' and '{0}' fields do not match.")] public string ConfirmEmail { get; set; } }
Si la validación del modelo falla, el mensaje de error será
Los campos 'Correo electrónico' y 'Confirmar correo electrónico' no coinciden.
Atributo de validación personalizado
Cuando se trata de validar algunas reglas que no son validación de datos genéricos, por ejemplo, asegurarse de que se requiere un campo o algún rango de valores, pero que son específicos para su lógica de negocios, puede crear su propio Validador personalizado . Para crear un atributo de validación personalizado, solo necesita inherit clase ValidationAttribute y override su método IsValid . El método IsValid toma dos parámetros, el primero es un object denominado como value y el segundo es un ValidationContext object llamado validationContext . Value refiere al valor real del campo que va a validar su validador personalizado.
Supongamos que desea validar el Email través de un Custom Validator
https://riptutorial.com/es/home 20
public class MyCustomValidator : ValidationAttribute { private static string myEmail= "[email protected]"; protected override ValidationResult IsValid(object value, ValidationContext validationContext) { string Email = value.ToString(); if(myEmail.Equals(Email)) return new ValidationResult("Email Already Exist"); return ValidationResult.Success; } } public class SampleViewModel { [MyCustomValidator] [Required] public string Email { get; set; } public string Name { get; set; } }
Aquí está su DotNetFiddle Demo
Modelo EDMx - Anotación de datos
Edmx modelo internel
public partial class ItemRequest { public int RequestId { get; set; } //... }
Agregando anotación de datos a esto: si modificamos este modelo directamente, cuando se realiza una actualización del modelo, los cambios se pierden. asi que
Para agregar un atributo en este caso 'Requerido'
Crear una nueva clase - cualquier nombre Entonces
using System.ComponentModel; using System.ComponentModel.DataAnnotations; //make sure the namespace is equal to the other partial class ItemRequest namespace MvcApplication1.Models { [MetadataType(typeof(ItemRequestMetaData))] public partial class ItemRequest { } public class ItemRequestMetaData { [Required]
https://riptutorial.com/es/home 21
public int RequestId {get;set;} //... } }
o
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace YourApplication.Models { public interface IEntityMetadata { [Required] Int32 Id { get; set; } } [MetadataType(typeof(IEntityMetadata))] public partial class Entity : IEntityMetadata { /* Id property has already existed in the mapped class */ } }
Anotaciones de datos para la primera implementación de la base de datos (código de modelo generado automáticamente)
[MetadataType(typeof(RoleMetaData))] public partial class ROLE { } public class RoleMetaData { [Display(Name = "Role")] public string ROLE_DESCRIPTION { get; set; } [Display(Name = "Username")] public string ROLE_USERNAME { get; set; } }
Si utilizó la base de datos primero y su código de modelo se generó automáticamente, este mensaje aparecerá sobre su código de modelo:
Este código fue generado a partir de una plantilla. Los cambios manuales en este archivo pueden causar un comportamiento inesperado en su aplicación. Los cambios manuales en este archivo se sobrescribirán si el código se regenera
Si desea usar anotaciones de datos y no desea que se sobrescriban si actualiza el edmx, simplemente agregue otra clase parcial a su carpeta modelo que se parece al ejemplo anterior.
Lea Anotaciones de datos en línea: https://riptutorial.com/es/asp-net-mvc/topic/1961/anotaciones-
https://riptutorial.com/es/home 22
de-datos
https://riptutorial.com/es/home 23
Capítulo 6: Áreas
Introducción
¿Qué es el área?
Un área es una unidad más pequeña en la aplicación MVC que se utiliza como una forma de separar una gran cantidad de módulos de aplicaciones en grupos funcionales. Una aplicación puede contener múltiples áreas que se almacenan en la carpeta Áreas.
Cada área puede contener diferentes modelos, controladores y vistas según los requisitos. Para usar un área, es necesario registrar el nombre del área en RouteConfig y definir el prefijo de la ruta.
Observaciones
Si quieres ir a esta área a través de tu controlador predeterminado
return RedirectToAction("Index","Home",new{area="areaname"});
Examples
Crear una nueva área
Haga clic derecho en la carpeta / nombre de su proyecto y cree un área nueva y asígnele un nombre.
En la aplicación mvc internet / empty / basic se creará una carpeta con el nombre del área, que contendrá tres carpetas diferentes llamadas controlador, modelo y vistas y un archivo de clase llamado
" areaname AreaRegistration.cs"
Configurar RouteConfig.cs
En su carpeta App_start abra routeconfig.cs y haga esto
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, namespaces:new []{"nameofyourproject.Controllers"}// add this line ; );
Cree un nuevo controlador y configure areanameAreaRegistration.cs
https://riptutorial.com/es/home 24
maproute
Crear un nuevo controlador foreg
ControllerName: "Home", ActionresultName: "Index"
abra AreaRegistraion.cs y agregue el nombre del controlador y el nombre de la acción que se redireccionará a
context.MapRoute( "nameofarea_default", "nameofarea/{controller}/{action}/{id}", // url shown will be like this in browser new {controller="Home", action = "Index", id = UrlParameter.Optional } );
Lea Áreas en línea: https://riptutorial.com/es/asp-net-mvc/topic/6310/areas
https://riptutorial.com/es/home 25
Capítulo 7: Asp.net mvc enviar correo
Examples
Formulario de contacto en Asp MVC
1. Modelo:
public class ContactModel { [Required, Display(Name="Sender Name")] public string SenderName { get; set; } [Required, Display(Name = "Sender Email"), EmailAddress] public string SenderEmail { get; set; } [Required] public string Message { get; set; } }
2. Controlador:
public class HomeController { [HttpPost] [ValidateAntiForgeryToken] public async Task<ActionResult> Contact(ContectModel model) { if (ModelState.IsValid) { var mail = new MailMessage(); mail.To.Add(new MailAddress(model.SenderEmail)); mail.Subject = "Your Email Subject"; mail.Body = string.Format("<p>Email From: {0} ({1})</p><p>Message:</p><p>{2}</p>", model.SenderName, mail.SenderEmail, model.Message); mail.IsBodyHtml = true; using (var smtp = new SmtpClient()) { await smtp.SendMailAsync(mail); return RedirectToAction("SuccessMessage"); } } return View(model); } public ActionResult SuccessMessage() { return View(); } }
3. Web.Config:
<system.net> <mailSettings>
https://riptutorial.com/es/home 26
<smtp from="[email protected]"> <network host="smtp-mail.outlook.com" port="587" userName="[email protected]" password="password" enableSsl="true" /> </smtp> </mailSettings> </system.net>
4. Ver:
Contact.cshtml
@model ContectModel @using (Html.BeginForm()) { @Html.AntiForgeryToken() <h4>Send your comments.</h4> <hr /> <div class="form-group"> @Html.LabelFor(m => m.SenderName, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.SenderName, new { @class = "form-control" }) @Html.ValidationMessageFor(m => m.SenderName) </div> </div> <div class="form-group"> @Html.LabelFor(m => m.SenderEmail, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.SenderEmail, new { @class = "form-control" }) @Html.ValidationMessageFor(m => m.SenderEmail) </div> </div> <div class="form-group"> @Html.LabelFor(m => m.Message, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextAreaFor(m => m.Message, new { @class = "form-control" }) @Html.ValidationMessageFor(m => m.Message) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" class="btn btn-default" value="Send" /> </div> </div> }
SuccessMessage.cshtml
<h2>Your message has been sent</h2>
Enviando correo electrónico desde la clase
De esta manera, puede ser muy útil, pero algunas personas (como yo) tienen un código de repetición, y como usted nos muestra, significa que necesito crear un controlador de contacto con
https://riptutorial.com/es/home 27
el mismo código en cada proyecto que tenemos, por lo que , Creo que esto puede ser útil también
Esta es mi clase, que puede estar en una DLL o lo que sea
public class Emails { public static void SendHtmlEmail(string receiverEmail, string subject, string body, bool Ssl = false) { //Those are read it from webconfig or appconfig var client = new SmtpClient(ConfigurationManager.AppSettings["MailServer"], Convert.ToInt16 (ConfigurationManager.AppSettings["MailPort"])) { Credentials = new NetworkCredential(ConfigurationManager.AppSettings["MailSender"], ConfigurationManager.AppSettings["MailSenderPassword"]), EnableSsl = Ssl }; MailMessage message = new MailMessage(); message.From = new MailAddress(ConfigurationManager.AppSettings["MailSender"]); message.To.Add(receiverEmail); // message.To.Add("[email protected]"); message.Subject = subject; message.IsBodyHtml = true; message.Body = body; client.Send(message); } }
Como se ve, se leerá desde el webconfig, así que necesitamos configurarlo, esta configuración es para Gmail, pero cada host tiene su propia configuración.
<appSettings> <add key="webpages:Version" value="3.0.0.0" /> <add key="webpages:Enabled" value="false" /> <add key="ClientValidationEnabled" value="true" /> <add key="UnobtrusiveJavaScriptEnabled" value="true" /> <add key="AdminUser" value="[email protected]" /> <add key="AdminPassWord" value="123456789" /> <add key="SMTPName" value="smtp.gmail.com" /> <add key="SMTPPort" value="587" /> </appSettings>
Lea Asp.net mvc enviar correo en línea: https://riptutorial.com/es/asp-net-mvc/topic/9736/asp-net-mvc-enviar-correo
https://riptutorial.com/es/home 28
Capítulo 8: Ayudantes html
Introducción
Los ayudantes de HTML son métodos utilizados para representar elementos HTML en una vista. Son parte del espacio de nombres System.Web.Mvc.HtmlHelper .
Hay diferentes tipos de ayudantes de HTML:
Ayudantes HTML estándar : se utilizan para representar elementos HTML normales, por ejemplo, Html.TextBox() .
Ayudantes HTML fuertemente tipados : estos ayudantes representan elementos HTML basados en las propiedades del modelo, por ejemplo, Html.TextBoxFor() .
Ayudantes HTML personalizados : el usuario puede crear un método auxiliar personalizado que devuelve MvcHtmlString .
Examples
Ayudante HTML personalizado - Nombre para mostrar
/// <summary> /// Gets displayName from DataAnnotations attribute /// </summary> /// <typeparam name="TModel"></typeparam> /// <typeparam name="TProperty"></typeparam> /// <param name="htmlHelper"></param> /// <param name="expression"></param> /// <returns></returns> public static MvcHtmlString GetDisplayName<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) { var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); var value = metaData.DisplayName ?? (metaData.PropertyName ?? ExpressionHelper.GetExpressionText(expression)); return MvcHtmlString.Create(value); }
Ayudante personalizado - botón Enviar de envío
/// <summary> /// Creates simple button /// </summary> /// <param name="poHelper"></param> /// <param name="psValue"></param> /// <returns></returns> public static MvcHtmlString SubmitButton(this HtmlHelper poHelper, string psValue) { return new MvcHtmlString(string.Format("<input type=\"submit\" value=\"{0}\">", psValue));
https://riptutorial.com/es/home 29
}
Lista exhaustiva de ejemplos de HtmlHelper que incluye salida HTML
HtmlHelper.Action()
@Html.Action(actionName: "Index")salida: el HTML representado por un método de acción denominado Index()
•
@Html.Action(actionName: "Index", routeValues: new {id = 1})salida: el HTML representado por un método de acción llamado Index(int id)
•
@(Html.Action("Index", routeValues: new RouteValueDictionary(new Dictionary<string, object>{ {"id", 1} })))salida: el HTML representado por un método de acción llamado Index(int id)
•
@Html.Action(actionName: "Index", controllerName: "Home")salida: el código HTML representado por un método de acción denominado Index() en el HomeController
•
@Html.Action(actionName: "Index", controllerName: "Home", routeValues: new {id = 1})salida: el HTML representado por un método de acción denominado Index(int id) en el HomeController
•
@Html.Action(actionName: "Index", controllerName: "Home", routeValues: new RouteValueDictionary(new Dictionary<string, object>{ {"id", 1} }))salida: el HTML representado por un método de acción denominado Index(int id) en el HomeController
•
HtmlHelper.ActionLink()
@Html.ActionLink(linkText: "Click me", actionName: "Index")salida: <a href="Home/Index">Click me</a>
•
@Html.ActionLink(linkText: "Click me", actionName: "Index", routeValues: new {id = 1})salida: <a href="Home/Index/1">Click me</a>
•
@Html.ActionLink(linkText: "Click me", actionName: "Index", routeValues: new {id = 1}, htmlAttributes: new {@class = "btn btn-default", data_foo = "bar")salida: <a href="Home/Index/1" class="btn btn-default" data-foo="bar">Click me</a>
•
@Html.ActionLink()salida: <a href=""></a>
•
@HtmlHelper.BeginForm()
@using (Html.BeginForm("MyAction", "MyController", FormMethod.Post, new {id="form1",@class = "form-horizontal"}))salida: <form action="/MyController/MyAction" class="form-horizontal" id="form1" method="post">
•
Ayudantes HTML estándar con sus salidas HTML
Html.TextBox ()
https://riptutorial.com/es/home 30
@Html.TextBox("Name", null, new { @class = "form-control" })salida: <input class="form-control" id="Name"name="Name"type="text"value=""/>
•
@Html.TextBox("Name", "Stack Overflow", new { @class = "form-control" })salida: <input class="form-control" id="Name"name="Name"type="text" value="Stack Overflow"/>
•
Html.TextArea ()
@Html.TextArea("Notes", null, new { @class = "form-control" })salida: <textarea class="form-control" id="Notes" name="Notes" rows="2" cols="20"></textarea>
•
@Html.TextArea("Notes", "Please enter Notes", new { @class = "form-control" })salida: <textarea class="form-control" id="Notes" name="Notes" rows="2" cols="20" >Please enter Notes</textarea>
•
Html.Label ()
@Html.Label("Name","FirstName")output: <label for="Name"> FirstName </label>
•
@Html.Label("Name", "FirstName", new { @class = "NameClass" })output: <label for="Name" class="NameClass">FirstName</label>
•
Html.Hidden ()
@Html.Hidden("Name", "Value")salida: <input id="Name" name="Name" type="hidden" value="Value" />
•
Html.CheckBox ()
@Html.CheckBox("isStudent", true)salida: <input checked="checked" id="isStudent" name="isStudent" type="checkbox" value="true" />
•
Html.Password ()
@Html.Password("StudentPassword")salida: <input id="StudentPassword" name="StudentPassword" type="password" value="" />
•
Ayudante personalizado - Botón de radio renderizado con etiqueta
public static MvcHtmlString RadioButtonLabelFor<TModel, TProperty>(this HtmlHelper<TModel> self, Expression<Func<TModel, TProperty>> expression, bool value, string labelText) { // Retrieve the qualified model identifier string name = ExpressionHelper.GetExpressionText(expression); string fullName = self.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name); // Generate the base ID TagBuilder tagBuilder = new TagBuilder("input"); tagBuilder.GenerateId(fullName); string idAttr = tagBuilder.Attributes["id"]; // Create an ID specific to the boolean direction idAttr = string.Format("{0}_{1}", idAttr, value); // Create the individual HTML elements, using the generated ID
https://riptutorial.com/es/home 31
MvcHtmlString radioButton = self.RadioButtonFor(expression, value, new { id = idAttr }); MvcHtmlString label = self.Label(idAttr, labelText); return new MvcHtmlString(radioButton.ToHtmlString() + label.ToHtmlString()); }
Ejemplo: @Html.RadioButtonLabelFor(m => m.IsActive, true, "Yes")
Ayudante personalizado - Selector de fecha y hora
public static MvcHtmlString DatePickerFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes) { var sb = new StringBuilder(); var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); var dtpId = "dtp" + metaData.PropertyName; var dtp = htmlHelper.TextBoxFor(expression, htmlAttributes).ToHtmlString(); sb.AppendFormat("<div class='input-group date' id='{0}'> {1} <span class='input-group-addon'><span class='glyphicon glyphicon-calendar'></span></span></div>", dtpId, dtp); return MvcHtmlString.Create(sb.ToString()); }
Ejemplo:
@Html.DatePickerFor(model => model.PublishedDate, new { @class = "form-control" })
Si usa Bootstrap.v3.Datetimepicker, su JavaScript es como el siguiente:
$('#dtpPublishedDate').datetimepicker({ format: 'MMM DD, YYYY' });
Lea Ayudantes html en línea: https://riptutorial.com/es/asp-net-mvc/topic/2290/ayudantes-html
https://riptutorial.com/es/home 32
Capítulo 9: Dockerización de la aplicación ASP.NET
Examples
Dockerfile y Nuget
La aplicación Dockerization de ASP.NET requiere un Dockerfile para su configuración y su ejecución como contenedor de ventana acoplable.
FROM microsoft/dotnet:latest RUN apt-get update && apt-get install sqlite3 libsqlite3-dev COPY . /app WORKDIR /app RUN ["dotnet", "restore"] RUN ["dotnet", "build"] RUN npm install && npm run postscript RUN bower install RUN ["dotnet", "ef", "database", "update"] EXPOSE 5000/tcp ENTRYPOINT ["dotnet", "run", "--server.urls", "http://0.0.0.0:5000"]
Un archivo de configuración de alimentación de nuget ayuda a recuperar de la fuente correcta. El uso de este archivo depende de la configuración actual del proyecto y puede cambiar a los requisitos del proyecto de la suite.
<?xml version="1.0" encoding="utf-8"?> <configuration> <packageSources> <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" /> <packageSources> <packageRestore> <add key="enabled" value="True" /> <add key="automatic" value="True" /> <packageRestore> <bindingRedirects> <add key="skip" value="False" /> </bindingRedirects> </configuration>
Soporte POSTGRESQL.
https://riptutorial.com/es/home 33
"Data": { "DefaultConnection": { "ConnectionString": "Host=localhost;Username=postgres;Password=******;Database=postgres;Port=5432;Pooling=true;" } },
Dockerización
Es necesario tener .NET o un paquete mono-aspnet.
Es importante entender la importancia de la dockerización. Instale dotnet en ubuntu o en el sistema operativo en el que está trabajando.
Instalando DOTNET
$ sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ trusty main" > /etc/apt/sources.list.d/dotnetdev.list' $ sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893 $ sudo apt-get update Ubuntu 16.04 $ sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ xenial main" > /etc/apt/sources.list.d/dotnetdev.list' $ sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893 $ sudo apt-get update
Instalar .NET Core SDK
$ sudo apt-get install dotnet-dev-1.0.0-preview2-003121
CORTESÍA: https://www.microsoft.com/net/core#ubuntu
Para la instalación de Docker, siga https://docs.docker.com/engine/installation/linux/ubuntulinux/
POR PUERTO:
Kestrel server port : 5000 Docker Deamon will listen to port : EXPOSE 5000/tcp
Para la construcción de docker:
$ sudo docker build -t myapp .
Para ejecutar el contenedor docker:
$ sudo docker run -t -d -p 8195:5000 myapp
https://riptutorial.com/es/home 34
Para visitar el sitio:
$ ifconfig eth0 : ***.***.** server-ip-address
El sitio estará disponible en (dada esta configuración):
http://server-ip-address:8195
Procesos Docker. Se listarán los procesos en ejecución.
$ sudo docker ps
Para eliminar el proceso o el contenedor.
$ sudo docker rm -rf <process_id>
Lea Dockerización de la aplicación ASP.NET en línea: https://riptutorial.com/es/asp-net-mvc/topic/6740/dockerizacion-de-la-aplicacion-asp-net
https://riptutorial.com/es/home 35
Capítulo 10: Empaquetado y Minificación
Examples
Minificación
La minificación se utiliza para reducir el tamaño de los archivos CSS y Javascript para acelerar los tiempos de descarga. Este proceso se realiza mediante la eliminación de todos los espacios en blanco, comentarios y cualquier otro contenido no esencial de los archivos.
Este proceso se realiza automáticamente cuando se utiliza un objeto ScriptBundle o StyleBundle . Si necesita deshabilitarlo, debe usar un objeto Bundle básico.
Ejemplo usando minificación
El siguiente código usa directivas de preprocesador para aplicar el agrupamiento solo durante las versiones a fin de permitir una depuración más fácil durante las versiones no liberadas (ya que los archivos no empaquetados suelen ser más fáciles de navegar):
public static void RegisterBundles(BundleCollection bundles) { #if DEBUG bundles.Add(new Bundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js")); bundles.Add(new Bundle("~/Content/css").Include("~/Content/site.css")); #else bundles.Add(new ScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js")); bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css")); #endif }
Guiones y paquetes de estilo
El siguiente es el fragmento de código predeterminado para el archivo BundleConfig.cs.
using System.Web.Optimization; public class BundleConfig { // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725 public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/bundles/jquery").Include( "~/Scripts/jquery-{version}.js")); // Use the development version of Modernizr to develop with and learn from. Then, when you're // ready for production, use the build tool at http://modernizr.com to pick only the tests you need. bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
https://riptutorial.com/es/home 36
"~/Scripts/modernizr-*")); bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css")); bundles.Add(new StyleBundle("~/Content/themes/base/css").Include( "~/Content/themes/base/jquery.ui.core.css", "~/Content/themes/base/jquery.ui.resizable.css", } }
Los paquetes se registran en el archivo Global.asax dentro del método Application_Start ():
using System.Web.Optimization; protected void Application_Start() { BundleConfig.RegisterBundles(BundleTable.Bundles); }
Los paquetes deben ser representados en tus Vistas como tal:
@using System.Web.Optimization @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/modernizr") @Styles.Render("~/Content/css") @Styles.Render("~/Content/themes/base/css")
Tenga en cuenta que la agrupación no se produce cuando está en modo de desarrollo (donde el elemento de compilación en el archivo Web.config se establece en debug = "true"). En su lugar, las declaraciones de Render en sus Vistas incluirán cada archivo individual en un formato no agrupado, no minificado, para facilitar la depuración.
Una vez que la aplicación está en modo de producción (donde el elemento de compilación en el archivo Web.config se establece en debug = "false"), se realizará la agrupación.
Esto puede llevar a complicaciones para los scripts que hacen referencia a rutas relativas de otros archivos, como las referencias a los archivos de iconos de Twitter Bootstrap. Esto se puede abordar utilizando la clase CssRewriteUrlTransform de System.Web.Optimization:
bundles.Add(new StyleBundle("~/bundles/css").Include( "~/Content/css/*.css", new CssRewriteUrlTransform()));
La clase CssRewriteUrlTransform reescribirá las URL relativas dentro de los archivos agrupados en rutas absolutas, de modo que las referencias permanecerán intactas después de que la referencia de llamada se mueva a la ubicación del paquete (p. Ej., Utilizando el código anterior, pasando de "~ / Content / css / bootstrap.css "a" ~ / bundles / css / bootstrap.css ").
Lea Empaquetado y Minificación en línea: https://riptutorial.com/es/asp-net-mvc/topic/1959/empaquetado-y-minificacion
https://riptutorial.com/es/home 37
Capítulo 11: Enrutamiento
Introducción
El enrutamiento es cómo ASP.NET MVC hace coincidir un URI con una acción. El módulo de enrutamiento es responsable de asignar las solicitudes entrantes del navegador a las acciones particulares del controlador MVC.
MVC 5 admite un nuevo tipo de enrutamiento, llamado enrutamiento de atributos. Como su nombre lo indica, el enrutamiento de atributos utiliza atributos para definir rutas. El enrutamiento de atributos le brinda más control sobre los URI en su aplicación web.
Examples
Enrutamiento personalizado
El enrutamiento personalizado proporciona una necesidad especializada de enrutamiento para manejar solicitudes entrantes específicas.
Para definir rutas personalizadas, tenga en cuenta que el orden de las rutas que agrega a la tabla de rutas es importante.
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); // this is an advanced custom route // you can define custom URL with custom parameter(s) point to certain action method routes.MapRoute( "CustomEntry", // Route name "Custom/{entryId}", // Route pattern new { controller = "Custom", action = "Entry" } // Default values for defined parameters above ); // this is a basic custom route // any custom routes take place on top before default route routes.MapRoute( "CustomRoute", // Route name "Custom/{controller}/{action}/{id}", // Route pattern new { controller = "Custom", action = "Index", id = UrlParameter.Optional } // Default values for defined parameters above ); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // Route pattern new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Default values for defined parameters above ); }
https://riptutorial.com/es/home 38
controller y action nombres de action están reservados. Por defecto, MVC asigna {controller} parte de la URL a la <controller>Controller y luego busca un método con el nombre <action> sin agregar ningún sufijo.
Aunque puede ser tentador crear una familia de rutas utilizando la plantilla {controller}/{action}/{parameter} al hacer esto usted revela la estructura de su aplicación y hace que las URL sean algo frágiles porque cambiar el nombre del controlador cambia la configuración. Ruta y rompe los enlaces guardados por el usuario.
Prefiere configuración de ruta explícita:
routes.MapRoute( "CustomRoute", // Route name "Custom/Index/{id}", // Route pattern new { controller = "Custom", action = nameof(CustomController.Index), id = UrlParameter.Optional } );
(no puede usar el nameof operador para el nombre del controlador, ya que tendrá un sufijo adicional Controller ) que se debe omitir al configurar el nombre del controlador en la ruta.
Añadiendo ruta personalizada en mvc
El usuario puede agregar una ruta personalizada, asignando una URL a una acción específica en un controlador. Esto se utiliza para propósitos de optimización de motores de búsqueda y hace que las URL sean legibles.
routes.MapRoute( name: "AboutUsAspx", // Route name url: "AboutUs.aspx", // URL with parameters defaults: new { controller = "Home", action = "AboutUs", id = UrlParameter.Optional } // Parameter defaults );
Atributo de enrutamiento en MVC
Junto con la forma clásica de definición de ruta, MVC WEB API 2 y luego MVC 5 introdujeron el Attribute routing :
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); // This enables attribute routing and must go before other routes are added to the routing table. // This makes attribute routes have higher priority routes.MapMvcAttributeRoutes(); } }
https://riptutorial.com/es/home 39
Para rutas con el mismo prefijo dentro de un controlador, puede establecer un prefijo común para todos los métodos de acción dentro del controlador utilizando el atributo RoutePrefix .
[RoutePrefix("Custom")] public class CustomController : Controller { [Route("Index")] public ActionResult Index() { ... } }
RoutePrefix es opcional y define la parte de la URL que tiene el prefijo de todas las acciones del controlador.
Si tiene varias rutas, puede establecer una ruta predeterminada al capturar la acción como parámetro y luego aplicarla a todo el controlador, a menos que se defina el atributo de Route específico en ciertos métodos de acción que anulan la ruta predeterminada.
[RoutePrefix("Custom")] [Route("{action=index}")] public class CustomController : Controller { public ActionResult Index() { ... } public ActionResult Detail() { ... } }
Conceptos básicos de enrutamiento
Cuando solicite la url yourSite/Home/Index través de un navegador, el módulo de enrutamiento dirigirá la solicitud al método de acción Index de la clase HomeController . ¿Cómo sabe enviar la solicitud al método específico de esta clase específica? Ahí viene la RouteTable.
Cada aplicación tiene una tabla de ruta donde almacena el patrón de ruta e información sobre dónde dirigir la solicitud. Así que cuando creas tu aplicación mvc, hay una ruta predeterminada ya registrada en la tabla de enrutamiento. Puedes ver eso en la clase RouteConfig.cs .
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); }
Puedes ver que la entrada tiene un nombre y una plantilla. La plantilla es el patrón de ruta que
https://riptutorial.com/es/home 40
debe verificarse cuando llega una solicitud. La plantilla predeterminada tiene Home como el valor del segmento url del controlador y el Index como el valor del segmento de acción. Eso significa que, si no pasa explícitamente un nombre y una acción del controlador en su solicitud, utilizará estos valores predeterminados. Esta es la razón por la que obtiene el mismo resultado cuando accede a su yourSite/Home/Index y su yourSite
Es posible que haya notado que tenemos un parámetro llamado id como el último segmento de nuestro patrón de ruta. Pero en los valores por defecto, especificamos que es opcional. Esa es la razón por la que no tuvimos que especificar el valor de id int url que intentamos.
Ahora, vuelva al método de acción de índice en HomeController y agregue un parámetro a ese
public ActionResult Index(int id) { return View(); }
Ahora pon un punto de vista visual de estudio en este método. Ejecute su proyecto y acceda a su yourSite/Home/Index/999 en su navegador. Se alcanzará el punto de interrupción y debería poder ver que el valor 999 ahora está disponible en el parámetro id .
Creando un segundo patrón de ruta
Digamos que nos gustaría configurarlo para que se llame al mismo método de acción para un patrón de ruta diferente. Podemos hacerlo agregando una nueva definición de ruta a la tabla de rutas.
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); // New custom route definition added routes.MapRoute("MySpecificRoute", "Important/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); //Default catch all normal route definition routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); }
La nueva definición que agregué tiene un patrón Important/{id} donde id es nuevamente opcional. Eso significa que cuando solicite su yourSiteName\Important o su yourSiteName\Important\888 , se enviará a la acción del Índice de HomeController.
Orden de registro de definición de ruta
El orden de registro de ruta es importante. Siempre debe registrar los patrones de ruta específicos antes de la ruta genérica predeterminada.
Ruta de todo
https://riptutorial.com/es/home 41
Supongamos que queremos tener una ruta que permita un número ilimitado de segmentos así:
http://example.com/Products/ (ver todos los productos)•http://example.com/Products/IT•http://example.com/Products/IT/Laptops•http://example.com/Products/IT/Laptops/Ultrabook•http://example.com/Products/IT/Laptops/Ultrabook/Asus•etc.•
Tendríamos que agregar una ruta, normalmente al final de la tabla de rutas, ya que esto probablemente detectaría todas las solicitudes, de este modo:
routes.MapRoute("Final", "Route/{*segments}", new { controller = "Product", action = "View" });
En el controlador, una acción que podría manejar esto, podría ser:
public void ActionResult View(string[] segments /* <- the name of the parameter must match the name of the route parameter */) { // use the segments to obtain information about the product or category and produce data to the user // ... }
Ruta completa para habilitar el enrutamiento del lado del cliente
Es una buena práctica codificar el estado de la aplicación de página única (SPA) en url:
my-app.com/admin-spa/users/edit/id123
Esto permite guardar y compartir el estado de la aplicación. Cuando el usuario coloca la url en la barra de direcciones del navegador y los clics en el servidor deben ignorar la parte del cliente de la url solicitada. Si sirve su SPA como una vista Razor renderizada (resultado de la acción del controlador de llamada) en lugar de como un archivo html estático, puede usar una ruta de acceso directo:
public class AdminSpaController { [Route("~/admin-spa/{clienSidePart*}")] ActionResult AdminSpa() { ... } }
En este caso, el servidor solo devuelve SPA y luego se inicializa de acuerdo con la ruta. Este enfoque es más flexible, ya que no depende del módulo url-rewrite .
Atributo de enrutamiento en áreas
https://riptutorial.com/es/home 42
Para usar el enrutamiento de atributos en áreas, se requieren áreas de registro y las [RouteArea(...)] .
En RouteConfig.cs :
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapMvcAttributeRoutes(); AreaRegistration.RegisterAllAreas(); } }
En una definición de enrutamiento de atributos de controlador de área de muestra:
[RouteArea("AreaName", AreaPrefix = "AreaName")] [RoutePrefix("SampleAreaController")] public class SampleAreaController : Controller { [Route("Index")] public ActionResult Index() { return View(); } }
Para utilizar enlaces de Url.Action en Áreas:
@Url.Action("Index", "SampleAreaController", new { area = "AreaName" })
Lea Enrutamiento en línea: https://riptutorial.com/es/asp-net-mvc/topic/1534/enrutamiento
https://riptutorial.com/es/home 43
Capítulo 12: Extensiones Ajax MVC
Introducción
Esto documenta el uso de la biblioteca System.Web.Mvc.Ajax .
Citando documentos de MSDN "Cada método de extensión representa un elemento HTML. El método ActionLink representa un elemento anchor (a) que se vincula a un método de acción. El método RouteLink representa un elemento anchor (a) que se vincula a una URL, que puede resolverse a una método de acción, un archivo, una carpeta o algún otro recurso. Esta clase también contiene los métodos BeginForm y BeginRouteForm que le ayudan a crear formularios HTML que son compatibles con las funciones AJAX.
Parámetros
Opciones de AJAX Descripción
ConfirmarObtiene o establece el mensaje que se mostrará en una ventana de confirmación antes de que se envíe una solicitud.
HttpMethodObtiene o establece el método de solicitud HTTP ("Obtener" o "Publicar").
Modo de inserciónObtiene o establece el modo que especifica cómo insertar la respuesta en el elemento DOM de destino.
LoadingElementDurationObtiene o establece un valor, en milisegundos, que controla la duración de la animación al mostrar u ocultar el elemento de carga.
LoadingElementIdObtiene o establece el atributo id de un elemento HTML que se muestra mientras se carga la función Ajax.
OnBeginObtiene o establece el nombre de la función JavaScript para llamar inmediatamente antes de que se actualice la página.
OnCompleteObtiene o establece la función de JavaScript para llamar cuando se han creado instancias de datos de respuesta pero antes de que se actualice la página.
En el fracasoObtiene o establece la función de JavaScript para llamar si falla la actualización de la página.
OnSuccessObtiene o establece la función de JavaScript para llamar después de que la página se actualice correctamente.
https://riptutorial.com/es/home 44
Opciones de AJAX Descripción
UpdateTargetIdObtiene o establece el ID del elemento DOM para actualizar utilizando la respuesta del servidor.
Url Obtiene o establece la URL para realizar la solicitud.
Observaciones
El paquete Jquery.Unobtrusive-Ajax es obligatorio en el proyecto. Los archivos javascript correspondientes deben incluirse en un paquete ( jquery.unobtrusive-ajax.js o jquery.unobtrusive-ajax.min.js ). Finalmente, debe activarse también en el archivo web.config :
<appSettings> <add key="UnobtrusiveJavaScriptEnabled" value="true" /> </appSettings>
Las acciones invocadas ( SomeAction en los ejemplos) deben devolver un Json o PartialView .
Examples
Ajax Action Link
@* Renders an anchor (a) element that links to an action method. * The innerHTML of "target-element" is replaced by the result of SomeAction. *@ @Ajax.ActionLink("Update", "SomeAction", new AjaxOptions{UpdateTargetId="target-element" })
Formas de Ajax
@* Adds AJAX functions support to a form. * The innerHTML of "target-element" is replaced by the result of SomeAction. *@ @using ( Ajax.BeginForm("SomeAction", "SomeController", new AjaxOptions { UpdateTargetId="target-element", OnSuccess = "some_js_fun(context)" }) ) { <!-– my form contents --> }
Lea Extensiones Ajax MVC en línea: https://riptutorial.com/es/asp-net-mvc/topic/9007/extensiones-ajax-mvc
https://riptutorial.com/es/home 45
Capítulo 13: Filtros de accion
Examples
Un filtro de acción de registro.
public class LogActionFilter : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { Log("OnActionExecuting", filterContext.RouteData); } public override void OnActionExecuted(ActionExecutedContext filterContext) { Log("OnActionExecuted", filterContext.RouteData); } public override void OnResultExecuting(ResultExecutingContext filterContext) { Log("OnResultExecuting", filterContext.RouteData); } public override void OnResultExecuted(ResultExecutedContext filterContext) { Log("OnResultExecuted", filterContext.RouteData); } private void Log(string methodName, RouteData routeData) { var controllerName = routeData.Values["controller"]; var actionName = routeData.Values["action"]; var message = String.Format("{0} controller:{1} action:{2}", methodName, controllerName, actionName); Debug.WriteLine(message, "Action Filter Log"); } }
Filtro de acción de Control de sesión - solicitud de página y ajax
Por lo general, los procesos de autenticación y autorización se realizan mediante cookies y token compatibles en .net MVC. Pero si decide hacerlo usted mismo con Session , puede usar la lógica siguiente para las solicitudes de página y las solicitudes de ajax.
public class SessionControl : ActionFilterAttribute { public override void OnActionExecuting ( ActionExecutingContext filterContext ) { var session = filterContext.HttpContext.Session; /// user is logged in (the "loggedIn" should be set in Login action upon a successful login request) if ( session["loggedIn"] != null && (bool)session["loggedIn"] )
https://riptutorial.com/es/home 46
return; /// if the request is ajax then we return a json object if ( filterContext.HttpContext.Request.IsAjaxRequest() ) { filterContext.Result = new JsonResult { Data = "UnauthorizedAccess", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } /// otherwise we redirect the user to the login page else { var redirectTarget = new RouteValueDictionary { { "Controller", "Login" }, { "Action", "Index" } }; filterContext.Result = new RedirectToRouteResult(redirectTarget); } } public override void OnResultExecuting ( ResultExecutingContext filterContext ) { base.OnResultExecuting(filterContext); /// we set a field 'IsAjaxRequest' in ViewBag according to the actual request type filterContext.Controller.ViewBag.IsAjaxRequest = filterContext.HttpContext.Request.IsAjaxRequest(); } }
Ubicaciones de uso del filtro de acción (global, controlador, acción)
Puede colocar filtros de acción en tres niveles posibles:
Global1. Controlador2. Acción3.
Colocar un filtro global significa que se ejecutará en las solicitudes a cualquier ruta. La colocación de uno en un controlador hace que se ejecute en las solicitudes de cualquier acción en ese controlador. Colocar uno en una acción significa que se ejecuta con la acción.
Si tenemos este simple filtro de acción:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] public class CustomActionFilterAttribute : FilterAttribute, IActionFilter { private readonly string _location; public CustomActionFilterAttribute(string location) { _location = location; } public void OnActionExecuting(ActionExecutingContext filterContext) { Trace.TraceInformation("OnActionExecuting: " + _location);
https://riptutorial.com/es/home 47
} public void OnActionExecuted(ActionExecutedContext filterContext) { Trace.TraceInformation("OnActionExecuted: " + _location); } }
Podemos agregarlo a nivel global agregándolo a la colección de filtro global. Con la configuración típica del proyecto MVC de ASP.NET, esto se hace en App_Start / FilterConfig.cs.
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new CustomActionFilterAttribute("Global")); } }
También podemos agregarlo en el controlador y en el nivel de acción, como en un controlador:
[CustomActionFilter("HomeController")] public class HomeController : Controller { [CustomActionFilter("Index")] public ActionResult Index() { return View(); } }
Si ejecutamos la aplicación y miramos la ventana de resultados, veremos los siguientes mensajes:
iisexpress.exe Information: 0 : OnActionExecuting: Global iisexpress.exe Information: 0 : OnActionExecuting: HomeController iisexpress.exe Information: 0 : OnActionExecuting: Index iisexpress.exe Information: 0 : OnActionExecuted: Index iisexpress.exe Information: 0 : OnActionExecuted: HomeController iisexpress.exe Information: 0 : OnActionExecuted: Global
Como puede ver, cuando llega la solicitud, los filtros se ejecutan:
Global1. Controlador2. Acción3.
Excelentes ejemplos de filtros colocados a nivel global incluyen:
Filtros de autentificación1. Filtros de autorizacion2. Filtros de registro3.
https://riptutorial.com/es/home 48
Atributo de manejador de excepciones
Este atributo maneja todas las excepciones no manejadas en el código, (esto es principalmente para solicitudes Ajax - que tratan con JSON - pero pueden extenderse)
public class ExceptionHandlerAttribute : HandleErrorAttribute { /// <summary> /// Overriden method to handle exception /// </summary> /// <param name="filterContext"> </param> public override void OnException(ExceptionContext filterContext) { // If exeption is handled - return ( don't do anything) if (filterContext.ExceptionHandled) return; // Set the ExceptionHandled to true ( as you are handling it here) filterContext.ExceptionHandled = true; //TODO: You can Log exception to database or Log File //Set your result structure filterContext.Result = new JsonResult { Data = new { Success = false, Message = filterContext .Exception.Message, data = new {} }, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } }
Digamos que siempre tienes que enviar una respuesta JSON similar a esto:
{ Success: true, // False when Error data: {}, Message:"Success" // Error Message when Error }
Así que en lugar de manejar excepciones en las acciones del controlador, como esto:
public ActionResult PerformMyAction() { try { var myData = new { myValue = 1}; throw new Exception("Handled", new Exception("This is an Handled Exception")); return Json(new {Success = true, data = myData, Message = ""});
https://riptutorial.com/es/home 49
} catch(Exception ex) { return Json(new {Success = false, data = null, Message = ex.Message}); } }
Puedes hacerlo:
[ExceptionHandler] public ActionResult PerformMyAction() { var myData = new { myValue = 1}; throw new Exception("Unhandled", new Exception("This is an unhandled Exception")); return Json(new {Success = true, data = myData, Message = ""}); }
O puede agregar a nivel de controlador
[ExceptionHandler] public class MyTestController : Controller { public ActionResult PerformMyAction() { var myData = new { myValue = 1}; throw new Exception("Unhandled", new Exception("This is an unhandled Exception")); return Json(new {Success = true, data = myData, Message = ""}); } }
Lea Filtros de accion en línea: https://riptutorial.com/es/asp-net-mvc/topic/1450/filtros-de-accion
https://riptutorial.com/es/home 50
Capítulo 14: Html.AntiForgeryToken
Introducción
El token anti-falsificación se puede usar para ayudar a proteger su aplicación contra la falsificación de solicitudes entre sitios. Para usar esta función, llame al método AntiForgeryToken desde un formulario y agregue el atributo ValidateAntiForgeryTokenAttribute al método de acción que desea proteger.
Genera un campo de formulario oculto (token anti-falsificación) que se valida cuando se envía el formulario.
Sintaxis
@ Html.AntiForgeryToken ()•
Observaciones
Al enviar una solicitud ajax con el token CSRF ( __RequestVerificationToken ), asegúrese de que el tipo de contenido no esté establecido en application/json . Si está utilizando jQuery, automáticamente establece el tipo de contenido en application/x-www-form-urlencoded que luego es reconocido por ASP.NET MVC.
Precaución
Tenga cuidado al establecer este valor. Su uso inadecuado puede abrir vulnerabilidades de seguridad en la aplicación.
Examples
Uso básico
El método de ayuda @Html.AntiForgeryToken() protege contra ataques de falsificación de solicitudes entre sitios (o CSRF).
Se puede usar simplemente usando el ayudante Html.AntiForgeryToken() dentro de uno de sus formularios existentes y decorando su Acción de controlador correspondiente con el atributo [ValidateAntiForgeryToken] .
Maquinilla de afeitar (YourView.cshtml)
@using (Html.BeginForm("Manage", "Account")) { @Html.AntiForgeryToken()
https://riptutorial.com/es/home 51
<!-- ... --> }
O
<form> @Html.AntiForgeryToken() <!-- ... --> </form>
Controlador (YourController.cs)
El método de acción objetivo:
[ValidateAntiForgeryToken] [HttpPost] public ActionResult ActionMethod(ModelObject model) { // ... }
Deshabilitar el control heurístico de identidad
Muchas veces verá una excepción
Anti forgery token is meant for user "" but the current user is "username"
Esto se debe a que el token de Anti-falsificación también está vinculado al usuario que ha iniciado sesión actualmente. Este error aparece cuando un usuario inicia sesión pero su token sigue vinculado a ser un usuario anónimo para el sitio.
Hay algunas formas de solucionar este comportamiento, pero si prefiere no tener los tokens CSRF vinculados al estado de inicio de sesión de un usuario, puede desactivar esta función.
Coloque esta línea en su archivo Global.asax o en una lógica de inicio de aplicación similar.
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
Validando todas las publicaciones
Debido a la vulnerabilidad causada por CSRF, generalmente se considera una buena práctica verificar un AntiForgeryToken en todos los HttpPosts, a menos que haya una buena razón para no hacerlo (algún problema técnico con la publicación, hay otro mecanismo de autenticación y / o el la publicación no muta el estado como guardarlo en un db o archivo). Para asegurarse de no olvidar, puede agregar un GlobalActionFilter especial que verifique automáticamente todos los HttpPosts a menos que la acción esté decorada con un atributo especial de "ignorar".
[AttributeUsage(AttributeTargets.Class)]
https://riptutorial.com/es/home 52
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { var request = filterContext.HttpContext.Request; // Only validate POSTs if (request.HttpMethod == WebRequestMethods.Http.Post) { bool skipCheck = filterContext.ActionDescriptor.IsDefined(typeof(DontCheckForAntiForgeryTokenAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(DontCheckForAntiForgeryTokenAttribute),true); if (skipCheck) return; // Ajax POSTs and normal form posts have to be treated differently when it comes // to validating the AntiForgeryToken if (request.IsAjaxRequest()) { var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName]; var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null; AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]); } else { new ValidateAntiForgeryTokenAttribute() .OnAuthorization(filterContext); } } } } /// <summary> /// this should ONLY be used on POSTS that DO NOT MUTATE STATE /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public sealed class DontCheckForAntiForgeryTokenAttribute : Attribute { }
Para asegurarse de que se verifique en todas las solicitudes, solo agréguelo a sus filtros de acción global
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //... filters.Add(new ValidateAntiForgeryTokenOnAllPosts()); //... } }
https://riptutorial.com/es/home 53
Uso anticipado: aplique el filtro antiforgery predeterminado para cada POST
Podemos olvidar aplicar el Antiforgery attribute para cada solicitud POST por lo que deberíamos hacerlo por defecto. Esta muestra asegurará que el Antiforgery filter siempre se aplique a cada solicitud POST .
Primero crea un nuevo filtro AntiForgeryTokenFilter :
//This will add ValidateAntiForgeryToken Attribute to all HttpPost action methods public class AntiForgeryTokenFilter : IFilterProvider { public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { List<Filter> result = new List<Filter>(); string incomingVerb = controllerContext.HttpContext.Request.HttpMethod; if (String.Equals(incomingVerb, "POST", StringComparison.OrdinalIgnoreCase)) { result.Add(new Filter(new ValidateAntiForgeryTokenAttribute(), FilterScope.Global, null)); } return result; } }
Luego registre este filtro personalizado a MVC, Application_Start:
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //Cactch generic error filters.Add(new HandleErrorAttribute()); //Anti forgery token hack for every post request FilterProviders.Providers.Add(new AntiForgeryTokenFilter()); } } public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } }
Por lo tanto, ahora todas sus solicitudes POST están protegidas de forma predeterminada mediante los atributos de Antiforgery, por lo que ya no necesitamos tener el atributo
https://riptutorial.com/es/home 54
[ValidateAntiForgeryToken] en cada método POST.
Uso de AntiForgeryToken con la solicitud de Ajax de Jquery
Primero creas el formulario
@using (Html.BeginForm()) { @Html.AntiForgeryToken() }
Método de acción
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Test(FormViewModel formData) { // ... }
Guión
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script> <script> var formData = new FormData($('form')[0]); $.ajax({ method: "POST", url: "/demo/test", data: formData , success: function (data) { console.log(data); }, error: function (jqXHR, textStatus, errorThrown) { console.log(errorThrown); } }) </script>
Asegúrese de que contentType no esté configurado para nada aparte de application/x-www-form-urlencoded y si Jquery no está especificado por defecto es application/x-www-form-urlencoded
Lea Html.AntiForgeryToken en línea: https://riptutorial.com/es/asp-net-mvc/topic/1997/html-antiforgerytoken
https://riptutorial.com/es/home 55
Capítulo 15: Html.RouteLink
Parámetros
Parámetro Detalles
Texto del enlace El texto que se mostrará para el enlace.
routeName El nombre de la ruta para devolver una ruta virtual para.
Examples
Ejemplo básico usando el texto de enlace y el nombre de la ruta
Como alternativa al uso de Html.ActionLink para generar enlaces en una vista, puede usar
Html.RouteLink
Para utilizar esta función, necesita configurar una ruta, por ejemplo:
public static void RegisterRoutes(RouteCollection routes) { routes.MapRoute( "SearchResults", "{controller}/{action}", new { controller = "Search", action = "Results" }); }
Luego, en una vista, puede crear un enlace a esa ruta así:
@Html.RouteLink("Search Results", "SearchResults");
Usar RouteLink() es conveniente si termina cambiando los nombres del controlador o los nombres de los métodos de acción, ya que usar Html.ActionLink() significa tener que cambiar los parámetros del controlador y el nombre del método de acción en la llamada, para que coincidan con los nuevos nombres que tienen ha cambiado
Con RouteLink() puede cambiar los detalles de la ruta en la llamada MapRoute() , en otras palabras, en una ubicación, y no se requerirá que ningún código que haga referencia a esa ruta a través de RouteLink() cambie.
Lea Html.RouteLink en línea: https://riptutorial.com/es/asp-net-mvc/topic/6209/html-routelink
https://riptutorial.com/es/home 56
Capítulo 16: Inyección de dependencia
Observaciones
Todo el punto de la inyección de dependencia (DI) es reducir el acoplamiento de código. Imagine cualquier tipo de interacción que implique la creación de algo como en el "Ejemplo de dependencia de código duro".
Una gran parte de escribir código es la capacidad de probarlo. Cada vez que creamos una nueva dependencia, hacemos que nuestro código sea difícil de probar porque no tenemos control sobre esa dependencia.
¿Cómo probaría el código que depende de DataTime.Now por ejemplo? Siempre cambia así que no tienes referencia. Esto es cuando se inyecta un parámetro estable como su punto de partida. Puede controlarlo, puede escribir pruebas basadas en varios valores y asegurarse de que siempre obtenga el resultado correcto.
Por lo tanto, una buena opción es pasar una interfaz o una clase abstracta como un parámetro en el constructor DI.
Una interfaz representa un contrato bien definido, siempre puede confiar en los métodos para estar allí y siempre puede confiar en las firmas del método.
Una vez que empieces a usar DI se abrirán otros aspectos. Por ejemplo, incluso si pasa una interfaz en algún momento, necesitará una implementación real para realizar cualquier trabajo. Aquí es donde aparecen otros conceptos. Podemos usar IOC (Inversión de control) para resolver nuestras dependencias. Esto significa que le indicamos a nuestro código que siempre use una implementación específica para cualquier contrato. Por supuesto que hay otras formas de hacer esto. Siempre podríamos crear una instancia de cada contrato con una implementación específica y, a partir de ese momento, nuestro código puede usar esa parte:
public ILogging Logging { get; set }
En algún momento lo inicializamos.
Logging = new FileLogging();
esto siempre funcionará siempre y cuando nuestra clase cumpla con el contrato esperado:
public class FileLogging : ILogging
a partir del momento de inicialización siempre utilizamos el objeto de registro. Esto hace la vida más fácil porque si alguna vez decidimos cambiar y usar un DatabaseLogging, por ejemplo, solo tenemos que cambiar el código en un lugar y aquí es exactamente donde inicializamos la clase de registro.
https://riptutorial.com/es/home 57
¿Es DI solo bueno para la prueba? No, DI también es importante al escribir código mantenible. Permite que la separación de inquietudes sea clara.
Cuando escriba cualquier código, piense ... es comprobable, puedo escribir una prueba, es cuando se inyecta un valor DateTime en lugar de usar DateTime. Ahora tiene sentido.
Examples
Configuraciones de Ninject
Después de la instalación de un contenedor IoC (Inversión de control), se necesitan algunos ajustes para que funcione. En este caso, usaré Ninject. En el archivo NinjectWebCommon, que se encuentra en la carpeta App_Start, sustituya el método CreateKernel con:
private static IKernel CreateKernel() { // Create the kernel with the interface to concrete bindings var kernel = RegisterServices(); try { kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel); kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>(); return kernel; } catch { kernel.Dispose(); throw; } }
Y el método RegisterServices con:
private static StandardKernel RegisterServices() { Container container = new Container(); // encapsulate the interface to concrete bindings in another class or even in another layer StandardKernel kernel = container.GetServices(); return kernel; }
Cree una nueva clase para el enlace que en este caso se llama Container:
public class Container { public StandardKernel GetServices() { // It is good practice to create a derived class of NinjectModule to organize the binding by concerns. In this case one for the repository, one for service and one for app service bindings return new StandardKernel(new NinjectRepositoryModule(), new NinjectServiceModule(),
https://riptutorial.com/es/home 58
new NinjectAppServiceModule()); } }
Finalmente, en cada clase de NinjectModule derivada modifique los enlaces que sobrecargan el método de carga como:
public class NinjectRepositoryModule: NinjectModule { public override void Load() { // When we need a generic IRepositoryBase<> to bind to a generic RepositoryBase<> // The typeof keyword is used because the target method is generic Bind(typeof (IRepositoryBase<>)).To(typeof (RepositoryBase<>)); // When we need a IUnitOfWorkbind to UnitOfWork concrete class that is a singleton Bind<IUnitOfWork>().To<UnitOfWork>().InSingletonScope(); } }
Otro ejemplo de NinjectModule derivado:
public class NinjectServiceModule :NinjectModule { public override void Load() { // When we need a IBenefitService to BenefitService concrete class Bind<IBenefitService>().To<BenefitService>(); // When we need a ICategoryService to CategoryService concrete class Bind<ICategoryService>().To<CategoryService>(); // When we need a IConditionService to ConditionService concrete class Bind<IConditionService>().To<ConditionService>(); } }
Utilización de las interfaces.
En la clase concreta que necesita el servicio, use la interfaz para acceder al servicio en lugar de su implementación como:
public class BenefitAppService { private readonly IBenefitService _service; public BenefitAppService(IBenefitService service) { _service = service; } public void Update(Benefit benefit) { if (benefit == null) return _service.Update(benefit); _service.Complete(); }
https://riptutorial.com/es/home 59
}
Ahora, si necesita algo en la clase concreta, no interferirá en el código anterior. Puede cambiar la implementación del servicio por otra diferencia completamente, y siempre que satisfaga la interfaz, estará listo. También hace que sea muy fácil probarlo.
Inyección de dependencia del constructor
La Inyección de dependencia del constructor requiere parámetros en el constructor para inyectar dependencias. Así que tienes que pasar los valores cuando creas un nuevo objeto.
public class Example { private readonly ILogging _logging; public Example(ILogging logging) { this._logging = logging; } }
Dependencia codificada
public class Example { private FileLogging _logging; public Example() { this._logging = new FileLogging(); } }
parámetro DI
public DateTime SomeCalculation() { return DateTime.Now.AddDays(3); }
vs
public DateTime SomeCalculation(DateTime inputDate) { return inputDate.AddDays(3); }
Inyección De la Dependencia De Ninject
El resolvedor de dependencias se utiliza para evitar clases estrechamente acopladas, mejorar la flexibilidad y facilitar las pruebas. Puede crear su propio inyector de dependencia (no
https://riptutorial.com/es/home 60
recomendado) o usar uno de los inyectores de dependencia bien escritos y probados. En este ejemplo voy a usar Ninject .
Paso uno: Crear resolución de dependencias.
En primer lugar, descargue Ninject desde NuGet. Cree una carpeta llamada Infraestructura y agregue una clase llamada NinjectDependencyResolver :
using Ninject; using System; using System.Collections.Generic; using System.Web.Mvc; public class NinjectDependencyResolver : IDependencyResolver { private IKernel kernel; public NinjectDependencyResolver() { // Initialize kernel and add bindings kernel = new StandardKernel(); AddBindings(); } public object GetService(Type serviceType) { return kernel.TryGet(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { return kernel.GetAll(serviceType); } private void AddBindings() { // Bindings added here } }
El MVC Framework llamará a los métodos GetService y GetServices cuando necesite un aviso de una clase para atender una solicitud entrante.
Paso dos: Registrar resolución de dependencias.
Ahora tenemos nuestro sistema de resolución de dependencias personalizado y debemos registrarlo para que el marco MVC use nuestro sistema de resolución de dependencias. Registre el resolvedor de dependencias en el archivo Global.asax.cs :
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); DependencyResolver.SetResolver(new NinjectDependencyResolver()); // .....
https://riptutorial.com/es/home 61
}
Paso tres: Añadir los enlaces.
Imagina que tenemos la siguiente interfaz e implementación:
public interface ICustomCache { string Info { get; } } public class CustomCache : ICustomCache { public string Info { get { return "Hello from CustomCache."; } } }
Si queremos usar CustomCache en nuestro controlador sin acoplarlo estrechamente con CustomCache, entonces debemos vincular ICustomCache a CustomCache e inyectarlo usando Ninject. Lo primero es lo primero, vincule ICustomCache a CustomCache agregando el siguiente código al método AddBindings () de NinjectDependencyResolver :
private void AddBindings() { // Bindings added here kernel.Bind<ICustomCache>().To<CustomCache>(); }
Luego prepare su controlador para inyección como se muestra a continuación:
public class HomeController : Controller { private ICustomCache CustomCache { get; set; } public HomeController(ICustomCache customCacheParam) { if (customCacheParam == null) throw new ArgumentNullException(nameof(customCacheParam)); CustomCache = customCacheParam; } public ActionResult Index() { // cacheInfo: "Hello from CustomCache." string cacheInfo = CustomCache.Info; return View(); } }
https://riptutorial.com/es/home 62
Este es un ejemplo de inyección costructora y es una forma de inyección de dependencia . Como puede ver, nuestro controlador de inicio no depende de la clase CustomCache itslef. Si queremos usar otra implementación de ICustomCache en nuestra aplicación, lo único que debemos cambiar es vincular a ICustomCache con otra implementación y ese es el único paso que debemos tomar. ¿Qué ha pasado aquí es, MVC marco pidió a nuestro solucionador de dependencias registrado para crear una instancia de la clase HomeController a través del método GetService. El método GetService le pide al kernel de Ninject que cree el objeto solicitado y el kernel de Ninject examina el tipo en su término y descubre que el constructor de HomeController vuelve a poner un ICustomCache y el enlace ya se ha agregado para el ICustomCache . Ninject crea una instancia de clase enlazada, la usa para crear HomeController y la devuelve MVC Framework.
Cadenas de dependencia.
Cuando Ninject intenta crear un tipo, examina otras dependencias entre el tipo y otros tipos y, si existe, Ninject intenta crearlos también. Por ejemplo, si nuestra clase CustomCache requiere ICacheKeyProvider y si se agrega la combinación de ICacheKeyProvider, Ninject puede proporcionarlo para nuestra clase.
Interfaz ICacheKeyProvider e implementación de SimpleCacheKeyProvider :
public interface ICacheKeyProvider { string GenerateKey(Type type); } public class SimpleCacheKeyProvider : ICacheKeyProvider { public string GenerateKey(Type type) { if (type == null) throw new ArgumentNullException(nameof(type)); return string.Format("{0}CacheKey", type.Name); } }
Clase modificada de CustomCache
public class CustomCache : ICustomCache { private ICacheKeyProvider CacheKeyProvider { get; set; } public CustomCache(ICacheKeyProvider keyProviderParam) { if (keyProviderParam == null) throw new ArgumentNullException(nameof(keyProviderParam)); CacheKeyProvider = keyProviderParam; } ........... }
https://riptutorial.com/es/home 63
Añadir enlace para ICacheKeyProvider :
private void AddBindings() { // Bindings added here kernel.Bind<ICustomCache>().To<CustomCache>(); kernel.Bind<ICacheKeyProvider>().To<SimpleCacheKeyProvider>(); }
Ahora, cuando navegamos a HomeController, Ninject crea la instancia de SimpleCacheKeyProvider la usa para crear CustomCache y usa la instancia de CustomCache para crear HomeController .
Ninject tiene varias características excelentes, como la inyección de dependencia encadenada, y debes examinarlas si quieres usar Ninject.
Lea Inyección de dependencia en línea: https://riptutorial.com/es/asp-net-mvc/topic/6392/inyeccion-de-dependencia
https://riptutorial.com/es/home 64
Capítulo 17: jQuery Ajax Call Con Asp MVC
Examples
Publicar objetos JavaScript con jQuery Ajax Call
Ajax llama, solicita y recupera datos para brindar al usuario la sensación de una mejor experiencia de interfaz de usuario interactiva. Este artículo le mostrará cómo usar jQuery y enviar datos a través de llamadas Ajax. Para este ejemplo, vamos a enviar el siguiente objeto JavaScript a nuestro servidor.
var post = { title: " Posting JavaScript objects with jQuery Ajax Call", content: " Posting JavaScript objects with jQuery Ajax Call", tags: ["asp mvc", "jquery"] };
El lado del servidor
El modelo del lado del servidor correspondiente al objeto javascript.
public class Post { public string Title { get; set; } public string Content { get; set; } public string[] Tags { get; set; } }
Todo lo que necesitamos hacer es crear un método de controlador MVC ASP.NET estándar que tome un solo parámetro del tipo Persona, como tal.
public class PostController : BaseController { public bool Create(Post model) { //Do somthing } }
El lado del cliente
Para enviar objetos de JavaScript, necesitamos usar el método JSON.stringify () para enviar el objeto a la opción de datos.
$.ajax({ url: '@Url.Action("create", "Post")', type: "POST", contentType: "application/json", data: JSON.stringify({ model: post }) }).done(function(result){
https://riptutorial.com/es/home 65
//do something });
Lea jQuery Ajax Call Con Asp MVC en línea: https://riptutorial.com/es/asp-net-mvc/topic/9734/jquery-ajax-call-con-asp-mvc
https://riptutorial.com/es/home 66
Capítulo 18: Manejo de errores Http
Introducción
Cada sitio web necesita para manejar los errores. Puede permitir que sus usuarios vean las páginas de error 404 o 500 que IIS distribuye o, utilizando el Web.Config y un simple Controlador, puede capturar estos errores y entregar sus propias páginas de error personalizadas.
Examples
Configuración básica
Este ejemplo cubrirá la creación de una página de error personalizada para 404 Página no encontrada y 500 Error de servidor. Puede extender este código para capturar cualquier código de error que necesite.
Web.Config
Si está utilizando IIS7 y superior, ignore el nodo <CustomError.. y use <httpErrors... lugar.
Agregue lo siguiente en el nodo system.webServer :
<httpErrors errorMode="Custom" existingResponse="Replace"> <remove statusCode="404" /> <remove statusCode="500" /> <error statusCode="404" path="/error/notfound" responseMode="ExecuteURL" /> <error statusCode="500" path="/error/servererror" responseMode="ExecuteURL" /> </httpErrors>
Esto le indica al sitio que dirija cualquier error 404 a ~/error/notfound y cualquier error 500 a ~/error/servererror . También conservará la URL solicitada (piense en transferir en lugar de redirigir ) para que el usuario nunca vea la URL de la página ~/error/...
A continuación, necesita un nuevo controlador de Error así que ...
public class ErrorController : Controller { public ActionResult servererror() { Response.TrySkipIisCustomErrors = true; Response.StatusCode = (int)HttpStatusCode.InternalServerError; return View(); } public ActionResult notfound() { Response.TrySkipIisCustomErrors = true; Response.StatusCode = (int)HttpStatusCode.NotFound; return View(); }
https://riptutorial.com/es/home 67
}
La clave a tener en cuenta aquí es el Response.TrySkipIisCustomErrors = true; . Esto evitará IIS y forzará su página de error.
Por último, cree las NotFound correspondientes de NotFound y NotFound y ServerError estilo para que todo esté bien y sin problemas con el diseño de tu sitio.
Hola presto - páginas de error personalizadas.
Lea Manejo de errores Http en línea: https://riptutorial.com/es/asp-net-mvc/topic/9137/manejo-de-errores-http
https://riptutorial.com/es/home 68
Capítulo 19: Maquinilla de afeitar
Introducción
¿Qué es Razor?
Razor es una sintaxis de marcado que le permite incrustar código basado en servidor (Visual Basic y C #) en páginas web.
El código basado en servidor puede crear contenido web dinámico sobre la marcha, mientras que una página web se escribe en el navegador. Cuando se llama a una página web, el servidor ejecuta el código basado en el servidor dentro de la página antes de devolver la página al navegador. Al ejecutarse en el servidor, el código puede realizar tareas complejas, como acceder a bases de datos.
Sintaxis
@ {...}•@nombre de la variable•@(nombre de la variable)•@para(...){ }•@ (Expresión explícita)•@ * comentarios * @•
Observaciones
ASP.NET Razor incluye motores de visualización para C # y VB.
El motor de visualización C # procesa archivos con una extensión .cshtml , mientras que el motor de visualización VB funciona con archivos .vbhtml .
Examples
Añadir comentarios
Razor tiene su propia sintaxis de comentario que comienza con @* y termina con *@ .
Comentario en línea:
<h1>Comments can be @*hi!*@ inline</h1>
Comentario multilínea:
@* Comments can spread over multiple
https://riptutorial.com/es/home 69
lines *@
Comentario HTML
También puede usar la sintaxis de comentario HTML normal comenzando con <!-- y terminando con --> en las vistas de Razor. Pero a diferencia de otros comentarios, el código Razor dentro de un comentario HTML todavía se ejecuta normalmente.
@{ var hello = "Hello World!"; } <!-- @hello -->
El ejemplo anterior produce el siguiente resultado HTML:
<!-- Hello World! -->
Comentarios dentro de un bloque de código:
@{ // This is a comment var Input = "test"; }
Mostrar HTML dentro del bloque de código Razor
Mientras se encuentre dentro de un bloque de código de Razor, el navegador solo reconocerá el código HTML si se escapa el código.
Use @: para una sola línea:
@foreach(int number in Model.Numbers) { @:<h1>Hello, I am a header!</h1> }
Utilice <text> ... </text> para multilínea:
@{ var number = 1; <text> Hello, I am text <br / > Hello, I am more text! </text> }
Tenga en cuenta que Razor, cuando está dentro de un bloque de código, entenderá las etiquetas HTML. Por lo tanto, agregar la etiqueta de text alrededor de las etiquetas HTML es innecesario (aunque sigue siendo correcto), como por ejemplo:
https://riptutorial.com/es/home 70
@{ var number = 1; <text> <div> Hello, I am text <br / > Hello, I am more text! </div> </text> }
Sintaxis basica
El código Razor se puede insertar en cualquier lugar dentro del código HTML. Los bloques de código de la maquinilla de afeitar están incluidos en @{ ... } . Las variables y funciones en línea comienzan con @ . El código dentro de los soportes de Razor sigue las reglas normales de C # o VB.
Declaración de una sola línea:
@{ var firstNumber = 1; }
Bloque de código multilínea:
@{ var secondNumber = 2; var total = firstNumber + secondNumber; }
Usando una variable en línea:
<h1>The total count is @total</h1>
Usando una variable en línea explícitamente :
<h2>Item@(item.Id)</h2>
Para este ejemplo en particular, no podremos usar la sintaxis implícita porque [email protected] parece un correo electrónico y Razor lo procesará como tal.
Adjuntar código dentro de las declaraciones de flujo de control:
<h1>Start with some HTML code</h1> @for (int i = 0; i < total; i++){ Console.Write(i); } <p>Mix in some HTML code for fun!</p> <p>Add a second paragraph.</p> @if (total > 3)
https://riptutorial.com/es/home 71
{ Console.Write("The total is greater than 3"); } else { Console.Write("The total is less than 3"); }
Esta misma sintaxis se usaría para todas las declaraciones como for , foreach , while , if , switch , etc.
Agregando código dentro del código:
@if (total > 3) { if(total == 10) { Console.Write("The total is 10") } }
Tenga en cuenta que no necesita escribir la @ en el segundo if . Después del código, simplemente puede escribir otro código detrás del código existente.
Si desea agregar código después de un elemento HTML , debe escribir a @ .
Escapando a @ personaje
En muchos casos, el analizador Razor es lo suficientemente inteligente como para determinar cuándo el signo @ debe utilizarse como parte del código, en lugar de ser parte de algo como una dirección de correo electrónico. En el siguiente ejemplo, no es necesario escapar del signo @ :
<p>Reach out to us at [email protected]</p>
Sin embargo, en algunos casos, el uso del signo @ es más ambiguo, y debe evitarse explícitamente con @@ , como se muestra en el siguiente ejemplo:
<p>Join us @@ Stack Overflow!</p>
Alternativamente, podemos usar un carácter @ codificado en HTML
<p>Join us @ Stack Overflow!</p>
Crear clases y métodos en línea usando funciones @
El uso de la palabra clave Razor @functions brinda la capacidad de introducir clases y métodos para el uso en línea dentro de un archivo Razor:
@functions {
https://riptutorial.com/es/home 72
string GetCssClass(Status status) { switch (status) { case Status.Success: return "alert-success"; case Status.Info: return "alert-info"; case Status.Warning: return "alert-warning"; case Status.Danger: default: return "alert-danger"; } } } <label class="alert @GetCssClass(status)"></label>
Lo mismo se puede hacer para las clases:
@functions { class Helpers { //implementation } }
Agregando un atributo personalizado con - (guión) en el nombre
Si necesita agregar un atributo a través de la maquinilla de afeitar que tiene un - (guión) en el nombre, simplemente no puede hacer
@Html.DropDownListFor(m => m.Id, Model.Values, new { @data-placeholder = "whatever" })
no compilará Los atributos de data- * son válidos y comunes en html5 para agregar valores extra a los elementos.
Sin embargo lo siguiente funcionará
@Html.DropDownListFor(m => m.Id, Model.Values, new { @data_placeholder = "whatever" })
ya que "_" se reemplaza con "-" cuando se procesa.
Esto funciona bien ya que los guiones bajos no son aceptables en los nombres de atributos en html.
Plantillas de editor
Las plantillas de editor son una buena manera de reutilizar el código Razor. Puede definir plantillas de editor como vistas parciales de Razor y luego usarlas en otras vistas.
https://riptutorial.com/es/home 73
Las plantillas de editor generalmente existen en la carpeta Views/Shared/EditorTemplates/ , aunque también se pueden guardar en la carpeta Views/ControllerName/EditorTemplates/ . El nombre de la vista suele ser el nombre del objeto para el que desea utilizar la plantilla, como <type>.cshtml .
Aquí hay una plantilla de editor simple para DateTime:
@model DateTime <div> <span> @Html.TextBox("", Model.ToShortDateString(), new { data_date_picker="true" }) </span> </div>
Guarde el archivo como Views / Shared / EditorTemplate / DateTime.cshtml .
Luego, use EditorFor para llamar a este código de plantilla en otra vista:
@Html.EditorFor(m => m.CreatedDate)
También hay un atributo UIHint para especificar el nombre del archivo:
public class UiHintExampleClass { [UIHint("PhoneNumber")] public string Phone { get; set; } }
Defina esta plantilla de número de teléfono en Views / Shared / EditorTemplates / PhoneNumber.cshtml .
Las plantillas de editor también se pueden definir para tipos personalizados.
Aquí hay un tipo personalizado llamado SubModel :
public class SubModel { public Guid Id { get; set;} public string FirstName { get; set; } public string LastName { get; set; } } public class Model { public Guid Id { get; set; } public DateTime Created {get; set; } public SubModel SubModel{get; set; } }
Este es el EditorTemplate para SubModel:
https://riptutorial.com/es/home 74
@model SubModel <div class="form-group"> @Html.LabelFor(m => m.FirstName) @Html.TextBoxFor(m => m.FirstName) </div> <div class="form-group"> @Html.LabelFor(m => m.LastName) @Html.TextBoxFor(m => m.LastName) </div>
Ahora, la vista para el modelo simplemente se convierte en:
@model Model @Html.EditorFor(m => m.CreatedDate) @Html.EditorFor(m => m.SubModel, new { @Prefix = "New"}) @* the second argument is how you can pass viewdata to your editor template*@
Pase el contenido de Razor a un @helper
Envía una parte de Razor a un @helper, por ejemplo, un div HTML.
@helper WrapInBox(Func<Object, HelperResult> content) { <div class="box">@content(null) </div> } //call @WrapInBox(@<div> I'm a inner div </div>)
Compartir @helpers a través de vistas
@Ayudantes podrían ser compartidos entre vistas.
Deben ser creados en la carpeta App_Code
@helper CreatePrimaryBootstrapButton(string label) { <button type="button" class="btn btn-primary">@label</button> } //call @MenuHelpers.CreatePrimaryBootstrapButton("my button")
Los globales @Url y @Html no están disponibles de forma predeterminada en @Helper definido en App_code. Puede agregarlos de la siguiente manera (para cada .cshtml en su carpeta App_code)
https://riptutorial.com/es/home 75
@* Make @Html and @Url available *@ @functions { private new static HtmlHelper<object> Html { get { return ((WebViewPage)CurrentPage).Html; } } private static UrlHelper Url { get { return ((WebViewPage)CurrentPage).Url; } } }
Lea Maquinilla de afeitar en línea: https://riptutorial.com/es/asp-net-mvc/topic/5266/maquinilla-de-afeitar
https://riptutorial.com/es/home 76
Capítulo 20: Modelo de enlace
Introducción
El enlace de modelo es el proceso de tomar parámetros HTTP, normalmente en la Cadena de consulta de una solicitud GET, o dentro del cuerpo POST, y aplicarlo en un objeto que luego puede validarse y consumirse de una manera orientada a objetos sin la necesidad de acciones del Controlador tener un conocimiento íntimo de cómo recuperar los parámetros HTTP.
En otras palabras, el enlace de modelo es lo que permite que las acciones, en MVC, tengan cualquiera de los parámetros, ya sea un tipo de valor o un objeto.
Observaciones
Para intentar crear una instancia en la acción, el proceso del modelo de enlace buscará datos en varios lugares:
Datos del formulario•Datos de ruta•Cadena de consulta•Archivos personalizados (cookies, por ejemplo)•
Examples
Enlace de valor de ruta
Dado algún enrutamiento predeterminado como {controller=Home}/{action=Index}/{id?} Si tiene la url https://stackoverflow.com/questions/1558902
Esto iría al QuestionsController y el valor 1558902 se asignaría a un parámetro id de una acción de índice, es decir,
public ActionResult Index(int? id){ //id would be bound to id of the route }
Enlace de cadena de consulta
Para ampliar la vinculación de ruta, diga que tiene una URL como https://stackoverflow.com/questions/1558902?sort=desc
y enrutamiento como {controller=Home}/{action=Index}/{id?}
public ActionResult Index(int? id, string sort){ //sort would bind to the value in the query string, i.e. "desc" }
https://riptutorial.com/es/home 77
Atadura a objetos
A menudo, estarías trabajando con clases de viewmodel en asp.net-mvc y querrías unirte a las propiedades en estas. Esto funciona de manera similar a la asignación a parámetros individuales.
Digamos que tienes un modelo de vista simple llamado PostViewModel como este
public class PostViewModel{ public int Id {get;set;} public int SnappyTitle {get;set;} }
Luego, publicó los valores de Id y SnappyTitle desde un formulario en la solicitud http y luego se mapearían directamente en ese modelo si el modelo en sí fuera el parámetro de acción, por ejemplo
public ActionResult UpdatePost(PostViewModel viewModel){ //viewModel.Id would have our posted value }
Vale la pena señalar que el enlace no distingue entre mayúsculas y minúsculas para los nombres de parámetros y propiedades. También emitirá valores cuando sea posible. Estoy dejando más casos de borde para ejemplos específicos
Ajax vinculante
Estos son valores de formulario que van en la solicitud HTTP usando el método POST. (incluidas las solicitudes POST de jQuery).
Digamos que hiciste un post de ajax como
$.ajax({ type: 'POST', url: window.updatePost, data: { id: 21, title: 'snappy title' }, //kept short for clarity });
Aquí los dos valores en json, id y title, estarían vinculados a la acción correspondiente, por ejemplo,
public JsonResult UpdatePost(int id, string title) { ... }
Generic, enlace basado en modelo de sesión
A veces necesitamos preservar todo el modelo y transferirlo a través de acciones o incluso controladores. Almacenamiento de modelo en la sesión buena solución para este tipo de
https://riptutorial.com/es/home 78
requisitos. Si combinamos esto con las poderosas características de unión de modelos de MVC, obtendremos una forma elegante de hacerlo. Podemos crear un enlace de modelo basado en sesión genérica en tres sencillos pasos:
Paso uno: Crear carpeta de modelos
Crear un cuaderno de modelo en sí. Personalmente creé la clase SessionDataModelBinder en la carpeta / Infrastructure / ModelBinders .
using System; using System.Web.Mvc; public class SessionDataModelBinder<TModel> : IModelBinder where TModel : class { private string SessionKey { get; set; } public SessionDataModelBinder(string sessionKey) { if (string.IsNullOrEmpty(sessionKey)) throw new ArgumentNullException(nameof(sessionKey)); SessionKey = sessionKey; } public object BindModel( ControllerContext controllerContext, ModelBindingContext bindingContext) { // Get model from session TModel model = controllerContext .HttpContext .Session[SessionKey] as TModel; // Create model if it wasn't found from session and store it if (model == null) { model = Activator.CreateInstance<TModel>(); controllerContext.HttpContext.Session[SessionKey] = model; } // Return the model return model; } }
Paso dos: registrar carpeta
Si tenemos modelo como abajo:
public class ReportInfo { public int ReportId { get; set; } public ReportTypes TypeId { get; set; } } public enum ReportTypes { NotSpecified,
https://riptutorial.com/es/home 79
Monthly, Yearly }
Podemos registrar el cuaderno de modelos basado en sesión para este modelo en Global.asax en el método Application_Start :
protected void Application_Start() { ......... // Model binders. // Remember to specy unique SessionKey ModelBinders.Binders.Add(typeof(ReportInfo), new SessionDataModelBinder<ReportInfo>("ReportInfo")); }
Paso tres: ¡úsalo!
Ahora podemos beneficiarnos de este modelo de carpeta simplemente agregando un parámetro a nuestras acciones :
public class HomeController : Controller { public ActionResult Index(ReportInfo reportInfo) { // Simply set properties reportInfo.TypeId = ReportTypes.Monthly; return View(); } public ActionResult About(ReportInfo reportInfo) { // reportInfo.TypeId is Monthly now because we set // it previously in Index action. ReportTypes currentReportType = reportInfo.TypeId; return View(); } }
Prevenir el enlace en PostModel
Considerando un modelo (post):
public class User { public string FirstName { get; set; } public bool IsAdmin { get; set; } }
Con una vista así:
@using (Html.BeginForm()) {
https://riptutorial.com/es/home 80
@Html.EditorFor(model => model.FirstName) <input type="submit" value="Save" /> }
Para evitar que un usuario malintencionado asigne IsAdmin, puede usar el atributo Bind en la acción:
[HttpPost] public ViewResult Edit([Bind(Exclude = "IsAdmin")] User user) { // ... }
Subir archivo
Modelo:
public class SampleViewModel { public HttpPostedFileBase file {get;set;} }
Ver:
@model HelloWorldMvcApp.SampleViewModel @using (Html.BeginForm("Index","Home",FormMethod.Post, new { enctype = "multipart/form-data" })) { <div class="form-group"> @Html.TextBoxFor(model => model.file, new {@class="form-control", type="file"}) @Html.ValidationMessageFor(model => model.file) </div> <button type="submit" class="btn btn-success submit">Upload</button> }
Acción:
[HttpPost] public ActionResult Index(SampleViewModel model) { if (model.file.ContentLength > 0) { string fileName = Path.GetFileName(model.file.FileName); string fileLocation = "~/App_Data/uploads/"+ fileName; model.file.SaveAs(Server.MapPath(fileLocation)); } return View(model); }
Validación de campos de fecha manualmente con formatos dinámicos
https://riptutorial.com/es/home 81
utilizando el cuaderno de modelos
Si diferentes usuarios necesitan un formato de fecha y hora diferente, es posible que deba analizar su cadena de fecha entrante a la fecha real de acuerdo con el formato. En este caso este fragmento puede ayudarte.
public class DateTimeBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); DateTime date; var displayFormat = Session["DateTimeFormat"]; if (value.AttemptedValue != "") { if (DateTime.TryParseExact(value.AttemptedValue, displayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out date)) { return date; } else { bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Invalid date format"); } } } return base.BindModel(controllerContext, bindingContext); }
Lea Modelo de enlace en línea: https://riptutorial.com/es/asp-net-mvc/topic/1258/modelo-de-enlace
https://riptutorial.com/es/home 82
Capítulo 21: Modelo de validación
Examples
Validar modelo en ActionResult
[HttpPost] public ActionResult ContactUs(ContactUsModel contactObject) { // This line checks to see if the Model is Valid by verifying each Property in the Model meets the data validation rules if(ModelState.IsValid) { } return View(contactObject); }
La clase modelo
public class ContactUsModel { [Required] public string Name { get; set; } [Required] [EmailAddress] // The value must be a valid email address public string Email { get; set; } [Required] [StringLength(500)] // Maximum length of message is 500 characters public string Message { get; set; } }
Eliminar un objeto de la validación
Digamos que tienes el siguiente modelo:
public class foo { [Required] public string Email { get; set; } [Required] public string Password { get; set; } [Required] public string FullName { get; set; } }
Pero desea excluir FullName de la validación del modelo porque está utilizando el modelo también en un lugar donde FullName no está completo, puede hacerlo de la siguiente manera:
ModelState.Remove("FullName");
https://riptutorial.com/es/home 83
Mensajes de error personalizados
Si desea proporcionar mensajes de error personalizados, lo haría así:
public class LoginViewModel { [Required(ErrorMessage = "Please specify an Email Address")] [EmailAddress(ErrorMessage = "Please specify a valid Email Address")] public string Email { get; set; } [Required(ErrorMessage = "Type in your password")] public string Password { get; set; } }
Cuando sus mensajes de error están en un archivo de recursos (.resx), debe especificar el tipo de recurso y el nombre del recurso:
public class LoginViewModel { [Required(ErrorMessageResourceType = typeof(ErrorResources), ErrorMessageResourceName = "LoginViewModel_RequiredEmail")] [EmailAddress(ErrorMessageResourceType = typeof(ErrorResources), ErrorMessageResourceName = "LoginViewModel_ValidEmail")] public string Email { get; set; } [Required(ErrorMessageResourceType = typeof(ErrorResources), ErrorMessageResourceName = "LoginViewModel_RequiredPassword")] public string Password { get; set; } }
Creando mensajes de error personalizados en el modelo y en el controlador
Digamos que tienes la siguiente clase:
public class PersonInfo { public int ID { get; set; } [Display(Name = "First Name")] [Required(ErrorMessage = "Please enter your first name!")] public string FirstName{ get; set; } [Display(Name = "Last Name")] [Required(ErrorMessage = "Please enter your last name!")] public string LastName{ get; set; } [Display(Name = "Age")] [Required(ErrorMessage = "Please enter your Email Address!")] [EmailAddress(ErrorMessage = "Invalid Email Address")] public string EmailAddress { get; set; } }
Estos mensajes de error personalizados aparecerán si su ModelState.IsValid devuelve falso.
Pero tanto usted como yo sabemos que solo puede haber 1 dirección de correo electrónico por
https://riptutorial.com/es/home 84
persona, o bien enviará correos electrónicos a personas potencialmente equivocadas y / o varias personas. Aquí es donde entra en juego el control del controlador. Así que asumamos que las personas están creando cuentas para que las guarde a través de Crear acción.
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Create([Bind(Include = "ID, FirstName, LastName, EmailAddress")] PersonInfo newPerson) { if(ModelState.IsValid) // this is where the custom error messages on your model will display if return false { if(database.People.Any(x => x.EmailAddress == newPerson.EmailAddress)) // checking if the email address that the new person is entering already exists.. if so show this error message { ModelState.AddModelError("EmailAddress", "This email address already exists! Please enter a new email address!"); return View(newPerson); } db.Person.Add(newPerson); db.SaveChanges(): return RedirectToAction("Index"); } return View(newPerson); }
Espero que esto sea capaz de ayudar a alguien!
Validación de modelos en JQuery.
En los casos en que necesite asegurar la validación del modelo utilizando Jquery, se puede usar la función .valid ().
Los campos de la clase modelo.
[Required] [Display(Name = "Number of Hospitals")] public int Hospitals{ get; set; } [Required] [Display(Name = "Number of Beds")] public int Beds { get; set; }
El código de vista
@using (Html.BeginForm(new {id = "form1", @class = "form-horizontal" })) { <div class="divPanel"> <div class="row"> <div class="col-md-3"> @Html.LabelFor(m => m.Hospitals) @Html.TextBoxFor(m => m.Hospitals, new { @class = "form-control", @type =
https://riptutorial.com/es/home 85
"number"}) @Html.ValidationMessageFor(m => m.Hospitals) </div> <div class="col-md-3"> @Html.LabelFor(m => m.Beds) @Html.TextBoxFor(m => m.Beds, new { @class = "form-control", @type = "number"}) @Html.ValidationMessageFor(m => m.Beds) </div> <div class="col-md-3"> <button type=button class="btn btn-primary" id="btnCalculateBeds"> Calculate Score</button> </div> </div> </div> }
El script para la verificación de validación.
$('#btnCalculateBeds').on('click', function (evt) { evt.preventDefault(); if ($('#form1').valid()) { //Do Something. } }
Asegúrese de que los archivos jquery.validate y jquery.validate.unobtrusive estén presentes en la solución.
Lea Modelo de validación en línea: https://riptutorial.com/es/asp-net-mvc/topic/2683/modelo-de-validacion
https://riptutorial.com/es/home 86
Capítulo 22: MVC vs Formularios Web
Introducción
Antes de saltar a ASP. Para desarrollar su aplicación web con NET MVC, debe considerar las ventajas y desventajas del marco y debe saber que existe otro marco web creado y mantenido por Microsoft que es ASP .NET Web Forms.
El que debe elegir es una cuestión de conocimiento de ambas tecnologías.
Sintaxis
El motor de vista ASPX utiliza "<% =%>" o "<%:%>" para representar el contenido del lado del servidor.
•
El Razor View Engine usa @ para representar el contenido del lado del servidor.•
Observaciones
https://www.asp.net/web-forms
https://www.asp.net/mvc
Examples
Ventajas de los formularios web ASP .NET
Controles previos a la compilación para manejar cuadrículas, entradas, gráficos, árboles, etc.
•
Admite un modelo de evento que conserva el estado a través de HTTP, lo que beneficia el desarrollo de aplicaciones web de línea de negocio. La aplicación basada en Web Forms proporciona docenas de eventos que son compatibles con cientos de controles de servidor.
•
Utiliza un patrón de controlador de página que agrega funcionalidad a páginas individuales. Para obtener más información, consulte Controlador de página en el sitio web de MSDN.
•
Utiliza el estado de vista o los formularios basados en servidor, lo que puede facilitar la administración de la información de estado.
•
Funciona bien para pequeños equipos de desarrolladores y diseñadores web que desean aprovechar la gran cantidad de componentes disponibles para el rápido desarrollo de aplicaciones.
•
En general, es menos complejo para el desarrollo de aplicaciones, porque los componentes •
https://riptutorial.com/es/home 87
(la clase de página, los controles, etc.) están estrechamente integrados y generalmente requieren menos código que el modelo MVC.
Modelo de desarrollo fácil para aquellos desarrolladores que vienen del desarrollo de WindowsForm.
•
¿Qué es Web Forms?
Ventajas de una aplicación web basada en MVC
Facilita la administración de la complejidad al dividir una aplicación en el modelo, la vista y el controlador (Separación de inquietudes).
•
No utiliza el estado de vista ni los formularios basados en servidor. Esto hace que el marco MVC sea ideal para los desarrolladores que desean un control total sobre el comportamiento de una aplicación.
•
Utiliza un patrón de controlador frontal que procesa las solicitudes de aplicaciones web a través de un solo controlador. Esto le permite diseñar una aplicación que admita una infraestructura de enrutamiento enriquecida. Para obtener más información, consulte Front Controller en el sitio web de MSDN.
•
Proporciona un mejor soporte para el desarrollo guiado por pruebas (TDD).•
Funciona bien para aplicaciones web que son compatibles con grandes equipos de desarrolladores y diseñadores web que necesitan un alto grado de control sobre el comportamiento de la aplicación.
•
¿Qué es Web Forms?
Desventajas
Formularios Web:
Ciclo de vida de la página compleja: cada vez que se realiza una solicitud al servidor, existen al menos 5 métodos para ejecutar antes del controlador de eventos.
•
Es difícil trabajar con marcos del lado del cliente como JQuery o Angular.•Difícil trabajar con Javascript asíncrono y XML (AJAX)•Manejo de ViewState•El lado del cliente de la página y el código posterior están estrechamente acoplados.•
MVC:
Se tarda más tiempo en desarrollarse en comparación con Web Forms.•Los datos se envían en formato de texto sin cifrar al servidor, mientras que en los formularios web, los datos de estado se cifran de forma predeterminada.
•
Razor View Engine VS ASPX View Engine
https://riptutorial.com/es/home 88
Razor (MVC) ASPX (Formularios Web)
El espacio de nombres utilizado por Razor View Engine es System.Web.Razor
El espacio de nombres utilizado por ASPX View Engine es System.Web.Mvc.WebFormViewEngine
Las extensiones de archivo utilizadas por el motor de vista de Razor son diferentes de un motor de vista de formulario web. Utiliza cshtml con C # y vbhtml con vb para vistas, vista parcial, plantillas y páginas de diseño.
Las extensiones de archivo utilizadas por los motores de vista de formulario web son como los formularios web de ASP.Net. Utiliza la extensión ASPX para ver la extensión aspc para vistas parciales o Controles de usuario o plantillas y extensiones maestras para diseño / páginas maestras.
El motor Razor es compatible con el desarrollo guiado por pruebas (TDD).
El motor de vista de formulario web no es compatible con Test Driven Development (TDD) porque depende de la clase System.Web.UI.Page para hacer la prueba compleja.
ASPX View Engine VS Razor View Engine
Lea MVC vs Formularios Web en línea: https://riptutorial.com/es/asp-net-mvc/topic/8584/mvc-vs-formularios-web
https://riptutorial.com/es/home 89
Capítulo 23: Operación CRUD
Introducción
La operación CRUD se refiere a las operaciones clásicas (crear, leer, actualizar, eliminar) relacionadas con los datos.
En el contexto de ASP MVC, hay varias formas de CRUD sus datos utilizando Modelos y, posteriormente, vistas, Controladores.
Una forma sencilla es hacer uso de la función de andamiaje proporcionada por las plantillas de Visual Studio y personalizarla según sus necesidades.
Tenga en cuenta que CRUD está muy bien definido y tiene muchas variaciones para satisfacer sus necesidades. Por ejemplo, primero la base de datos, primero la entidad, etc.
Observaciones
Para simplificar, esta operación CRUD utiliza un contexto de marco de entidad en el controlador. No es una buena práctica, pero está fuera del alcance de este tema. Haga clic en el marco de la entidad si desea obtener más información al respecto.
Examples
Crear - Parte del controlador
Para implementar la funcionalidad de crear necesitamos dos acciones: GET y POST .
La acción GET utilizada para devolver la vista muestra un formulario que permite al usuario ingresar datos usando elementos HTML. Si hay algunos valores predeterminados que deben insertarse antes de que el usuario agregue datos, debe asignarse a las propiedades del modelo de vista en esta acción.
1.
Cuando el usuario complete el formulario y haga clic en el botón "Guardar", trataremos los datos del formulario. Por eso ahora necesitamos la acción POST . Este método será responsable de administrar los datos y guardarlos en la base de datos. En caso de cualquier error, la misma vista devuelta con datos de formulario almacenados y mensaje de error explica qué problema ocurre después de enviar la acción.
2.
Implementaremos estos dos pasos dentro de dos métodos Create () dentro de nuestra clase de controlador.
// GET: Student/Create // When the user access this the link ~/Student/Create a get request is made to controller Student and action Create, as the page just need to build a blank form, any information is needed to be passed to view builder
https://riptutorial.com/es/home 90
public ActionResult Create() { // Creates a ViewResult object that renders a view to the response. // no parameters means: view = default in this case Create and model = null return View(); } // POST: Student/Create [HttpPost] // Used to protect from overposting attacks, see http://stackoverflow.com/documentation/asp.net-mvc/1997/html-antiforgerytoke for details [ValidateAntiForgeryToken] // This is the post request with forms data that will be bind the action, if in the data post request have enough information to build a Student instance that will be bind public ActionResult Create(Student student) { try { //Gets a value that indicates whether this instance received from the view is valid. if (ModelState.IsValid) { // Adds to the context db.Students.Add(student); // Persist the data db.SaveChanges(); // Returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action, in this case the index action. return RedirectToAction("Index"); } } catch { // Log the error (uncomment dex variable name and add a line here to write a log). ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator."); } // view = default in this case Create and model = student return View(student); }
Crear - Ver parte
@model ContosoUniversity.Models.Student //The Html.BeginForm helper Writes an opening <form> tag to the response. When the user submits the form, the request will be processed by an action method. @using (Html.BeginForm()) { //Generates a hidden form field (anti-forgery token) that is validated when the form is submitted. @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Student</h4> <hr /> //Returns an unordered list (ul element) of validation messages that are in the ModelStateDictionary object. @Html.ValidationSummary(true, "", new { @class = "text-danger" })
https://riptutorial.com/es/home 91
<div class="form-group"> //Returns an HTML label element and the property name of the property that is represented by the specified expression. @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> //Returns an HTML input element for each property in the object that is represented by the Expression expression. @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } }) //Returns the HTML markup for a validation-error message for each data field that is represented by the specified expression. @Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.FirstMidName, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.FirstMidName, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.FirstMidName, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.EnrollmentDate, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.EnrollmentDate, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.EnrollmentDate, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Create" class="btn btn-default" /> </div> </div> </div> } <div> //Returns an anchor element (a element) the text is Back to List and action is Index @Html.ActionLink("Back to List", "Index") </div>
Detalles - parte del controlador
Al ser url ~/Student/Details/5 : (~: raíz del sitio, Student: Controller, Details: Action, 5: student id), es posible recuperar al alumno por su id.
https://riptutorial.com/es/home 92
// GET: Student/Details/5 public ActionResult Details(int? id) { // it good practice to consider that things could go wrong so,it is wise to have a validation in the controller if (id == null) { // return a bad request return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Student student = db.Students.Find(id); if (student == null) { // if doesn't found return 404 return HttpNotFound(); } return View(student); }
Detalles - Ver parte
// Model is the class that contains the student data send by the controller and will be rendered in the view @model ContosoUniversity.Models.Student <h2>Details</h2> <div> <h4>Student</h4> <hr /> <dl class="dl-horizontal"> <dt> //Gets the display name for the model. @Html.DisplayNameFor(model => model.LastName) </dt> <dd> //Returns HTML markup for each property in the object that is represented by the Expression expression. @Html.DisplayFor(model => model.LastName) </dd> <dt> @Html.DisplayNameFor(model => model.FirstMidName) </dt> <dd> @Html.DisplayFor(model => model.FirstMidName) </dd> <dt> @Html.DisplayNameFor(model => model.EnrollmentDate) </dt> <dd> @Html.DisplayFor(model => model.EnrollmentDate) </dd> <dt> @Html.DisplayNameFor(model => model.Enrollments)
https://riptutorial.com/es/home 93
</dt> <dd> <table class="table"> <tr> <th>Course Title</th> <th>Grade</th> </tr> @foreach (var item in Model.Enrollments) { <tr> <td> @Html.DisplayFor(modelItem => item.Course.Title) </td> <td> @Html.DisplayFor(modelItem => item.Grade) </td> </tr> } </table> </dd> </dl> </div> <p> //Returns an anchor element (a element) the text is Edit, action is Edit and the route value is the model ID property. @Html.ActionLink("Edit", "Edit", new { id = Model.ID }) | @Html.ActionLink("Back to List", "Index") </p>
Editar - parte del controlador
// GET: Student/Edit/5 // It is receives a get http request for the controller Student and Action Edit with the id of 5 public ActionResult Edit(int? id) { // it good practice to consider that things could go wrong so,it is wise to have a validation in the controller if (id == null) { // returns a bad request return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } // It finds the Student to be edited. Student student = db.Students.Find(id); if (student == null) { // if doesn't found returns 404 return HttpNotFound(); } // Returns the Student data to fill out the edit form values. return View(student); }
Este método es muy similar al método de acción de detalles, que es un buen candidato para una refactorización, pero está fuera del alcance de este tema.
https://riptutorial.com/es/home 94
// POST: Student/Edit/5 [HttpPost] //used to To protect from overposting attacks more details see http://stackoverflow.com/documentation/asp.net-mvc/1997/html-antiforgerytoke [ValidateAntiForgeryToken] //Represents an attribute that is used for the name of an action. [ActionName("Edit")] public ActionResult Edit(Student student) { try { //Gets a value that indicates whether this instance received from the view is valid. if (ModelState.IsValid) { // Two thing happens here: // 1) db.Entry(student) -> Gets a DbEntityEntry object for the student entity providing access to information about it and the ability to perform actions on the entity. // 2) Set the student state to modified, that means that the student entity is being tracked by the context and exists in the database, and some or all of its property values have been modified. db.Entry(student).State = EntityState.Modified; // Now just save the changes that all the changes made in the form will be persisted. db.SaveChanges(); // Returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action, in this case the index action. return RedirectToAction("Index"); } } catch { //Log the error add a line here to write a log. ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator."); } // return the invalid student instance to be corrected. return View(student); }
Eliminar - parte del controlador
Es una buena práctica resistir la tentación de realizar la acción de eliminación en la solicitud de obtención. Sería un gran error de seguridad, se debe hacer siempre en el método posterior.
// GET: Student/Delete/5 public ActionResult Delete(int? id) { // it good practice to consider that things could go wrong so,it is wise to have a validation in the controller if (id == null) { // returns a bad request return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
https://riptutorial.com/es/home 95
} // It finds the Student to be deleted. Student student = db.Students.Find(id); if (student == null) { // if doesn't found returns 404 return HttpNotFound(); } // Returns the Student data to show the details of what will be deleted. return View(student); } // POST: Student/Delete/5 [HttpPost] //Represents an attribute that is used for the name of an action. [ActionName("Delete")] //used to To protect from overposting attacks more details see http://stackoverflow.com/documentation/asp.net-mvc/1997/html-antiforgerytoke [ValidateAntiForgeryToken] public ActionResult Delete(int id) { try { // Finds the student Student student = db.Students.Find(id); // Try to remove it db.Students.Remove(student); // Save the changes db.SaveChanges(); } catch { //Log the error add a line here to write a log. ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator."); } // Returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action, in this case the index action. return RedirectToAction("Index"); }
Lea Operación CRUD en línea: https://riptutorial.com/es/asp-net-mvc/topic/6380/operacion-crud
https://riptutorial.com/es/home 96
Capítulo 24: Plantillas de visualización y editor
Introducción
Al tratar con objetos en una aplicación MVC, si algún objeto se muestra en varios lugares con el mismo formato, necesitaríamos algún tipo de diseño estandarizado. ASP.NET MVC ha hecho que este tipo de estandarización sea fácil de hacer con la inclusión de plantillas de visualización y editor. En resumen, las plantillas de visualización y editor se utilizan para estandarizar el diseño que se muestra al usuario al editar o mostrar ciertos tipos o clases.
Examples
Plantilla de pantalla
Modelo:
public class User { public int ID { get; set; } public string FirstName { get; set; } public DateTime DateOfBirth { get; set; } }
Si queremos mostrar a los usuarios en diferentes Vistas, sería mejor crear un diseño estandarizado para estos usuarios donde sea necesario. Podemos lograr esto utilizando plantillas de pantalla.
Una plantilla de visualización es simplemente una vista parcial que está vinculada con el modelo al objeto que desea mostrar y existe en la carpeta Views/Shared/DisplayTemplates (aunque también puede ponerla en Views/ControllerName/DisplayTemplates ). Además, el nombre de la vista (de forma predeterminada) debe ser el nombre del objeto para el que desea utilizarlo como plantilla .
Vistas / Shared / DisplayTemplates / User.cshtml
@model TemplatesDemo.Models.User <div style="padding-bottom: 10px"> <p><strong>ID:</strong> @Html.DisplayFor(m => m.ID)</p> <p><strong>Name:</strong> @Html.DisplayFor(m => m.FirstName)</p> <p><strong>Date of Birth:</strong> @Html.DisplayFor(m => m.DateOfBirth)</p> </div> <hr/>
Ahora, si queremos mostrar a todos los usuarios de la base de datos y mostrarlos en diferentes Vistas, simplemente podemos enviar la lista de usuarios a la Vista y usar la Plantilla de
https://riptutorial.com/es/home 97
Visualización para mostrarlos. Podemos usar uno de los dos métodos para hacerlo:
Html.DisplayFor() Html.DisplayForModel()
DisplayFor llama a la plantilla de pantalla para el tipo de propiedad seleccionada (por ejemplo, Html.DisplayFor(x => x.PropertyName) . DisplayForModel llama a la plantilla de pantalla para el @model de la vista
Ver
@model IEnumerable<TemplatesDemo.Models.User> @{ ViewBag.Title = "Users"; } <h2>Users</h2> @Html.DisplayForModel()
Plantilla de editor
Las Plantillas de visualización se pueden usar para estandarizar el diseño de un objeto, así que ahora veamos cómo podemos hacer lo mismo para estos objetos al editarlos. Al igual que las plantillas de visualización, hay dos formas de llamar a las plantillas de editor para un tipo dado:
Html.EditorFor() Html.EditorForModel()
Las plantillas de editor, al igual que las plantillas de visualización, deben existir en Views / Shared / EditorTemplates o Views / ControllerName / EditorTemplates . Para esta demostración, los crearemos en la carpeta Compartida. Nuevamente, el nombre de la vista (de manera predeterminada) debe ser el nombre del objeto para el que desea usarla como plantilla.
Modelo
public class User { public int Id { get; set; } public string Name { get; set; } public DateTime DateOfBirth { get; set; } public Roles Roles { get; set; } public int RoleId { get; set; } } public class Roles { public int Id { get; set; } public string Role { get; set; } }
https://riptutorial.com/es/home 98
Digamos que queremos poder editar cualquier usuario desde la base de datos en múltiples vistas. Usaremos un ViewModel para este propósito.
ViewModel
public class UserEditorViewModel { public User User { get; set; } public IEnumerable<Roles> Roles { get; set; } }
Usando este ViewModel , crearemos una plantilla de editor
Vistas / Shared / EditorTemplates / UserEditorViewModel.cshtml
@model TemplatesDemo.Models.UserEditorViewModel <div class="form-group"> @Html.DisplayNameFor(m => m.User.Id) @Html.EditorFor(m => m.User.Id) </div> <div class="form-group"> @Html.DisplayNameFor(m => m.User.Name) @Html.EditorFor(m => m.User.Name) </div> <div class="form-group"> @Html.DisplayNameFor(m => m.User.DateOfBirth) @Html.EditorFor(m => m.User.DateOfBirth) </div> <div class="form-group"> @Html.DisplayNameFor(m => m.User.Roles.Role) @Html.DropDownListFor(m => m.User.RoleId, new SelectList(Model.Roles,"Id","Role")) </div>
Obtendremos el usuario deseado y la lista de roles disponibles y los vincularemos en viewModel UserEditorViewModel en Controller Action y enviaremos el viewModel a la vista. Para simplificar, estoy iniciando el viewModel desde la Acción.
Acción
public ActionResult Editor() { var viewModel = new UserEditorViewModel { User = new User { Id = 1, Name = "Robert", DateOfBirth = DateTime.Now, RoleId = 1 }, Roles = new List<Roles>() { new Roles { Id = 1,
https://riptutorial.com/es/home 99
Role = "Admin" }, new Roles { Id = 2, Role = "Manager" }, new Roles { Id = 3, Role = "User" } } }; return View(viewModel); }
Podemos usar la plantilla de editor creada en cualquier vista que deseemos.
Ver
@model TemplatesDemo.Models.UserEditorViewModel @using (Html.BeginForm("--Your Action--", "--Your Controller--")) { @Html.EditorForModel() <input type="submit" value="Save" /> }
Lea Plantillas de visualización y editor en línea: https://riptutorial.com/es/asp-net-mvc/topic/9784/plantillas-de-visualizacion-y-editor
https://riptutorial.com/es/home 100
Capítulo 25: Registro de errores
Examples
Atributo simple
using System; using System.Web; using System.Web.Mvc; namespace Example.SDK.Filters { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] public sealed class CustomErrorHandlerFilter : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { // RouteDate is useful for retrieving info like controller, action or other route values string controllerName = filterContext.RouteData.Values["controller"].ToString(); string actionName = filterContext.RouteData.Values["action"].ToString(); string exception = filterContext.Exception.ToString(); // Full exception stack string message = filterContext.Exception.Message; // Message given by the exception // Log the exception within database LogExtensions.Insert(exception.ToString(), message, controllerName + "." + actionName); base.OnException(filterContext); } } }
Luego FilterConfig.cs en FilterConfig.cs
filters.Add(new CustomErrorHandlerFilter());
devolviendo página de error personalizada
public ActionResult Details( string product) { .... if (productNotFound) { // http://www.eidias.com/blog/2014/7/2/mvc-custom-error-pages Response.Clear(); Response.TrySkipIisCustomErrors = true; Response.Write(product + " product not exists"); Response.StatusCode = (int)HttpStatusCode.NotFound; Response.End(); return null; }
https://riptutorial.com/es/home 101
}
Cree un ErrorLogger personalizado en ASP.Net MVC
Paso 1: Crear un filtro de registro de errores personalizado que escribirá errores en archivos de texto de acuerdo con DateWise.
public class ErrorLogger : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { string strLogText = ""; Exception ex = filterContext.Exception; filterContext.ExceptionHandled = true; var objClass = filterContext; strLogText += "Message ---\n{0}" + ex.Message; if (ex.Source == ".Net SqlClient Data Provider") { strLogText += Environment.NewLine + "SqlClient Error ---\n{0}" + "Check Sql Error"; } else if (ex.Source == "System.Web.Mvc") { strLogText += Environment.NewLine + ".Net Error ---\n{0}" + "Check MVC Code For Error"; } else if (filterContext.HttpContext.Request.IsAjaxRequest() == true) { strLogText += Environment.NewLine + ".Net Error ---\n{0}" + "Check MVC Ajax Code For Error"; } strLogText += Environment.NewLine + "Source ---\n{0}" + ex.Source; strLogText += Environment.NewLine + "StackTrace ---\n{0}" + ex.StackTrace; strLogText += Environment.NewLine + "TargetSite ---\n{0}" + ex.TargetSite; if (ex.InnerException != null) { strLogText += Environment.NewLine + "Inner Exception is {0}" + ex.InnerException;//error prone } if (ex.HelpLink != null) { strLogText += Environment.NewLine + "HelpLink ---\n{0}" + ex.HelpLink;//error prone } StreamWriter log; string timestamp = DateTime.Now.ToString("d-MMMM-yyyy", new CultureInfo("en-GB")); string error_folder = ConfigurationManager.AppSettings["ErrorLogPath"].ToString(); if (!System.IO.Directory.Exists(error_folder)) { System.IO.Directory.CreateDirectory(error_folder); } if (!File.Exists(String.Format(@"{0}\Log_{1}.txt", error_folder, timestamp)))
https://riptutorial.com/es/home 102
{ log = new StreamWriter(String.Format(@"{0}\Log_{1}.txt", error_folder, timestamp)); } else { log = File.AppendText(String.Format(@"{0}\Log_{1}.txt", error_folder, timestamp)); } var controllerName = (string)filterContext.RouteData.Values["controller"]; var actionName = (string)filterContext.RouteData.Values["action"]; // Write to the file: log.WriteLine(Environment.NewLine + DateTime.Now); log.WriteLine("------------------------------------------------------------------------------------------------"); log.WriteLine("Controller Name :- " + controllerName); log.WriteLine("Action Method Name :- " + actionName); log.WriteLine("------------------------------------------------------------------------------------------------"); log.WriteLine(objClass); log.WriteLine(strLogText); log.WriteLine(); // Close the stream: log.Close(); filterContext.HttpContext.Session.Abandon(); filterContext.Result = new RedirectToRouteResult (new RouteValueDictionary { {"controller", "Errorview"}, {"action", "Error"} }); } }
Paso 2: Agregar ruta física en el servidor o en la unidad local donde se almacenará el archivo de texto
<add key="ErrorLogPath" value="C:\ErrorLog\DemoMVC\" />
Paso 3: Agregar Errorview Controller con Error ActionMethod
Paso 4: Agregar error.cshtml Ver y mostrar mensaje de error personalizado en la vista
Paso 5: Registrar el filtro ErrorLogger en la clase FilterConfig
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new ErrorLogger()); } }
https://riptutorial.com/es/home 103
Paso 6: Registrar FilterConfig en Global.asax
Lea Registro de errores en línea: https://riptutorial.com/es/asp-net-mvc/topic/2268/registro-de-errores
https://riptutorial.com/es/home 104
Capítulo 26: Reglas de reescritura de IIS
Examples
Forzar HTTPS usando la regla de reescritura
Este ejemplo muestra cómo puede usar las reglas de IIS Rewrite para forzar HTTPS haciendo que todas las solicitudes HTTP devuelvan un Redireccionamiento 301 (Permanente) a la página HTTPS.
Esto suele ser mejor que usar el atributo [RequireHttps] porque el atributo usa una redirección 302, y al estar en el canal de MVC es mucho más lento que hacerlo a nivel de IIS.
<rewrite xdt:Transform="Insert"> <rules> <rule name="Enforce HTTPS WWW" stopProcessing="true"> <match url=".*" /> <conditions logicalGrouping="MatchAll" trackAllCaptures="true"> <add input="{HTTP_HOST}" pattern="^(?!www)(.*)"/> <add input="{URL}" pattern="^(.*)"/> <!-- {URL} Gives the base portion of the URL, without any querystring or extra path information, for example, "/vdir/default.asp". --> </conditions> <action type="Redirect" url="https://www.{C:1}{C:2}" appendQueryString="true" redirectType="Permanent" /> </rule> </rules> </rewrite>
Lea Reglas de reescritura de IIS en línea: https://riptutorial.com/es/asp-net-mvc/topic/6358/reglas-de-reescritura-de-iis
https://riptutorial.com/es/home 105
Capítulo 27: T4MVC
Introducción
T4MVC es una plantilla T4 que genera ayudantes fuertemente tipados para usar en los mecanismos de enrutamiento MVC, a diferencia de las cadenas mágicas. T4MVC detectará los diversos controladores, acciones y vistas, y creará referencias a esas vistas, cometiendo errores en tiempo de compilación en el caso de que un intento de enrutar o acceder a una vista no sea válido.
Examples
Llamando a una acción
En MVC, hay algunos escenarios donde desea especificar una acción para propósitos de enrutamiento, ya sea para un enlace, una acción de formulario o una redirección a la acción. Puede especificar una acción a través del espacio de nombres MVC.
Cuando se le da un controlador, como HomeController :
public class HomeController : Controller { public ActionResult Index() { ... } public ActionResult MyAction() { ... } public ActionResult MyActionWithParameter(int parameter) { ... } }
T4MVC generará un controlador heredado que anula la acción. Esta anulación establecerá los datos de la ruta correctamente para que UrlHelper de MVC genere la URL correcta. Puede llamar a este método y pasarlo a varios métodos para UrlHelper . Los siguientes ejemplos suponen que se está utilizando la ruta MVC predeterminada:
Enlazar
Para generar una a etiqueta con el texto especificado:
@Html.ActionLink("Link Text", MVC.Home.Index() ) //result: <a href="/">Link Text</a> @Html.ActionLink("Link Text", MVC.Home.MyAction() ) //result: <a href="/Home/MyAction">Link Text</a>
https://riptutorial.com/es/home 106
//T4MVC also allows you to specify the parameter without creating an anonymous object: @Html.ActionLink("Link Text", MVC.Home.MyActionWithParameter(1) ) //result: <a href="/Home/MyActionWithParameter/1">Link Text</a>
Para generar un url:
@Url.Action( MVC.Home.Index() ) //result: / @Url.Action("Link Text", MVC.Home.MyAction() ) //result: /Home/MyAction @Url.Action("Link Text", MVC.Home.MyActionWithParameter(1) ) //result: /Home/MyActionWithParameter/1
Tenga en cuenta que T4MVC sigue las mismas reglas que MVC Routing: no especificará las variables de ruta predeterminadas, por lo que la acción del Index en el HomeController no genera /Home/Index sino la forma abreviada y perfectamente válida de / .
Método de formulario
Para generar una etiqueta de form con la action correcta especificada:
@Html.BeginForm( MVC.Home.Index(), FormMethod.Get /* or FormMethod.Post */ ) { //my form } //result: <form action="/" method="GET"> //my form </form> @Html.BeginForm( MVC.Home.MyActionWithParameter(1), FormMethod.Get /* or FormMethod.Post */ ) { //my form } //result: <form action="/Home/MyActionWithParameter/1" method="GET"> //my form </form>
Redirigir a la acción
Cuando esté en un controlador, es posible que desee redirigir a una acción de la acción actual. Esto se puede hacer, likeso:
public class RedirectingController : Controller { public ActionResult MyRedirectAction() { ... return RedirectToAction( MVC.Redirecting.ActionToRedirectTo() ); //redirects the user to the action below. } public ActionResult ActionToRedirectTo() { ... }
https://riptutorial.com/es/home 107
}
Lea T4MVC en línea: https://riptutorial.com/es/asp-net-mvc/topic/9147/t4mvc
https://riptutorial.com/es/home 108
Capítulo 28: Usando múltiples modelos en una vista
Introducción
El enfoque principal de este tema es usar una clase de modelo múltiple en la capa de visualización de MVC
Examples
Uso de múltiples modelos en una vista con ExpandoObject dinámico
ExpandoObject (el espacio de nombres System.Dynamic ) es una clase que se agregó a .Net Framework 4.0 . Esta clase nos permite agregar y eliminar dinámicamente propiedades en un objeto en tiempo de ejecución. Al utilizar el objeto Expando, podemos agregar nuestras clases de modelo en el objeto Expando creado dinámicamente. El siguiente ejemplo explica cómo podemos usar este objeto dinámico.
Modelo de profesor y alumno:
public class Teacher { public int TeacherId { get; set; } public string Name { get; set; } } public class Student { public int StudentId { get; set; } public string Name { get; set; } }
Métodos de lista de profesores y alumnos:
public List<Teacher> GetTeachers() { List<Teacher> teachers = new List<Teacher>(); teachers.Add(new Teacher { TeacherId = 1, Name = "Teacher1" }); teachers.Add(new Teacher { TeacherId = 2, Name = "Teacher2" }); teachers.Add(new Teacher { TeacherId = 3, Name = "Teacher3" }); return teachers; } public List<Student> GetStudents() { List<Student> students = new List<Student>(); students.Add(new Student { StudentId = 1, Name = "Student1"}); students.Add(new Student { StudentId = 2, Name = "Student2"}); students.Add(new Student { StudentId = 3, Name = "Student3"});
https://riptutorial.com/es/home 109
return students; }
Controlador (usando el modelo dinámico):
public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "Hello World"; dynamic mymodel = new ExpandoObject(); mymodel.Teachers = GetTeachers(); mymodel.Students = GetStudents(); return View(mymodel); } }
Ver:
@using ProjectName ; // Project Name @model dynamic @{ ViewBag.Title = "Home Page"; } <h2>@ViewBag.Message</h2> <h2>Teacher List</h2> <table> <tr> <th>Id</th> <th>Name</th> </tr> @foreach (Teacher teacher in Model.Teachers) { <tr> <td>@teacher.TeacherId</td> <td>@teacher.Name</td> </tr> } </table> <h2>Student List</h2> <table> <tr> <th>Id</th> <th>Name</th> </tr> @foreach (Student student in Model.Students) { <tr> <td>@student.StudentId</td> <td>@student.Name</td> </tr> } </table>
https://riptutorial.com/es/home 110
Lea Usando múltiples modelos en una vista en línea: https://riptutorial.com/es/asp-net-mvc/topic/10144/usando-multiples-modelos-en-una-vista
https://riptutorial.com/es/home 111
Capítulo 29: Validación automática del lado del cliente a partir de atributos
Observaciones
Por defecto, Safari no impone la validación de elementos HTML5. Debe anular esto manualmente utilizando otros medios.
Examples
Modelo
public class UserModel { [Required] [StringLength(6, MinimumLength = 3)] [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")] public string UserName { get; set; } [Required] [StringLength(8, MinimumLength = 3)] public string FirstName { get; set; } [Required] [StringLength(9, MinimumLength = 2)] public string LastName { get; set; } [Required] public string City { get; set; } }
configuración de web.config
<appSettings> <add key="ClientValidationEnabled" value="true"/> <add key="UnobtrusiveJavaScriptEnabled" value="true"/> </appSettings>
Paquetes Nuget Requeridos
<package id="jQuery" version="1.10.2" targetFramework="net452" /> <package id="jQuery.Validation" version="1.11.1" targetFramework="net452" /> <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.3" targetFramework="net452" />
Vista de formulario
https://riptutorial.com/es/home 112
@model WebApplication4.Models.UserModel @{ ViewBag.Title = "Register"; } <h2>@ViewBag.Title.</h2> @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) { @Html.AntiForgeryToken() <h4>Create a new account.</h4> <hr /> @Html.ValidationSummary("", new { @class = "text-danger" }) <div class="form-group"> @Html.LabelFor(m => m.FirstName, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.FirstName, new { @class = "form-control" }) @Html.ValidationMessageFor(m=>m.FirstName) </div> </div> <div class="form-group"> @Html.LabelFor(m => m.LastName, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.LastName, new { @class = "form-control" }) @Html.ValidationMessageFor(m => m.LastName) </div> </div> <div class="form-group"> @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" }) @Html.ValidationMessageFor(m => m.UserName) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" class="btn btn-default" value="Register" /> </div> </div> } @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
Configuración del paquete
public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/bundles/jquery").Include( "~/Scripts/jquery-{version}.js")); bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( "~/Scripts/jquery.validate*"));
https://riptutorial.com/es/home 113
} }
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); // Need to include your bundles BundleConfig.RegisterBundles(BundleTable.Bundles); } }
Lea Validación automática del lado del cliente a partir de atributos en línea: https://riptutorial.com/es/asp-net-mvc/topic/6044/validacion-automatica-del-lado-del-cliente-a-partir-de-atributos
https://riptutorial.com/es/home 114
Capítulo 30: ViewData, ViewBag, TempData
Introducción
ViewData y ViewBag se utilizan para transferir datos desde el controlador para ver.
ViewData no es más que un diccionario de objetos y es accesible por cadena como clave.
ViewBag es muy similar a ViewData. ViewBag es una propiedad dinámica. ViewBag es solo una envoltura alrededor de ViewData.
TempData mantiene los datos durante el tiempo de la solicitud HTTP, lo que significa que mantiene los datos entre dos solicitudes consecutivas. TempData nos ayuda a transferir datos entre controladores o entre acciones. Usos de sesión interna.
Sintaxis
ViewData [clave] = valor;1.
ViewBag.Key = valor;2.
TempData [clave] = valor;3.
Examples
¿Qué son ViewData, ViewBag y TempData?
ViewData es el mecanismo para que un controlador proporcione datos a la vista que presenta, sin usar ViewModel. Específicamente, ViewData es un diccionario que está disponible tanto en los métodos de acción MVC como en las vistas. Puede usar ViewData para transferir algunos datos de su método de acción a la vista devuelta por el método de acción.
Como es un diccionario, puede usar el diccionario como sintaxis para configurar y obtener datos de él.
ViewData[key] = value; // In the action method in the controller
Por ejemplo, si desea pasar un mensaje de cadena de su método de acción de índice a su vista de índice Index.cshtml , puede hacer esto.
public ActionResult Index() { ViewData["Message"] = "Welcome to ASP.NET MVC"; return View(); // notice the absence of a view model }
https://riptutorial.com/es/home 115
Para acceder a esto en su vista Index.cshtml , simplemente puede acceder al diccionario ViewData con la tecla utilizada en el método de acción.
<h2>@ViewData["Message"]</h2>
ViewBag es el equivalente dinámico del diccionario ViewData sin tipo. Aprovecha el tipo dynamic C # para la experiencia del azúcar sintáctico.
La sintaxis para configurar algunos datos para ViewBag es
ViewBag.Key = Value;
Entonces, si queremos pasar la cadena de mensaje en nuestro ejemplo anterior usando ViewBag, será
public ActionResult Index() { ViewBag.Message = "Welcome to ASP.NET MVC"; return View(); // not the absence of a view model }
y en su vista de índice,
<h2>@ViewBag.Message</h2>
Los datos no se comparten entre ViewBag y ViewData. ViewData requiere encasillado para obtener datos de tipos de datos complejos y buscar valores nulos para evitar errores cuando View Bag no requiere encasillado.
TempData se puede usar cuando desea conservar datos entre una solicitud http y la siguiente solicitud HTTP solamente. La vida útil de los datos almacenados en TempDataDictionary finaliza después de la segunda solicitud. Por lo tanto, TempData es útil en situaciones en las que estás siguiendo el patrón PRG.
[HttpPost] public ActionResult Create(string name) { // Create a user // Let's redirect (P-R-G Pattern) TempData["Message"] = "User created successfully"; return RedirectToAction("Index"); } public ActionResult Index() { var messageFromPreviousCall = TempData["Message"] as String; // do something with this message // to do : Return something }
Cuando return RedirectToAction("SomeActionMethod") , el servidor enviará una respuesta 302 al cliente (navegador) con el valor del encabezado de ubicación establecido en la URL a
https://riptutorial.com/es/home 116
"SomeActionMethod" y el navegador le enviará una solicitud totalmente nueva. ViewBag / ViewData no funcionará en ese caso para compartir algunos datos entre estas 2 llamadas. Necesitas usar TempData en tales escenarios.
Ciclo de vida de TempData
Los datos guardados en TempData se almacenan en la sesión y se eliminarán automáticamente al final de la primera solicitud donde se accede a los datos. Si nunca se lee, se mantendrá hasta que finalmente se lea o la sesión se agote.
El uso típico se parece a la siguiente secuencia (donde cada línea se invoca desde una solicitud diferente):
//first request, save value to TempData TempData["value"] = "someValueForNextRequest"; //second request, read value, which is marked for deletion object value = TempData["value"]; //third request, value is not there as it was deleted at the end of the second request TempData["value"] == null
Este comportamiento puede ser más controlado con los métodos Peek y Keep .
Con Peek puede recuperar los datos almacenados en TempData sin marcarlos para eliminarlos, por lo que los datos seguirán estando disponibles en una futura solicitud.
//first request, save value to TempData TempData["value"] = "someValueForNextRequest"; //second request, PEEK value so it is not deleted at the end of the request object value = TempData.Peek("value"); //third request, read value and mark it for deletion object value = TempData["value"];
•
Con Keep , puede especificar que una clave que se marcó para su eliminación debería conservarse. En este caso, recuperar los datos y guardarlos para eliminarlos requiere 2 llamadas de método:
//first request, save value to TempData TempData["value"] = "someValueForNextRequest"; //second request, get value marking it from deletion object value = TempData["value"]; //later on decide to keep it TempData.Keep("value"); //third request, read value and mark it for deletion object value = TempData["value"];
•
Con esto en mente, use Peek cuando siempre quiera conservar el valor para otra solicitud y use Keep cuando el valor se Keep dependiendo de la lógica adicional.
https://riptutorial.com/es/home 117
Lea ViewData, ViewBag, TempData en línea: https://riptutorial.com/es/asp-net-mvc/topic/1286/viewdata--viewbag--tempdata
https://riptutorial.com/es/home 118
Capítulo 31: Vistas parciales
Introducción
Una vista parcial es una vista que se representa dentro de otra vista. Las vistas parciales se pueden reutilizar y así evitar la duplicación de código. Pueden ser renderizados por Html.Partial o Html.RenderPartial
Sintaxis
@ Html.Partial ("ViewName")
@ Html.Partial ("ViewName", ViewModel)
@ {Html.RenderPartial ("ViewName");}
Si su vista parcial se encuentra en una carpeta diferente a la compartida, entonces deberá mencionar la ruta completa de la vista como se muestra a continuación:
[email protected] ("~ / Areas / Admin / Views / Shared / partial / _subcat.cshtml")
•
Examples
Vista parcial con modelo.
También se puede agregar un modelo a la vista parcial:
@model Solution.Project.Namespace.MyModelClass <p>@Model.Property</p>
En la Vista ahora solo puedes usar:
<div> @Html.Partial("PartialViewExample", new MyModelClass(){Property="my property value"}) </div> <div> @{ Html.RenderPartial("PartialViewExample", new MyModelClass(){Property="my property value"}); } </div>
Vista parcial a una cadena - para contenido de correo electrónico, etc.
Llamando a la función
string InvoiceHtml = myFunction.RenderPartialViewToString("PartialInvoiceCustomer", ToInvoice); // ToInvoice is a model, you can pass parameters if needed
https://riptutorial.com/es/home 119
Función para generar HTML
public static string RenderPartialViewToString(string viewName, object model) { using (var sw = new StringWriter()) { BuyOnlineController controller = new BuyOnlineController(); // instance of the required controller (you can pass this as a argument if needed) // Create an MVC Controller Context var wrapper = new HttpContextWrapper(System.Web.HttpContext.Current); RouteData routeData = new RouteData(); routeData.Values.Add("controller", controller.GetType().Name.ToLower().Replace("controller", "")); controller.ControllerContext = new ControllerContext(wrapper, routeData, controller); controller.ViewData.Model = model; var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName); var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw); viewResult.View.Render(viewContext, sw); return sw.ToString(); } }
Vista parcial - PartialInvoiceCustomer
@model eDurar.Models.BuyOnlineCartMaster <h2>hello customer - @Model.CartID </h2>
Html.Partial Vs Html.RenderPartial
Html.Partial devuelve una cadena por otro lado Html.RenderPartial devuelve void.
Html.RenderPartial
Este método devuelve void y el resultado se escribe directamente en el flujo de respuesta HTTP. Eso significa que usa el mismo objeto TextWriter que se usa en la página web / plantilla actual. Por este motivo, este método es más rápido que el método parcial. Este método es útil cuando los datos que se muestran en la vista parcial ya están en el modelo de vista correspondiente.
Ejemplo: en un blog para mostrar los comentarios de un artículo, nos gustaría usar el método RenderPartial ya que la información de un artículo con comentarios ya está completa en el modelo de vista.
@{Html.RenderPartial("_Comments");}
https://riptutorial.com/es/home 120
Html.parcial
Este método devuelve una cadena codificada en HTML. Esto se puede almacenar en una variable. Al igual que el método RenderPartial, el método Parcial también es útil cuando los datos que se muestran en la vista parcial ya están en el modelo de vista correspondiente.
Ejemplo: en un blog para mostrar los comentarios de un artículo, puede usar el método Parcial, ya que la información de un artículo con comentarios ya se ha completado en el modelo de vista.
@Html.Partial("_Comments")
Lea Vistas parciales en línea: https://riptutorial.com/es/asp-net-mvc/topic/2171/vistas-parciales
https://riptutorial.com/es/home 121
Capítulo 32: Web.config cifrado
Examples
Cómo proteger su archivo web.config
Es una buena práctica cifrar su archivo Web.config si tiene información confidencial allí, por ejemplo, una cadena de conexión con contraseña.
Con la herramienta de registro IIS de ASP.NET (Aspnet_regiis.exe) puede cifrar fácilmente secciones específicas del archivo Web.config. Se requiere un comando con privilegios elevados.
Ejemplo utilizando DataProtectionConfigurationProvider . Este proveedor utiliza DPAPI para cifrar y descifrar datos:
aspnet_regiis.exe -pef "connectionStrings" c:\inetpub\YourWebApp -prov "DataProtectionConfigurationProvider"
Ejemplo utilizando RSAProtectedConfigurationProvider :
aspnet_regiis.exe -pef "connectionStrings" c:\inetpub\YourWebApp -prov "RSAProtectedConfigurationProvider"
Si no especifica el parámetro -prov, utiliza RSAProtectedConfigurationProvider como predeterminado. Este proveedor se recomienda para los escenarios de Web Farm.
Para obtener la sección connectionStrings de nuevo para borrar el texto:
aspnet_regiis.exe -pdf "connectionStrings" c:\inetpub\YourWebApp
Más información sobre el aspnet_regiis.exe está disponible en MSDN .
Lea Web.config cifrado en línea: https://riptutorial.com/es/asp-net-mvc/topic/6373/web-config-cifrado
https://riptutorial.com/es/home 122
Creditos
S. No
Capítulos Contributors
1Empezando con asp.net-mvc
Aaron Hudon, Adil Mammadov, Aditya Korti, Ameya Deshpande, Ashley Medway, Community, Hywel Rees, Rifaj, Shog9, Shyju, Supraj v, Syed Farjad Zia Zaidi, SztupY
2 ActionResult hasan, SlaterCodes, Tetsuya Yamamoto
3 Anotaciones de datos
abiNerd, dotnetom, dove, Edathadan Chief aka Arun, Ehsan Sajjad, Felipe Oriani, gunr2171, Karthikeyan, LaCartouche, mmushtaq, Ollie P, Rion Williams, SailajaPalakodeti, Stephen Muecke, Tetsuya Yamamoto, The_Outsider, tmg, Tsahi Asher
4 Áreas Himaan Singh, Tetsuya Yamamoto
5Asp.net mvc enviar correo
Ashiquzzaman, hasan, sGermosen
6 Ayudantes htmlAshiquzzaman, Laurel, Lokesh_Ram, Pavel Pája Halbich, Peter Mortensen, QuantumHive, Tassadaque, Testing123, Tetsuya Yamamoto, The_Outsider, TheFallenOne
7Dockerización de la aplicación ASP.NET
SUMIT LAHIRI
8Empaquetado y Minificación
Ashley Medway, Beofett, hasan, Laurel, Lokesh_Ram, Paul DS, rageit, Rion Williams, Robban, Tetsuya Yamamoto, tmg
9 Enrutamiento
Alex Art., Andrei Rînea, chsword, Ciaran Bruen, Jarrod Dixon, Jason Evans, Karthikeyan, kkakkurt, Laurel, Lokesh_Ram, mstaessen, Pavel Voronin, SailajaPalakodeti, Sandro, Shyju, SlaterCodes, Stephen Muecke, Tetsuya Yamamoto, tmg, Tot Zam, user270576
10 Extensiones Ajax MVC rll
11 Filtros de accionAndrei Rînea, Dawood Awan, juunas, Laurel, Lokesh_Ram, Tolga Evcimen
12 Html.AntiForgeryTokenAaron Hudon, Andrei Rînea, Art, felickz, Hanno, Jakotheshadows, Joshua Leigh, Martin Costello, Minh Nguyen, Rion Williams, SailajaPalakodeti, SlaterCodes, viggity
13 Html.RouteLink Jason Evans
https://riptutorial.com/es/home 123
14Inyección de dependencia
Adil Mammadov, Andrei Dragotoniu, Cà phê đen, Dave, PedroSouki
15jQuery Ajax Call Con Asp MVC
Ashiquzzaman, hasan
16 Manejo de errores Http scgough
17 Maquinilla de afeitar
Aditya Korti, aeliusd, Anik Saha, Arendax, Ashley Medway, Big Fan, Brandon Wood, Braydie, Denis Elkhov, dove, James Haug, Julian, Kuldeep Prajapati, Lee Chengkai, lloyd, RamenChef, SadiRubaiyet, Sain Pradeep, Sandro, Thennarasan, Tim Coker, TKharaishvili, Tot Zam, usr
18 Modelo de enlaceAdil Mammadov, Andrei Rînea, dove, Ehsan Sajjad, James Haug, Md Dinar, PedroSouki, rdans, Tolga Evcimen
19 Modelo de validaciónAaron Hudon, Ankit Kumar Singh, GTown-Coder, hasan, Marimba, Nikunj Patel, Pavel Voronin, SlaterCodes, Stephen Muecke, The_Outsider, TheFallenOne, Vincentw
20MVC vs Formularios Web
DiegoS, Houssam Hamdan, The_Outsider
21 Operación CRUD EvenPrime, Krzyserious, PedroSouki, Tetsuya Yamamoto
22Plantillas de visualización y editor
Adnan Niloy, SailajaPalakodeti
23 Registro de errores Andrus, Leandro Soares, Saineshwar
24Reglas de reescritura de IIS
SlaterCodes
25 T4MVC James Haug
26Usando múltiples modelos en una vista
hasan, Travis Tubbs
27Validación automática del lado del cliente a partir de atributos
Slick86
28ViewData, ViewBag, TempData
bzlm, Daniel J.G., IanB, Rion Williams, SailajaPalakodeti, Shyju, TheFallenOne, tmg
29 Vistas parcialesAdnan Niloy, Ashiquzzaman, Edathadan Chief aka Arun, glacasa, Jason Evans, Laurel, Lokesh_Ram, Marimba, SailajaPalakodeti, The_Outsider
https://riptutorial.com/es/home 124
30 Web.config cifrado glaubergft, Jack Spektor
https://riptutorial.com/es/home 125