Secretos internos de ASP.NET – Parte II


Ciclo vital de las páginas

ASP.NET
2.0 presenta dos importantes cambios en el ciclo vital de una página
ASP.NET. En primer lugar, ASP.NET 2.0 expone nuevos eventos para
admitir nuevas características, entre las que se incluyen páginas
principales, personalización y la compatibilidad integrada con
dispositivos móviles. En segundo lugar, ASP.NET 2.0 introduce el envío
cruzado entre páginas para formularios Web.

Nuevos eventos

ASP.NET 2.0 proporciona una pila de métodos de ciclo vital de las páginas más granular en comparación con ASP.NET 1.x.
Los nuevos métodos proporcionan un mayor nivel de control al
desarrollador Web. Se puede obtener acceso a estos eventos a través del
objeto Page de cualquier página ASP.NET.

La tabla 1 muestra la lista completa de métodos. La columna Método muestra el nombre real del método de evento y la columna ActivoPostBack. Por ejemplo, se puede utilizar el nuevo método TestDeviceFilter
para determinar el filtro de dispositivo aplicado y utilizar esta
información para decidir cómo se mostrará la página. Por otra parte, el
nuevo método LoadControlState sólo se desencadena durante una devolución de datos. Este método se puede omitir (junto con SaveControlState)
para crear esquemas alternativos de serialización para guardar y
restaurar el estado de control durante una devolución de datos.
indica si el evento siempre está activo o sólo está activo durante las acciones

Si se consideran
los detalles de bajo nivel del ciclo vital de las páginas, podemos ver
que muchas de las características que están disponibles en ASP.NET 2.0,
como los temas y la personalización, estarían implementados de manera
natural. Por ejemplo, un tema se procesaría en el evento IntializeThemes, mientras que los datos de personalización se cargarían en LoadPersonalizationData y posteriormente se aplicarían con el método ApplyPersonalization.
Observe que el orden de los métodos es extremadamente importante para
conocer los elementos de la interfaz de usuario que determinarán el
aspecto y el funcionamiento final de las aplicaciones Web.

Envío cruzado entre páginas

El otro cambio importante en el ciclo vital de las páginas se refiere a la devolución de eventos y Web Forms. En ASP.NET 1.x,
Web Forms realiza la devolución de manera automática a su página host.
Es decir, cuando un usuario envía un formulario, los datos del
formulario siempre se devuelven a la página que contenía el formulario
original. Esta decisión de diseño permite un fácil almacenamiento del
estado de control, pero limita la capacidad del desarrollador de
realizar operaciones más complejas.

En ASP.NET
2.0, los controles de Web Forms tienen una nueva propiedad que permite
al desarrollador decidir adonde se deben enviar los datos del
formulario cuando se realiza una acción de envío. En la mayoría de los
casos, el mecanismo de devolución de datos será la opción deseada y,
por tanto, sigue siendo la opción predeterminada. Sin embargo, si el
desarrollador desea enviar los datos de una forma diferente, ahora es
posible.

Puede, por
ejemplo, crear un asistente de varias páginas compuesto por varios
formularios diferentes. Cada formulario remite a la siguiente página de
la secuencia, hasta que el usuario alcanza una página de resumen en la
que se puede realizar la validación final. Se puede obtener acceso a
los datos de la última página en el contexto actual mediante el objeto PreviousPage. El objeto PreviousPage

almacena los datos validados de la página anterior para utilizarlos en
la página actual. Gracias a este objeto, el envío cruzado entre páginas
no sacrifica la persistencia del control. Si el usuario necesita
realizar una copia de seguridad de un formulario de la secuencia, los
datos de la página estarán accesibles de manera inmediata y el usuario
no tendrá que volver a introducir todos los datos.

Extensibilidad

ASP.NET
se diseñó en un principio como un marco de trabajo abierto. Es decir,
muchos de los módulos y de los componentes que forman ASP.NET pueden
ampliarse, modificarse o reemplazarse para adaptarlos a sus necesidades
concretas. En ASP.NET 2.0, la naturaleza extensible del marco de
trabajo queda claramente ilustrada con los nuevos HTTPHandlers y HTTPModules que ahora son una parte estándar del marco de trabajo.

La canalización de solicitudes

En
ASP.NET, las solicitudes se pasan desde el servidor Web a través de un
filtro de interfaz de programación de aplicación de servidor de
Internet (ISAPI, Internet Server Application Programming Interface)
hacia el tiempo de ejecución real de ASP.NET.

Cuando IIS recibe
una solicitud, la extensión se asigna a un filtro ISAPI de acuerdo con
la configuración de IIS. Las extensiones .aspx, .asmx, .asd y otras se
asignan a aspnet_isapi.dll, que es sencillamente un filtro ISAPI que
inicia el tiempo de ejecución de ASP.NET. Una vez que una solicitud
llega al tiempo de ejecución de ASP.NET, se inicia en el objeto HTTPApplication, que actúa como host de la aplicación Web ASP.NET. El objeto HTTPApplication:

  1. Lee los archivos de configuración del equipo y de la aplicación.
  2. Pasa la solicitud a través de una o varias instancias HTTPModule. Cada HTTPModule
    proporciona un servicio como el mantenimiento de sesiones,
    autenticación o mantenimiento de perfiles. Estos módulos devuelven la
    solicitud a HTTPApplication.
  3. Pasa la solicitud a un HTTPHandler
    en función del verbo y de la ruta de acceso. El verbo hace referencia
    al verbo HTTP utilizado en la solicitud (GET, POST, FTP, etc.) y la
    ruta de acceso hace referencia a una dirección URL dentro de la
    aplicación. Dependiendo de cómo se hayan configurado los controladores,
    la solicitud se puede procesar como una página ASP.NET (System.Web.UI.Page es una implementación de IHTTPHandler)
    o la solicitud puede desencadenar otra acción como la compilación por
    lotes de todas las páginas Web (precomiplation.asd desencadena PrecompHandler).

En
ASP.NET 2.0, este modelo permanece intacto; no obstante, se han
agregado nuevos módulos y controladores para proporcionar servicios
adicionales. Al igual que ocurre con ASP.NET 1.x, puede
extender, reemplazar o reconfigurar cualquier clase de controlador o
módulo para proporcionar su propia funcionalidad personalizada.

Nuevos módulos

Por supuesto, se han agregado nuevos HTTPModules
para admitir los nuevos servicios que se ofrecen en ASP.NET 2.0.
Concretamente, una aplicación ASP.NET con la configuración de módulos
predeterminada incluirá nuevos módulos para:

  • Id. de sesión: el mecanismo de identificación de sesiones se ha escindido del módulo Session de ASP.NET 1.x
    para proporcionar un mayor control sobre las cookies, la reescritura de
    direcciones URL y otras formas de generación de identificadores de
    sesión.
  • Administración de funciones: se ha
    agregado un nuevo módulo que proporciona servicios basados en funciones
    para admitir los nuevos mecanismos de identificación de usuarios. Este
    módulo ayuda a vincular las aplicaciones ASP.NET con la seguridad
    basada en funciones incorporada en .NET Framework.
  • Identificación anónima: las nuevas
    características de personalización admiten usuarios anónimos. Este
    módulo realiza un seguimiento de las características a las que puede
    obtener acceso un usuario anónimo y cómo se mantienen dichas
    características entre solicitudes.
  • Perfil: el módulo de perfiles está
    vinculado con el nuevo servicio de perfiles y ayuda a proporcionar un
    almacenamiento persistente de datos específico del usuario.
  • Contadores de página: ASP.NET 2.0
    incorpora un nuevo módulo para vincular con contadores de página y
    mejorar el análisis estadístico del tráfico Web.

Además
de estos nuevos módulos, se ha cambiado el comportamiento de algunos de
los módulos más antiguos: por ejemplo, el módulo de almacenamiento en
caché de la salida ahora admite las nuevas técnicas de almacenamiento
en caché que se describen más adelante en este artículo.

Nuevos controladores

Además
de estos nuevos módulos, ASP.NET 2.0 presenta nuevos controladores para
admitir las herramientas de configuración de aplicaciones y otras
nuevas características como la solicitud de compilación por lotes. El
más importante de los nuevos controladores incluye la familia ".axd"
que procesa las solicitudes de administración de sitios Web. Estos
controladores inician las herramientas de administración interna que
permiten a los desarrolladores configurar los usuarios ASP.NET así como
otras opciones de configuración. Entre los controladores de
administración se incluyen:

  • Administración Web: WebAdminHandler
    es la página principal del sitio Web administrativo. Este controlador
    proporciona el punto de partida para administrar aplicaciones Web
    ASP.NET 2.0.
  • Seguimiento: se ha mejorado ASP.NET 1.x TraceHandler y es el único controlador "axd" que estaba disponible en ASP.NET 1.x.
  • Recursos
    Web: ahora es posible configurar los recursos Web tras la
    implementación gracias a la nueva herramienta administrativa y a WebResourcesHandler.
  • Imágenes en caché: CachedImageServiceHandler ofrece compatibilidad para almacenar en caché componentes gráficos.
  • Contadores: SiteCountersHandler funciona con el módulo de contadores de páginas para ofrecer estadísticas de acceso para una aplicación ASP.NET 2.0.
  • Precompilación: como ya se ha mencionado, PrecompHandler se puede utilizar para compilar por lotes todas las páginas ASPX de una aplicación ASP.NET.
  • Exportación de elementos Web: WebPartExportHandler
    proporciona compatibilidad para almacenar y transferir diseños de
    elementos Web. Los elementos Web son un nuevo mecanismo para
    personalizar el aspecto y el contenido de una aplicación Web de tipo
    portal.

Como siempre, HTTPForbiddenHandler
está vinculado con todos los tipos de archivos que no hay que devolver
nunca. En ASP.NET 2.0, la lista de tipos de archivos prohibidos se ha
ampliado para incluir páginas principales, archivos de máscara y otros
nuevos componentes para desarrolladores.

Técnicas avanzadas de almacenamiento en caché

Una
manera de mejorar el rendimiento de cualquier aplicación Web es
almacenar en memoria caché el contenido estático. El contenido en caché
siempre se devuelve más rápidamente que el contenido recientemente
procesado. Sin embargo, el posible inconveniente es que el contenido en
caché puede quedarse obsoleto. ASP.NET 1.x admite varios tipos de almacenamiento en caché, entre los que se incluyen:

  • Nivel
    de página: cada página se puede almacenar en caché como un elemento
    completo o en función de los parámetros utilizados para obtener acceso
    a la página. La página en caché caduca después de un tiempo fijo.
  • Fragmento de página: si la página se creó con
    los controles del usuario (archivos .ascx), los controles del usuario
    se pueden almacenar en caché independientemente del resto del contenido
    de la página.
  • Almacenamiento en caché mediante programación:
    el desarrollador también puede almacenar en caché objetos, gracias a la
    API de caché. La API de caché ofrece la ventaja concreta de
    proporcionar una manera de crear varios tipos de dependencias para
    cuando es necesario limpiar la caché.

En
ASP.NET 2.0, el mecanismo de almacenamiento en caché de nivel de página
se ha extendido para admitir las dependencias de base de datos. Con una
dependencia de caché de base de datos, una página almacenada en caché
se puede vincular a una determinada tabla de una base de datos de SQL
Server. Cuando la tabla cambia, la caché caducará automáticamente.
Además, un desarrollador puede utilizar la sustitución tras la caché
para reemplazar parte del contenido almacenado en caché por contenido
actualizado. La sustitución tras la caché permite que una aplicación
utilice el almacenamiento en caché de nivel de página incluso cuando es
preciso generar dinámicamente parte de la página.

Invalidación de la caché de la base de datos

Para
la mayoría de los sitios Web orientados a datos, el almacenamiento en
caché puede ser un tema espinoso, especialmente en aquellas situaciones
que exigen el almacenamiento en caché y es necesario disponer de datos
actualizados. En ASP.NET 1.x, las páginas se pueden almacenar en
caché durante un período de tiempo y organizarlas por los parámetros de
entrada (cadena de consulta o parámetros POST):

Listado 5. Directiva de caché de salida de ASP.NET 1.x

<%@ outputcache duration="3600" varybyparam="ProdID" %> 

Por ejemplo, el código del listado 5 almacena una página en memoria caché durante una hora en función de la variable ProdID.
El problema que surge en el ejemplo anterior es qué hacer si los datos
empresariales relevantes se actualizan en otro sitio. Por ejemplo,
imaginemos una página de catálogo de productos almacenada en caché por
identificador de producto. Si la información acerca de este producto
(cantidad disponible o precio, por ejemplo) se actualiza desde un sitio
administrativo, se almacenarán en caché y se mostrarán a los clientes
datos incorrectos. Con la versión anterior de ASP.NET, para solucionar
este problema habría que eliminar manualmente la página de la caché
mediante Response.RemoveOutputCacheItem o esperar hasta que finalice el período de tiempo duration y permitir al sistema actualizar la página automáticamente.

ASP.NET
2.0 resuelve este problema ofreciendo compatibilidad con dependencias
de caché de bases de datos. Hay disponibles notificaciones de nivel de
tabla al trabajar con SQL Server 7 y 2000, y Microsoft SQL Server 2005
ofrecerá notificaciones en un nivel todavía más granular. Por ejemplo,
el siguiente código almacena en caché una página de productos durante
un período de hasta 1 hora, pero agrega una segunda dependencia en una
tabla de base de datos.

Listado 6. Ejemplo de caché de base de datos de ASP.NET 2.0

<%@ outputcache duration="3600" 
varybyparam="ProdID"
sqldependency="MyDatabase:Products" %>

Utilizando el nuevo atributo sqldependency, la página almacenada en caché caducará si se realiza algún cambio a la tabla de productos. El atributo sqldependency debe hacer referencia a un datasource que se haya configurado en el archivo web.config. A su vez, datasource identifica la conexión de base de datos y los parámetros necesarios para lograr que funcione la notificación de dependencias.

Dependencias de caché personalizadas

ASP.NET 2.0 incluye una implementación de CacheDependency, la clase SQLCacheDependency,
que es compatible con Microsoft SQL Server. La implementación de una
nueva dependencia de caché puede ser un proceso complicado, pero es
posible debido a la naturaleza extensible de ASP.NET 2.0. Es decir,
puede crear su propia clase CacheDependency para proporcionar una funcionalidad similar para otros sistemas de bases de datos como Oracle o Sybase.

Sustitución tras la caché

Para
aquellos casos en los que unos pocos elementos de la página sean
dinámicos pero la mayoría de la página podría utilizar el
almacenamiento en caché, ASP.NET 2.0 proporciona una característica
denominada sustitución tras la caché. Esta característica se utiliza
para informar al tiempo de ejecución de ASP.NET de que un elemento
concreto, mientras se encuentra en una página almacenada en caché, debe
volver a evaluarse antes de presentar la página al usuario.

Hay dos maneras de utilizar esta característica:

  • Llamar al nuevo método Response.writeSubstitution, pasándole una referencia a la función de devolución de llamada de sustitución.
  • Agregar un control <asp:substitution> a la página Web y establecer el atributo methodname en el nombre de la función de devolución de llamada.
  • Para ambas opciones es necesario agregar a la página una directiva @OutputCache, que especifique la duración y la ubicación de la dependencia.

Implementación de la sustitución tras la caché

Es
posible crear controles que detecten la sustitución tras la caché para
aprovechar esta característica. Un ejemplo de esto es el control AdRotator. El listado 7 ilustra una página que:

  • Recupera datos de la tabla de autores de la base de datos Pubs.
  • Enlaza los datos con un control GridView.
  • Muestra anuncios desde AdRotator.
  • Muestra la hora en la que se creó la página en un control de etiqueta.

También se ha agregado al ejemplo un control <asp:substitution> (líneas en negrita del listado). Este control tiene su atributo methodname establecido en uncachedUpdate
(un método que devuelve como salida una cadena, en este caso, la hora
actual). El control de sustitución devolverá la hora correcta,
independientemente de lo que se haya almacenado en caché.

Listado 7. Código fuente de PostCache.ASPX

<%@ Page language="c#" Codebehind="PostCache.ASPX.cs" 
AutoEventWireup="true" Inherits="WebApplication1.PostCache" %>
<%@ outputcache duration="30" varybyparam="none" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm1</title>
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<DIV style="DISPLAY: inline;
Z-INDEX: 101; LEFT: 32px; WIDTH: 160px;
POSITION: absolute; TOP: 24px; HEIGHT: 8px"
align="right" ms_positioning="FlowLayout">
this page was created at:
</DIV>
<asp:Label id="CreatedTime"
style="Z-INDEX: 102; LEFT: 200px; POSITION: absolute;
TOP: 24px" runat="server" Width="120px" Height="16px">
</asp:Label>
<asp:substitution id="UpdatedTime" methodname="uncachedUpdate"
style="Z-INDEX: 103; LEFT: 200px; POSITION: absolute;
TOP: 48px" runat="server" Width="112px" Height="11px">
</asp:substitution>
<DIV style="DISPLAY: inline; Z-INDEX: 104; LEFT: 32px;
WIDTH: 160px; POSITION: absolute; TOP: 48px;
HEIGHT: 16px" align="right" ms_positioning="FlowLayout">
and last updated at:
</DIV>
<asp:AdRotator id="Ads" style="Z-INDEX: 105; LEFT: 312px;
POSITION: absolute; TOP: 16px" runat="server"
Width="80px" Height="60px" AdvertisementFile="img/Ads.xml">
</asp:AdRotator>
</form>
</body>
</HTML>

El archivo de código subyacente de esta página
contiene el evento necesario para admitir la sustitución tras la caché
en el método uncachedUpdate. Observe que el método Page_Load
informa de la hora en la que se cargó la página, por lo que podemos
determinar cuándo se está produciendo un almacenamiento en caché.

Listado 8. PostCache.ASPX.cs

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace WebApplication1 {
public class PostCache : System.Web.UI.Page {
protected System.Web.UI.WebControls.Label CreatedTime;
protected System.Web.UI.WebControls.Label UpdatedTime;
protected System.Web.UI.WebControls.AdRotator Ads;

private void InitializeComponent() {
this.Load += new System.EventHandler(this.Page_Load);
}

private void Page_Load(object sender, System.EventArgs e) {
CreatedTime.Text = DateTime.Now.ToShortTimeString();
}

protected String uncachedUpdate() {
return DateTime.Now.ToShortTimeString();
}
}

}

Sustitución tras la caché en acción

La primera vez que se ejecuta la aplicación, podemos ver que las horas
de "creación de la página" y "última actualización" son iguales.

En las posteriores
llamadas a la misma página podemos ver el efecto de la sustitución tras
la caché. Aunque la hora de creación de la página y la imagen siguen
siendo las mismas, la hora de última actualización cambia.

Tanto la hora de creación como la imagen de adRotator
permanecen constantes como consecuencia de la directiva de
almacenamiento en caché. La página se almacena en caché durante 30
segundos. Una vez que ya ha pasado este tiempo, tanto la hora de
creación como adRotator se actualizarán en la siguiente solicitud. Sin embargo, el control <asp:substitution>, que llama al método uncachedUpdate(), se actualizará cada vez que se solicite la página independientemente de su estado de almacenamiento en caché.

Con
una correcta manipulación de la sustitución tras la caché, los
desarrolladores pueden aumentar notablemente el rendimiento de sus
aplicaciones Web actualizando únicamente los puntos dinámicos de sus
páginas. Junto con la invalidación de la caché de base de datos y las
actualizaciones asíncronas de páginas, las aplicaciones Web
desarrolladas con ASP.NET 2.0 acabarán con la mayoría de las
limitaciones impuestas por la tradicional arquitectura Web de solicitud
y respuesta.

Rendimiento

Teniendo
en cuenta los cambios en la infraestructura y las características
adicionales de ASP.NET 2.0, la pregunta que cabe plantearse es, ¿qué
velocidad ofrece ASP.NET 2.0? Aunque todavía no hay indicadores de
rendimiento ya que ASP.NET 2.0 todavía está en proceso de desarrollo,
se ha realizado un importante esfuerzo para garantizar que el
rendimiento se mantiene o se mejora en todos los aspectos del marco de
trabajo ASP.NET 2.0.

Mejor canalización de solicitudes

Un
punto en el que todos los desarrolladores verán un mejor rendimiento es
en la canalización de solicitudes. A pesar de la incorporación de
muchos nuevos enlaces de eventos, la pila de solicitudes básica de
ASP.NET es hasta un 30% más rápida que la de ASP.NET 1.1. Puede evaluar
las mejoras en el rendimiento creando una página sencilla que muestre
"Hola mundo". Como la página no tiene ninguna funcionalidad avanzada,
puede probar directamente las canalizaciones HTTPHandler y HTTPModule,
así como el complemento ISAPI que conecta ASP.NET 2.0 con IIS.
Independientemente de la versión de IIS que esté utilizando, debe
apreciar una mejora del rendimiento ya que este código se ha optimizado
para conseguir un funcionamiento más rápido.

Mejor administración de la memoria con IIS 6.0

Algunas
de las mejoras de rendimiento de ASP.NET 2.0 sólo vienen junto con IIS
6.0. Por ejemplo, en IIS 6.0, la memoria de trabajo para el proceso de
trabajo se ha reducido en aproximadamente un 50% en las pruebas de
carga; para estas se han utilizado 100 usuarios simultáneos requiriendo
una página con varios controles. Esto significa que, para un
determinado servidor, el sistema operativo utiliza aproximadamente la
mitad de los recursos que antes eran necesarios.

En
una prueba diseñada para imitar una página ASP.NET moderadamente
compleja, la carga del sistema (memoria y uso de la CPU) descendió
drásticamente en comparación con la misma página ejecutándose en IIS
5.0. Esta mejora concreta del rendimiento se consiguió moviendo los
búferes de respuesta de la memoria administrada a la memoria nativa. Al
eliminar la necesidad de asignar memoria administrada a una determinada
respuesta, ASP.NET 2.0 elimina un cuello de botella de recursos y
genera respuestas más rápidas para cada solicitud.

Otras
mejoras de rendimiento aprovechan la estrecha integración de IIS 6.0
con el núcleo del sistema operativo Windows. IIS 6.0 realiza parte de
su almacenamiento en caché y en búfer a nivel de núcleo, lo que
proporciona un mayor rendimiento para todas las aplicaciones Web,
incluidas ASP.NET.

Otras mejoras

Como desarrollador, esperará que ASP.NET 2.0 funciona tanto o más rápido que ASP.NET 1.x.
Ahora que se ha creado la funcionalidad básica, son de esperar mejoras
adicionales de rendimiento en la versión final de ASP.NET 2.0.

Conclusión

ASP.NET
2.0 contiene muchas mejoras en la arquitectura diseñadas para mejorar
la productividad de los desarrolladores. No sólo se ha mejorado el
modelo de código para reducir los conflictos, sino que el proceso de
compilación se ha ampliado para proporcionar una mayor variedad de
opciones a la hora de compilar e implementar aplicaciones Web. La
extensibilidad del marco de trabajo ASP.NET se ha puesto de manifiesto
una vez más mediante los nuevos HTTPModules y HTTPHandlers,
que admiten muchas de las nuevas características que incluye ASP.NET,
incluidas la personalización, las páginas principales y el sitio
administrativo. El almacenamiento en caché se ha mejorado para permitir
las dependencias de base de datos y la sustitución tras la caché.
Internamente, ASP.NET 2.0 contiene notables mejoras respecto a su
predecesor; la nueva implementación incorpora un número de mejoras
solicitadas por los desarrolladores al mismo tiempo que respeta las
prácticas recomendadas del sector. ASP.NET 2.0 proporciona una
plataforma de desarrollo Web de primera clase diseñada para manejar la
complejidad del desarrollo de aplicaciones Web empresariales.

About justindeveloper

I am MCP (Microsoft Certified Professional). MCTS (Microsoft Certified Technology Specialist) and MCPD (Microsoft Certified Professional Developer), also I am SAP Business One Certified!! Desarrollando desde el IDE de Visual Studio NET 2003 hasta ahora con el Visual Studio NET 2010. Desde Microsoft SQL Server 2000 hasta ahora con el Microsoft SQL Server 2008 R2 y tambien con SharePoint, desde WSS 3.0 y MOSS 2007 y ahora familirizandome con el Sharepoint Foundation 2010 & Sharepoint Server 2010. The software development will follow being every time more wonderful!
This entry was posted in Development. Bookmark the permalink.

4 Responses to Secretos internos de ASP.NET – Parte II

  1. José says:

    En tiempo de ejecución, se puede crear o modificar una página .aspx?

  2. Its like you read my mind! You appear to know a lot
    about this, like you wrote the book in it or something.
    I think that you could do with some pics
    to drive the message home a little bit, but instead of that, this
    is fantastic blog. A fantastic read. I’ll definitely be back.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s