Hace unos meses, un usuario de StackOverflow planteaba una interesante cuestión: ¿qué debería saber un desarrollador para construir un sitio web público? Es decir, ¿cuáles son aquellos aspectos importantes que deben tenerse en cuenta a la hora de crear un site de calidad, desde el punto de vista técnico?
Tras un tiempo de respuestas, ideas y debates, otro usuario ha realizado una recopilación de los aspectos y sugerencias más votadas y los ha publicado en forma de lista categorizada, donde podemos encontrar muy buenas ideas a tener en cuenta en nuestros propios desarrollos, y que me he permitido traducir.
Muchos de los puntos son obvios y seguro que ya los estáis teniendo en cuenta, quizás otros son demasiado exagerados, y seguro que alguno de ellos ni siquiera os los habíais planteado. En cualquier caso el resultado es una relación interesante y muy a tener en cuenta para mejorar nuestros sitios web.
Interfaz y experiencia de usuario
- Ser consciente de que los navegadores implementan los estándares de forma diferente y asegurarse de que el sitio web funciona razonablemente bien en la mayoría de los principales navegadores. Como mínimo, sería necesario probarlo con un navegador que utilice un motor reciente Gecko (Firefox), Webkit (Safari, Chrome y algunos navegadores móviles), las versiones soportadas de Internet Explorer, y Opera.
- Tener en cuenta que el sitio web puede ser visitado utilizando medios distintos a los navegadores habituales, como por ejemplo teléfonos móviles, lectores de pantalla, o motores de búsqueda. Usar estándares de accesibilidad como WAI o Section508.
- Considerar los mecanismos de actualización del sitio web para que estos procesos no afecten a los usuarios una vez que el sistema está en marcha y puedan producirse de forma suave y transparente. Por ejemplo, puede ayudar el mantener entornos de prueba paralelos, el uso de herramientas de control del código fuente, o mecanismos de builds automatizados.
- No mostrar errores directamente al usuario.
- No incluir en las páginas direcciones de correo de usuarios en texto plano, para evitar que sean bombardeados por los spammers.
- Incluir límites razonables de utilización del sitio para evitar malos usos por parte de usuarios o procesos automáticos (como puede ser los virus). Por ejemplo, es razonable que un sistema de correo electrónico gratuito limite el número de mensajes diarios que puede enviar un usuario, aunque el número máximo sea muy alto; otro ejemplo podemos verlo en Google, que muestra un mensaje de error cuando detecta demasiado tráfico hacia sus servidores desde una única dirección IP.
Seguridad
- Conocer la amplia guía de desarrollo OWASP, que cubre la seguridad de sitios web de forma muy completa.
- Conocer el fundamento de los ataques de inyección SQL y cómo prevenirlos.
- Jamás confiar en los datos introducidos por los usuarios.
- Evitar el almacenamiento de contraseñas en texto plano utilizando técnicas criptográficas como hashes y salts.
- No intentes utilizar tu magnífico y elaborado sistema de autenticación; es bastante probable que existan fallos impredecibles de los que sólo te darás cuenta después de haber sido hackeado.
- Usar SSL/HTTPS en las páginas de identificación de usuarios y, en general, en todas aquellas páginas donde sea introducida información sensible, como datos personales o bancarios.
- Evitar el secuestro de sesiones (session hijacking).
- Evitar los ataques XSS (Cross Site Scripting).
- Evitar los ataques XSRF (Cross Site Request Forgeries).
- Mantener tus sistemas actualizados con los últimos parches disponibles.
- Asegurarse de que la información de conexión a la base de datos está almacenada en un lugar lo suficientemente seguro.
- Mantener informado sobre las últimas técnicas de ataque y vulnerabilidades que afecten a la plataforma sobre la que trabajas.
- Conocer el manual The Google Browser Security Handbook.
Rendimiento
- Implementar el cacheado de páginas cuando sea necesario. Comprender y usar apropiadamente los mecanismos de cacheo HTTP.
- Optimizar las imágenes. Por ejemplo, no utilizar una imagen de 20 Kb. como mosaico de fondo.
- Conocer cómo comprimir el contenido de las páginas con gzip.
- Echar un vistazo al sitio Yahoo Exceptional Performance, donde se muestran directrices y buenas prácticas para mejorar el rendimiento de sitios web. Utilizar herramientas como YSlow.
- Utilizar la técnica de CSS Sprites para las pequeñas imágenes (como las que encontramos en las barras de herramientas), con objeto de minimizar el número de peticiones HTTP.
- Los sitios web de alto tráfico deberían considerar el despliegue de componentes en distintos dominios para optimizar la descarga en paralelo de los mismos.
- En general, minimizar el número total de peticiones HTTP necesarias para que el navegador muestre las páginas.
SEO
- Utilizar direcciones URL amigables para los buscadores. Por ejemplo, utilizar direcciones del tipo "ejemplo.com/paginas/titulo-del-articulo" en lugar de "ejemplo.com/index.php?page=45".
- No utilizar enlaces que digan "pulse aquí". Estarías creando sitio web poco optimizado para buscadores, a la vez que complicando las cosas para los usuarios que utilizan lectores de pantalla.
- Crear un mapa del sitio en XML (sitemap).
- Utilizar
<link rel="canonical" ... />
Cuando tengas múltiples URLs que apunten a un mismo contenido. - Utilizar las herramientas disponibles en www.google.com/webmasters.
- Instalar Google Analytics desde el principio.
- Conocer cómo funcionan los rastreadores de los buscadores y el archivo robots.txt.
- No maquetar con tablas; Google generalmente valorará positivamente el marcado HTML semántico y la maquetación con CSS.
- Si tienes contenido no textual en la página, utiliza en el sitemap las extensiones de Google para audio, video, etc. Hay alguna información sobre ello en la respuesta de Tim Farley.
Tecnología
- Entender el protocolo HTTP; conocer cosas como GET, POST, sesiones, cookies, y saber lo que significa e implica su naturaleza "sin estado" (stateless).
- Escribir el código (X)HTML y CSS conformes a las especificaciones de la W3C, y asegurarse de que validan. El objetivo es evitar las particularidades de los navegadores, a la vez que se facilita enormemente la navegación utilizando browsers no estándar como lectores de pantalla o dispositivos móviles.
- Comprender cómo se procesa el código javascript en los navegadores. Mover los scripts al final de las páginas.
- Comprender cómo funciona el sandbox de javascript, especialmente si pretendes utilizar iframes.
- Asegurarse de que javascript puede ser deshabilitado sin que la página deje de funcionar. AJAX debe ser una extensión, y no la base sobre la que se construya un sitio. Aunque la mayoría de usuarios lo tengan activado, recordar que existen muchos y muy populares dispositivos en los que no funcionará correctamente.
- Entender la diferencia entre las reflexiones 301 y 302 (esto también es un aspecto SEO).
- Aprender tanto como sea posible sobre la plataforma en la que será desplegado el sitio web en producción.
- Considerar el uso de un reseteador de CSS.
- Considerar herramientas como jQuery, que oculta muchas de las particularidades de los distintos navegadores utilizando javascript para la manipulación del DOM.
Corrección de errores
- Entender que pasarás el 20% del tiempo codificando y el 80% restante manteniéndolo, por tanto codifica apropiadamente.
- Configurar un buen sistema de notificación y gestión de errores.
- Habilitar sistemas para que los usuarios puedan contactar contigo y trasladarte críticas y sugerencias.
- Documentar cómo funciona la aplicación para facilitar el futuro soporte y mantenimiento del sistema.
- Poner a funcionar el sistema primero en Firefox y después en Internet Explorer.
- Hacer copias de seguridad frecuentes.
Publicado en: Variable not found.
Publicado por José M. Aguilar a las 11:56 p. m.
Etiquetas: buenas prácticas, desarrollo, recomendaciones, web
Hace unas semanas, en el post Cambiar la ubicación de las vistas en ASP.NET MVC estuvimos viendo cómo era posible aprovechar la flexibilidad del framework para saltarse las convenciones respecto a la ubicación de los archivos de vistas (.aspx, .ascx y .master).
En esta ocasión vamos a seguir profundizando en los puntos de extensión del framework, centrándonos en la facilidad con la que podemos modificar el ControllerFactory
, que es el componente encargado de localizar y crear las instancias de los controladores que deben procesar las peticiones.
Y vamos a ilustrarlo con un ejemplo, en el que desmontaremos otra de las convenciones del framework MVC: el nombre de los controladores. Como sabemos, cuando se recibe una petición que según su ruta debe ser procesada por un controlador llamado XYZ, el motor por defecto intentará instanciar una clase denominada XYZController
. Lo que vamos a hacer es retocar este comportamiento para que nuestros controladores puedan denominarse “ControladorDeXYZ
”, un nombre mucho más acertado en nuestro idioma.
En este post veremos cómo podemos modificar la forma en que este componente localiza las clases de controladores y adaptarla a nuestras preferencias.
Pero antes, recuerda:
Saltarse las convenciones = malo
Hazlo sólo cuando realmente esté justificado... o por diversión, como es el caso ;-)
Lo que vamos a hacer en el post no es una implementación eficiente, y por supuesto no es válida para un entorno de producción; se trata simplemente de un experimento que demuestra la facilidad para sustituir ciertos componentes del framework, y la flexibilidad que nos aporta. Los conceptos que vamos a tratar pueden ser utilizados con otros fines, como facilitar la inyección de dependencias en controladores, que probablemente veamos en un futuro post.
Y ahora, al tema…
1. El proceso básico de la petición
Antes de empezar la faena, es conveniente estudiar un poco el funcionamiento del framework; así podremos entender mejor qué estamos tocando.
Cuando se recibe una petición, su tratamiento pasa a través de una serie de componentes que se encargan de procesarla a distintos niveles siguiendo el ciclo de vida definido para el framework. Así, una vez que el sistema de enrutamiento ha terminado su tarea detectando la información presente en la URL y determinando, por tanto, su destino, utilizará un manejador MvcHandler
para continuar procesando la petición desde el método ProcessRequest()
.
La porción de código de ASP.NET MVC framework donde se define este método es la siguiente (en el archivo MvcHandler.cs
, recordad que el código fuente está disponible en Codeplex):
1: protected internal virtual void ProcessRequest(HttpContextBase httpContext)
2: {
3: [...]
4:
5: // Get the controller type
6: string controllerName =
7: RequestContext.RouteData.GetRequiredString("controller");
8:
9: // Instantiate the controller and call Execute
10: IControllerFactory factory =
11: ControllerBuilder.GetControllerFactory();
12:
13: IController controller =
14: factory.CreateController(RequestContext, controllerName);
15:
16: if (controller == null)
17: {
18: throw new InvalidOperationException(...); // Simplificado
19: }
20: try
21: {
22: controller.Execute(RequestContext);
23: }
24: finally
25: {
26: factory.ReleaseController(controller);
27: }
28: }
Resumidamente, podríamos decir que el sistema procesa las peticiones siguiendo estos pasos:
- en primer lugar, obtiene el nombre del controlador desde el contexto de la petición (normalmente desde la ruta). En el código anterior, se guarda en la variable
controllerName
. - a continuación obtiene una instancia de la factoría de controladores desde la clase
ControllerBuilder
. una vez obtenida la factoría según el paso anterior, se le pide mediante una llamada a su método
CreateController()
que cree el controlador que procesará la petición, enviándole como parámetro el nombre obtenido anteriormente.- y por último, se invoca al método
Execute
del controlador para que realice las acciones oportunas, liberando al final los recursos utilizados mediante una llamada aReleaseController
.
Como en otras muchas partes del framework, se puede observar en el código anterior la utilización de interfaces en lugar de clases para los elementos que intervienen en el proceso, lo que da pistas sobre la flexibilidad de ASP.NET MVC: casi cualquier elemento puede ser sustituido por otro siempre que se cumpla el contrato definido.
2. La factoría de controladores, a corazón abierto
Visto el procedimiento anteriormente descrito, está claro que la lógica de localización e instanciación del controlador es responsabilidad de las factorías de controladores, y más exactamente del método
que éstas deben implementar.CreateController()
ASP.NET MVC utiliza como factoría la clase DefaultControllerFactory
de forma predeterminada, sin embargo, nada en el código anterior obliga a que esto sea así. Si logramos crear una nueva factoría que implemente el interfaz IControllerFactory
e indicamos al framework que la utilice, ya casi tendremos el trabajo hecho.
En el código de la clase DefaultControllerFactory
(la factoría predeterminada), se puede observar que el proceso de creación está compuesto por dos pasos; en el primero de ellos se obtiene el tipo de controlador mediante una llamada a GetControllerType()
, mientras que en el segundo se obtiene una instancia de dicho tipo llamando a GetControllerInstance()
, que es la que retorna el método:
1: public virtual IController
2: CreateController(RequestContext requestContext, string controllerName)
3: {
4: [...] // Simplificado
5: Type controllerType = GetControllerType(controllerName);
6: IController controller = GetControllerInstance(controllerType);
7: return controller;
8: }
Dado que lo único que queremos sustituir es el mecanismo de localización, lo más sencillo es crear nuestra nueva factoría, a la que llamaremos AcmeControllerFactory
, heredando de DefaultControllerFactory
y sobrescribir el método GetControllerType
, que afortunadamente es virtual.
El código completo para esta nueva clase es el siguiente:
1: public class AcmeControllerFactory: DefaultControllerFactory
2: {
3: protected override Type GetControllerType(string controllerName)
4: {
5: Type r = base.GetControllerType(controllerName);
6: if (r == null)
7: {
8: Assembly current = Assembly.GetExecutingAssembly();
9: r = (from t in current.GetTypes()
10: where
11: (
12: t.Name.Equals("ControladorDe" + controllerName,
13: StringComparison.InvariantCultureIgnoreCase)
14: && t.IsPublic
15: && !t.IsAbstract
16: && typeof(IController).IsAssignableFrom(t)
17: )
18: select t).FirstOrDefault();
19: }
20: return r;
21: }
22: }
Como podemos observar, lo primero que hacemos es intentar localizar el controlador con el nombre que nos llega en el parámetro, pero utilizando el método propuesto por la factoría por defecto, es decir, llamando al método GetControllerType()
original. Es decir, vamos a ser al menos algo respetuosos con las convenciones de nombrado existentes ;-) … primero intentaremos localizar el controlador ciñéndonos a ellas, y sólo si no tenemos éxito aplicaremos nuestro propio criterio de nombrado.
Así, ante una petición rutada hacia el controlador Cliente,
primero buscaremos la clase ClienteController
(según la convención), y si no existe es cuando intentaremos localizar un tipo llamado ControladorDeCliente
. Obviamente, podríamos hacerlo al revés, es decir, buscar primero según nuestro criterio de nombrado y si no tenemos éxito buscar utilizando el estándar, o bien ni siquiera intentar esta última opción.
Por tanto, si el método por defecto no es capaz de encontrar un controlador correspondiente a dicha denominación es cuando ejecutamos nuestra lógica adicional, que consiste en buscar en el ensamblado actual, mediante una consulta LINQ, aquellas clases cuyo nombre corresponda con el patrón que pretendemos emplear (“ControladorDe”+controllerName
), y que sean públicas, instanciables, e implementen el interfaz IController
.
No se han implementado optimizaciones, como la inclusión de un caché, que permitan mejorar el rendimiento en esta consulta. Cada petición deberá recorrer, en el peor de los casos, todo el ensamblado en busca de un controlador apropiado.
Tampoco se ha implementado ningún tipo de resolución de conflictos; si existe más de un controlador con el mismo nombre en distintos namespaces, se retornará el primero que se encuentre.
Eso os lo dejo de deberes ;-)
3. Sustituir la factoría de controladores
Ya tenemos creada la clase AcmeControllerFactory,
nuestra propia factoría de controladores, y está lista para entrar en acción. Pero, ¿cómo le decimos al framework que queremos utilizar una factoría de controladores distinta a la predeterminada?
Volvamos a estudiar el código de procesado de las peticiones que vimos anteriormente. Como se puede observar, el IControllerFactory
a utilizar es obtenido desde la clase ControllerBuilder
:
1: protected internal virtual void ProcessRequest(HttpContextBase httpContext)
2: {
3: [...]
4: // Instantiate the controller and call Execute
5: IControllerFactory factory =
6: ControllerBuilder.GetControllerFactory();
7:
8: IController controller =
9: factory.CreateController(RequestContext, controllerName);
10: [...]
11: }
Y aquí de nuevo entra en juego la flexibilidad del diseño de ASP.NET MVC: ControllerBuilder
viene preparada para que podamos sustituir muy fácilmente la factoría a instanciar, por lo que podemos indicarle el tipo concreto que queremos que utilice.
En el siguiente código estamos indicando al ControllerBuilder
que nuestra factoría por defecto, es decir, la clase encargada de buscar e instanciar los controladores, será AcmeControllerFactory.
Como se define en la inicialización de la aplicación (Application_Start
del global.asax
), todas las peticiones utilizarán esta factoría para crear los controladores:
1: protected void Application_Start()
2: {
3: RegisterRoutes(RouteTable.Routes);
4: ControllerBuilder
5: .Current
6: .SetControllerFactory(typeof(AcmeControllerFactory));
7: }
4. Probar que realmente funciona
Podemos comprobar el funcionamiento de todo este invento de forma muy sencilla. Una vez seguidos los pasos anteriores, basta con crear un nuevo controlador que ya atienda a nuestra propia convención de nombrado, como el siguiente:
1: [HandleError]
2: public class ControladorDeCliente : Controller
3: {
4: public ActionResult Listar()
5: {
6: return View();
7: }
8:
9: public ActionResult Editar()
10: {
11: return View();
12: }
13: }
Creamos, asimismo, una vista “Listar.aspx” y otra “Editar.aspx” en la carpeta “Views\Cliente” para que el motor pueda localizarlas y podamos ver algún resultado en pantalla. A partir de este momento, ejecutando el proyecto, podremos comprobar cómo si introducimos la URL http://localhost:tupuerto/Cliente/Listar
el flujo de ejecución pasará por el método Listar()
visto anteriormente. También podemos invocar a la acción Editar()
, y el resultado será el esperado.
Y para los perezosos, ahí va el código fuente del proyecto (requiere Visual Studio 2008 o Web Developer Express con SP1 y ASP.NET MVC 1.0):
Publicado en: Variable not found.
Lo sé. Estoy desactualizado... pero me sigue gustando Office 2003, como supongo que ocurre a mucha gente todavía. Y de hecho, continúo creando mis documentos con Microsoft Word 2003.
Sin embargo, a pesar del largo camino que hemos recorrido juntos, aún no he sido capaz de verle sentido al modo diseño de lectura, esa extraña forma de presentar los documentos por defecto al abrirlos, o que podemos activar voluntariamente desde el menú “edición”. ¿A quién se le ocurrió esa idea? ¿Alguien la ha visto útil alguna vez? ¿Tiene, quizás, alguna utilidad oculta que no he sido capaz de intuir en todos estos años?
Bueno, en cualquier caso, podemos conseguir muy fácilmente que no utilice el diseño de lectura en el momento de abrir los documentos, accediendo al cuadro de diálogo de configuración (Herramientas >> Opciones) y desmarcando el check “Permitir el inicio en diseño Lectura”:
Sencillo, ¿eh? Desde luego, no tengo excusa para haber aguantado este odioso comportamiento durante más de un lustro…
Publicado en: Variable not found.
He recibido algunos mensajes de lectores de Variable not found que quieren iniciarse en ASP.NET MVC, pero no saben por dónde empezar, y me sugieren que escriba algunos posts que expliquen desde cero este nuevo framework. Posiblemente lo haga algún día, pero mientras tanto, les he recordado que existen recursos gratuitos que pueden ser de mucha utilidad para dar los primeros pasos (e incluso profundizar un poco) en esta tecnología.
Por ejemplo, recientemente han aparecido una gran cantidad de libros sobre ASP.NET MVC, y de la mayoría de ellos se pueden descargar capítulos gratuitos que, además de ayudarnos a decidir cuál de ellos puede ser de nuestro interés, tienen valor por la información que nos pueden aportar. Como siempre, el problema es la dispersión de esta información, por lo que he decidido hacer esta recopilación para tenerlos todos a mano. Conforme vaya descubriendo nuevos ejemplares iré ampliando la lista; y por supuesto, si conocéis alguno que no esté aquí, me lo comentáis y lo añadimos.
Eso sí, todos en inglés, aunque al ser muy técnicos creo que son fáciles de comprender.
Pro ASP.NET MVC Framework Autor: Steve Sanderson Post de presentación: Now Published Pro ASP.NET MVC Framework (Apress) « Steve Sanderson’s blog Capítulo gratuito: Chapter 2: Your First ASP.NET MVC Application (23 páginas)En este capítulo, el autor muestra muy detalladamente, prácticamente paso a paso, cómo crear nuestra primera aplicación simple con ASP.NET MVC. En primer lugar, crea un proyecto muy básico mediante el cual explica los fundamentos básicos de la programación siguiendo este modelo, y a continuación entra en la creación de una mini-aplicación con entrada de datos, validaciones y lógica simple. | |
Professional ASP.NET MVC 1.0 Autores: Scott Hanselman, Rob Conery, Phil Haack y Scott Guthrie Capítulo gratuito: Chapter 1: Nerdinner (192 páginas) Este extenso capítulo describe la creación de un sitio web medianamente complejo, www.nerddinner.com, utilizando gran cantidad de tecnologías relacionadas con el framework MVC como filtros, Ajax, LinqToSql, pruebas unitarias, etc. Muy recomendable, imprescindible. | |
ASP.NET MVC 1.0 Quickly Autor: Maarten Balliauw Post de presentación: Announcing my book- ASP.NET MVC 1.0 Quickly Capítulo gratuito: Chapter 2: Your first ASP.NET MVC application (20 páginas) | ASP.NET MVC in Action Autores: Jeffrey Palermo, Ben Scheirman, Jimmy Bogard Post de presentación: Announcing ASP.NET MVC in Action (from Manning) - Jeffrey Palermo (.com) - CodeBetter.Com Recurso gratuito: Getting Started with the ASP.NET MVC Framework (Green Paper – PDF) (18 páginas) (El enlace a este documento te lo envían por correo electrónico tras facilitar tu dirección). Se trata de otra introducción al framework, el sistema de rutas, controladores y vistas partiendo desde cero. Capítulo gratuito: Chapter 9: AJAX in ASP.NET MVC (21 páginas) |
ASP.NET MVC Framework Unleashed Autor: Stephen Walther Capítulos gratuitos: el autor ha publicado varios capítulos en su blog, y los retirará en cuanto el libro esté disponible en Amazon, así que daos prisa que los contenidos son excelentes. | |
Beginning ASP.NET MVC 1.0 Autores: Simone Chiaretta, Keyvan Nayyeri Capítulo gratuito: Chapter 9: Testing ASP.NET MVC Applications (38 páginas) |
Publicado por José M. Aguilar a las 12:00 a. m.
Etiquetas: asp.net, aspnetmvc, desarrollo, libros, servicios on-line
El control de errores en aplicaciones web es fundamental si queremos ofrecer un interfaz robusto y amigable para los usuarios en cualquier situación. No hay nada más frustrante para un usuario que una pantalla de error con contenidos indescifrables y que no le aportan alternativas de salida.
El framework ASP.NET MVC nos ofrece mecanismos de control de errores muy potentes basada en la utilización del atributo HandleError,
el cual definirá la vista que será mostrada al usuario cuando se produzca alguna excepción no controlada en el código de los controladores, siempre que en el web.config
se haya activado el uso de errores personalizados mediante la propiedad CustomErrors
.
En este post vamos a profundizar en el uso del atributo HandleError,
comentando cómo se implementa en el controlador, su ámbito de actuación, los parámetros que ofrece y la forma de crear las vistas para mostrar los errores de forma amigable.
El controlador
HandleError
puede ser declarado tanto a nivel de clase (controlador) como a nivel de acción. En el primer caso, se establecerá el comportamiento general para todas las acciones del controlador, mientras que en el segundo será aplicable sólo a la acción a la que se asocie el atributo:
// Control de errores a nivel de clase de controlador,
// que será aplicado a todas las acciones del mismo.
[HandleError()]
public class HomeController : Controller
{
...
}
// Control de errores a nivel de acción concreta...
[HandleError(ExceptionType=typeof(ArgumentException), View="ArgumentError")]
public ActionResult Calculate(int a, int b)
{
ViewData["results"] = calculateSomething();
return View();
}
En realidad, el comportamiento definido en el atributo HandleError
a nivel de clase también se aplicará a los errores generados por las vistas u otros resultados (ActionResult
) retornados por los controladores. Es decir, sobre el segundo de los ejemplos anteriores, la vista “ArgumentError” (que existirá en un archivo llamado ArgumentError.aspx) será invocada cuando la excepción ArgumentException
sea lanzada bien por el propio controlador, o bien por la vista “Calculate” que retorna por defecto.
Un último detalle sobre esto: el atributo HandleError
puede ser especificado tantas veces como necesitemos sobre la misma acción o controlador, indicando comportamientos para distintos tipos de excepción. El atributo que se tendrá en cuenta cuando se produzca un error será el primero que se encuentre cuyo tipo de excepción (parámetro ExceptionType) sea compatible con la excepción lanzada.
El manejador de errores que se empleará en una acción será el primero que corresponda al tipo de excepción producida, teniendo en cuenta tanto los atributos que adornan la acción como los que acompañan a su controlador, y siempre según un orden preestablecido.
Veamos con más detenimiento los parámetros que admite la declaración del atributo.
Parámetros de HandleError
[HandleError(
ExceptionType=typeof(DivisionByZero),
View="ErrorPersonalizado",
Master="MaestraErrores",
Order = 0)
]
public ActionResult Index()
...
- ExceptionType permite indicar el tipo de excepción que se pretende controlar. Por defecto, el sistema entenderá que la regla se refiere al tipo base
Exception
, por lo que se aplicará a todos los errores que se generen, pues todas las excepciones heredan de esta clase. - View, el nombre de la vista que será mostrada al usuario. Por defecto se tomará el valor “Error”, por eso en la plantilla de proyectos ASP.NET MVC ya existe una vista con este nombre.
- Master, la página maestra con la que será renderizada la vista, independientemente de lo que tenga declarado ésta.
- Order, un valor numérico (por defecto –1, el más prioritario) que indica la prioridad de aplicación de esta regla cuando el sistema encuentre varios atributos
HandleError
aplicables al mismo elemento y que puedan presentar conflictos. Los valores más pequeños, Por ejemplo, si no se indicara este parámetro en el siguiente caso, el resultado dependería del orden de declaración, lo cual no es demasiado recomendable:
[HandleError(Order=10, View="ErrorGenerico")]
public class HomeController : Controller
{
...
[HandleError (ExceptionType=typeof(DivisionByZero),
View="OperacionIncorrecta", Order=1)]
public ActionResult Calculate()
...
Como puede intuirse, esto hará que en caso de producirse una división por cero, se muestre la vista “OperacionIncorrecta” y no la “ErrorGenerico”.
Cada vez que utilicemos HandleError
es conveniente tener muy en cuenta la prioridad (definida en la propiedad Order
), el alcance (las excepciones a tratar, definidas en la propiedad ExceptionType
), así como los valores por defecto en cada caso. Esto evitará comportamientos misteriosos del sistema una vez se produzcan errores en tiempo de ejecución.
Acceso desde la vista a la información del error
Ya hemos comentado anteriormente que la vista que será mostrada a los usuarios cuando se produzca un error será la indicada en el parámetro View
del atributo HandleError
, o la vista "Error", si este parámetro no es informado. Sea cual sea, el archivo nombredevista.aspx deberá estar localizable por el motor de vistas en el momento de su lanzamiento (por cierto, si no te gustan las ubicaciones por defecto, puedes ver cómo modificar la forma en la que se buscan las vistas en este post).
La vista de un error es una página .aspx normal, como una vista más de la web, pero con la particularidad de que puede recibir información sobre el error que ha provocado su presentación. De hecho, se trata de una vista tipada que hereda de ViewPage<System.Web.Mvc.HandleErrorInfo>
, de forma que la propiedad Model
será del tipo HandleErrorInfo
, clase que nos ofrece completa información sobre el origen del problema:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<System.Web.Mvc.HandleErrorInfo>" %>
<asp:Content ID="errorTitle" ContentPlaceHolderID="TitleContent" runat="server">
Error en el sistema
</asp:Content>
<asp:Content ID="errorContent" ContentPlaceHolderID="MainContent" runat="server">
<h2>
Ups, se ha producido un ligero inconveniente...
</h2>
<p>
La acción <%= Model.ActionName %>
del controlador <%= Model.ControllerName %>
ha lanzado la excepción <%= Model.Exception.GetType().Name %> con
el mensaje "<%= Model.Exception.Message %>".
</p>
</asp:Content>
A pesar de no ser un buen ejemplo como pantalla del error amigable para el usuario ;-), el código anterior ilustra cómo es posible acceder desde la vista a los datos del contexto del error proporcionados por el entorno, y cómo la clase HandleErrorInfo
nos ofrece una información sobre la acción en la que se ha lanzado la excepción, el controlador en el que se encuentra la misma, y lo más interesante, nos ofrece en la propiedad Exception
la excepción producida, por lo que tendremos acceso a su tipo, descripción e incluso al estado de la pila de llamadas en el momento de producirse el error.
Publicado en: www.variablenotfound.com
Publicado por José M. Aguilar a las 11:59 p. m.
Etiquetas: asp.net, aspnetmvc, c#, desarrollo, programación, web