Páginas y controles compilados al vuelo con ASP.NET
A la hora de desarrollar páginas web en .NET es posible hacer que las páginas y los controles estén compilados y con toda la lógica en una DLL, o hacer que las páginas y los controles se compilen al vuelo conforme se van solicitando por los usuarios, quedando disponibles a partir de entonces para sucesivas peticiones. Dentro de la opción de compilación al vuelo podemos tener la lógica y la presentación (HTML) juntas en un mismo archivo, o en diferentes. Voy a tratar únicamente la forma basada en archivos independientes, ya que es la opción predeterminada en Visual Studio, SharpDevelop, además de propiciar una mayor separación entre lógica y presentación, lo cual incrementa la mantenibilidad del proyecto.
Ambas aproximaciones, compilación estática o al vuelo, tienen sus puntos fuertes así como algunos inconvenientes. La opción de tener toda la lógica compilada nos aporta una mayor velocidad desde el momento inicial en el que se arranca la aplicación, pero en contra nos obliga a tener que recompilar la aplicación o alguna parte de ella y generar una nueva DLL cada vez que se realiza un cambio, implicando un reinicio de la aplicación con el coste que ello supone.
Por contra la opción basada en compilación al vuelo, on the fly
en inglés, nos permite modificar la lógica de cualquier página y control sin tener que recompilar la aplicación ni tener que reiniciar la aplicación. Sin embargo tiene como desventaja que el arranque de la aplicación será algo más pesado, ya que ninguna página o control estará compilado y por lo tanto será necesario compilarlos conforme se vayan solicitando, incrementando los requisitos del servidor en esos momentos.
En lo que a mi respecta, la mayoría de los proyectos que realizo últimamente los hago utilizando compilación al vuelo, a pesar de que al comienzo utilizaba la compilación estática. El motivo principal que propició este cambio fue la facilidad de mantenimiento que aporta la compilación al vuelo, aunque en ningún caso debería debería tomarse esto como una regla ya que cada proyecto es un mundo.
A continuación voy a explicar cómo hacer que las páginas y controles se compilen al vuelo, detallando algunos problemas con los que nos podemos encontrar y posibles soluciones.
Página compilada al vuelo
Como hemos dicho antes vamos a separar la lógica y la presentación en archivos independientes, lo que en muchos sitios se denomina páginas y controles codebehind
. El archivo con la lógica suele denominarse con la extensión .aspx.cs y el de la presentación .aspx. A modo de resumen, cuando el servidor web recibe la primera petición para la página aspx, localiza el archivo con la lógica y lo compila. Tras esto el comportamiento de las páginas compiladas estáticamente o dinámicamente es idéntico, el servidor crea una DLL temporal a partir del HTML de la presentación embebiéndolo en una clase generada dinámicamente, y que hereda de la clase definida en el archivo de la lógica. Una vez hecho esto ejecuta la DLL produciendo el resultado HTML de la página.
De todo lo anterior lo que a nosotros nos interesa es el punto en el que, a partir del archivo con la presentación, se localiza el archivo con la lógica y se compila. Para explicarlo vamos a ver un pequeño detalle con el típico hola mundo.
Archivo con la presentación
<%@ Page language="c#" Codebehind="HolaMundo.aspx.cs" Src="HolaMundo.aspx.cs" Inherits="com.eslomas.HolaMundo" %> <html> <head /> <body> <asp:label id="label1" runat="server" /> </body> </html> |
Archivo con la lógica
using System; using System.Data; using System.Drawing; using System.Web; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; namespace com.eslomas { public class HolaMundo : System.Web.UI.Page { protected System.Web.UI.WebControls.Label label1; private void Page_Load(object sender, System.EventArgs e) { label1.Text = "Hola mundo!!!!"; } #region Web Form Designer generated code override protected void OnInit(EventArgs e) { // // CODEGEN: llamada requerida por el Diseñador de Web Forms ASP.NET. // InitializeComponent(); base.OnInit(e); } /// <summary> /// Método necesario para admitir el Diseñador, no se puede modificar /// el contenido del método con el editor de código. /// </summary> private void InitializeComponent() { this.Load += new System.EventHandler(this.Page_Load); } #endregion } } |
Lo que permite conectar ambos archivos es la primera línea del archivo de presentación, que contiene la directiva Page
. En ella puede verse como se indica mediante el atributo src el nombre del fuente con la lógica. Aparte de este atributo es también importante el inherits, que indica de qué clase definida en ese archivo tendrá que heredar la dll temporal que se genere a partir de la presentación. Si nos fijamos podemos ver como hay un atributo con el mismo valor que src, que es codebehind. Este atributo no es necesario y no tiene ninguna utilidad a nivel de servidor web, se crea automáticamente por Visual Studio para relacionar ambos archivos, por lo que si no utilizas esta herramienta no haría falta indicarlo.
Controles compilados al vuelo
En el caso de los controles el funcionamiento es similar, a continuación muestro un ejemplo con los archivos de presentación y lógica de un control de ejemplo, que únicamente muestra en un label el resultado de una suma.
Archivo con la presentación
<%@ Control Language="c#" Codebehind="ControlEjemplo.ascx.cs" src="ControlEjemplo.ascx.cs" Inherits="com.eslomas.ControlEjemplo" %> Resultado de la suma: <asp:label id="lOutput" runat="server" /> |
Archivo con la lógica
namespace com.eslomas { using System; using System.Data; using System.Drawing; using System.Web; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; public abstract class ControlEjemplo : System.Web.UI.UserControl { protected System.Web.UI.WebControls.Label lOutput; private void Page_Load(object sender, System.EventArgs e) { lOutput.Text = "esto es un control"; } #region Web Form Designer generated code override protected void OnInit(EventArgs e) { // // CODEGEN: This call is required by the ASP.NET Web Form Designer. // InitializeComponent(); base.OnInit(e); } /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.Load += new System.EventHandler(this.Page_Load); } #endregion } } |
En esta ocasión la vinculación entre ambos archivos viene dada por la directiva Control
, mediante la utilización de los atributos src y inherits, al igual que en el caso de las páginas.
Soluciones a algunos problemas
Reutilización utilizando herencia
La separación en archivos independiente para la presentación y la lógica nos brinda una posibilidad más, que es la reutilización de un archivo de lógica para varias páginas o controles. Imaginémonos varias páginas web con un comportamiento idéntico, por ejemplo unos listados de contenidos, que difieren sin embargo en su aspecto html. Podríamos crear un único archivo de lógica y relacionarlo con todos los archivos de presentación. En el cso de páginas compiladas estáticamente esta relación vendrá dada por el atributo inherits, pero en nuestro caso deberemos indicar también el atributo src. No importa que en varios archivos de presentación indiquemos el mismo src, éste sólo se compilará una vez, la primera vez que accedamos a una página que lo referencie.
Controles con atributos
Cuando cargamos un control en una página es habitual pasarle información mediante los atributos que tenga disponibles, para lo cual simplemente añadimos sus nombres, junto a sus valores, a la declaración XML del control en la página. Esto funciona perfectamente esté el control compilado estáticamente o se vaya a compilarse al vuelo, sin embargo, no funcionaría a la hora de hacer un LoadControl
desde el archivo de lógica. El método LoadControl
de la clase Page permite cargar un control dinámicamente en tiempo de ejecución.
Si utilizamos este método lo que obtendremos será una instancia WebControl, por lo que tendríamos que hacer un cast a la clase concreta del control para poder pasarle los atributos necesarios. El problema es que este cast hay que declararlo al escribir la lógica, por lo que al compilar el archivo nos dará un error, ya que el control todavía no se habrá compilado, por hacerse ésto al vuelo. Para resolver esta situación una posible solución es crear un interfaz que se corresponda con los atributos del control, compilar este interfaz, y hacer un cast a él a la hora de cargar el control con LoadControl.
necesito ayuda: tengo que conectar mysql con c# usando asp.net en una plataforma linux, ya tengo apache2 xsp y mod mono sin embago no me reconoce las librerias del driver mysql instalado, si supieran algo acerca de esto les agradecería la información.