1. Introducción básica a los scripts del servidor
Primero, revisemos los métodos básicos de ejecución de las páginas del servidor web:
1. El cliente envía una solicitud al servidor escribiendo la dirección en la barra de direcciones del navegador
2. Después de que el servidor recibe la solicitud, lo envía a Se ejecuta la página del lado del servidor correspondiente (es decir, un script). El script genera una respuesta del cliente y la envía de vuelta al cliente.
3. El navegador del cliente recibe la respuesta del servidor y la analiza. HTML, y presenta la página web gráfica al usuario. Para
la interacción entre el servidor y el cliente, generalmente se utilizan los siguientes métodos principales:
1. Formulario: este es el método más importante que se utiliza para obtener la entrada del usuario. El envío del formulario envía los datos al servidor para su procesamiento
2. QueryString: al agregarparámetros
después de la URL, los parámetros se transmiten al servidor. Este método es en realidad el mismo que el método Get.
un método especial, generalmente utilizado para confirmar la identidad del usuario
. 2. Introducción a ASP.Net
Los lenguajes de script de servidor tradicionales, como ASP, JSP, etc., escriben scripts de servidor de forma muy similar. Todos incorporan códigos interpretados o compilados y ejecutados. en HTML, y la plataforma del servidor ejecuta estos códigos para generar HTML para scripts y páginas similares. El ciclo de vida de Servlet es realmente muy simple, es decir, todo el código se ejecuta desde el principio hasta el final. Por supuesto, está escrito en Servlet. Java puede escribir código más complejo, pero desde un punto de vista estructural, no es diferente de JSP.
El surgimiento de ASP.Net rompió esta tradición; ASP.Net adoptó la tecnología CodeBehind y los controles del lado del servidor, agregó el concepto de eventos del lado del servidor, cambió el modelo de escritura del lenguaje de script y se acercó a la programación en Windows, facilitando la programación web. , intuitivo; pero debemos ver que ASP.Net en sí no cambia el modelo básico de programación web, solo encapsula algunos detalles y proporciona algunas funciones fáciles de usar, lo que hace que el código sea más fácil de escribir y mantener; Hasta cierto punto, complica la forma de ejecución del lado del servidor. Este es el tema principal que vamos a discutir hoy: el ciclo de vida de la página web ASP.Net.
3. Modo de procesamiento de solicitudes ASP.Net
Decimos que la página web de ASP.Net no se separa del modo de programación web, por lo que todavía funciona en el modo de solicitud->recibir solicitud->procesar solicitud->enviar respuesta. con el cliente desencadenará una nueva solicitud, por lo que el ciclo de vida de una página web se basa en una solicitud.
Cuando IIS recibe una solicitud del cliente, la entregará al proceso aspnet_wp para su procesamiento. Este proceso verificará si el dominio de la aplicación solicitado existe. Si no existe, creará uno y luego creará un tiempo de ejecución Http (. HttpRuntime ) para manejar solicitudes, este tiempo de ejecución "proporciona un conjunto de servicios de tiempo de ejecución ASP.NET para la aplicación actual" (de MSDN).
Cuando HttpRuntime procesa solicitudes, mantendrá una serie de instancias de aplicaciones, es decir, instancias de la clase Global de la aplicación (global.asax). Estas instancias se almacenarán en un grupo de aplicaciones cuando no haya solicitudes (en realidad, el grupo de aplicaciones se mantiene). Por otra clase, HttpRuntime es solo una simple llamada). Cada vez que se recibe una solicitud, HttpRuntime obtendrá una instancia inactiva para procesar la solicitud. Esta instancia no procesará otras solicitudes antes de que finalice el procesamiento. Vuelva al grupo, "Una instancia se utiliza para manejar múltiples solicitudes durante su vida útil, pero solo puede manejar una solicitud a la vez". (Extraído de MSDN)
Cuando la instancia de la aplicación maneja la solicitud, creará una instancia de la clase de página de solicitud y ejecuta su método ProcessRequest para procesar la solicitud. Este método es el comienzo del ciclo de vida de la página web.
4. Página Aspx y CodeBehind
Antes de profundizar en el ciclo de vida de la página, primero analicemos algunas de las relaciones entre Aspx y CodeBehind.
<%@ Page language="c#" Codebehind="WebForm.aspx.cs" Inherits="MyNamespace.WebForm" %>
Creo que los amigos que han usado la tecnología CodeBehind deberían estar muy familiarizados con esta oración en la parte superior de ASPX. Analícelo uno por uno:
Idioma de la página = "c #" No hace falta decir que
Codebehind = "WebForm.aspx.cs" Esta oración indica el archivo de código vinculado
Hereda = "MyNamespace.WebForm" Esta oración es muy importante. Representa el nombre de la clase. heredada por la página, que es la clase en el archivo de código de CodeBehind. Esta clase debe derivarse de System.Web.WebControls.Page.
De lo anterior podemos analizar que, de hecho, la clase en CodeBehind es la base de la página. (ASPX), en este punto, es posible que algunos amigos quieran preguntar. Al escribir ASPX, el código o los controles del servidor se incrustan exactamente de acuerdo con el método ASP. ?
En realidad, este problema no es complicado. Los amigos que usan programación ASP.Net pueden ir al disco de su sistema: WINDOWSMicrosoft.NETFramework<número de versión>Temporary ASP.NET Files y colocarlo debajo de Todos los archivos temporales de ASP. Aplicaciones .Net que existen en esta máquina El nombre del subdirectorio es el nombre de la aplicación y luego baja dos niveles (para garantizar la unicidad, ASP.Net genera automáticamente dos niveles de subdirectorios y el subdirectorio El nombre es. aleatorio), y luego encontraremos que hay muchas bibliotecas de enlaces similares a: "yfy1gjhc.dll", "xeunj5u3.dll" y fuentes como archivos "komee-bp.0.cs" y "9falckav.0.cs".
Dehecho
, este es el resultado de que ASPX sea compilado dinámicamente por ASP.Net. Cuando abrimos estos archivos fuente, podemos encontrar:
clase pública WebForm_aspx: MyNamespace.WebForm, System.Web.SessionState.IRequiresSessionState.
, ASPX Es una subclase de la clase de enlace de código. Su nombre es el nombre del archivo ASPX más el sufijo "_aspx". Al estudiar estos códigos, podemos encontrar que, de hecho, todos los controles de servidor definidos en aspx se generan en estos códigos. Luego, cuando estos códigos se generan dinámicamente, el código originalmente incrustado en ASPX se escribe en la ubicación correspondiente.
Cuando se visita una página por primera vez, el tiempo de ejecución HTTP utilizará un generador de código para analizar el archivo ASPX y generar el código fuente y compilarlo. Luego, las visitas posteriores llamarán directamente al dll compilado. Esta es la razón por la que se accede a ASPX. es muy lento.
Habiendo explicado este problema, veamos otro problema. Cuando usamos el enlace de código, arrastramos un control a la página de diseño y luego cambiamos a la vista de código. Puede usar el control directamente en Page_Load. Dado que el control se genera en la subclase, ¿por qué se puede usar en la clase principal? ¿Qué tal usarlo directamente?
De hecho, podemos encontrar que cada vez que usamos VS.Net para arrastrar un control a la página, siempre se agrega una declaración similar a esta al archivo de enlace de código:
protected System.Web.WebControls.Button Button1.
Podemos encontrar que esto; El campo es Declararlo como protegido y el nombre es consistente con el ID del control en ASPX. Si lo piensa detenidamente, este problema se resolverá. Mencionamos anteriormente que el código fuente de ASPX es generado y compilado dinámicamente por el generador. El generador generará el código para generar dinámicamente cada control de servidor. Al generar, verificará si la clase principal ha declarado este control. agregará un código similar al siguiente:
this.DataGrid1 = __ctrl;
Este __ctrl es la variable que genera el control. En este momento asigna la referencia del control a la variable correspondiente en la clase padre. la clase padre La declaración debe estar protegida (de hecho, también puede ser pública), porque es necesario garantizar que las subclases puedan llamarla.
Luego, cuando se ejecuta Page_Load, debido a que el código de inicialización en la subclase ha asignado un valor a la declaración de la clase principal, podemos usar este campo para acceder al control correspondiente. Sabiendo esto, no confirmaremos el enlace del código. en el constructor en el archivo especificado provoca un error de excepción de referencia nula. Debido a que el constructor se ejecuta primero, la inicialización de la subclase aún no ha comenzado, por lo que los campos en la clase principal tienen valores nulos. En cuanto a la subclase, lo discutiremos más adelante. cuando se inicializa una clase.
5. Ciclo de vida de la página
Ahora, volviendo al contenido mencionado en el tercer título, hablamos de la instancia de HttpApplication que recibe la solicitud y crea una instancia de la clase de página. De hecho, esta instancia es una instancia de la clase ASPX compilada dinámicamente. En el título anterior aprendimos que ASPX es en realidad una subclase de la clase en el enlace del código, por lo que hereda todos los métodos protegidos.
Ahora echemos un vistazo al código de la clase CodeBehind generada automáticamente por VS.Net para comenzar nuestra discusión sobre el ciclo de vida de la página:
#region El código generado por Web Form Designer
anula protected void OnInit(EventArgs e)
{
//
// CODEGEN: esta llamada la requiere el diseñador de formularios web ASP.NET.
//
InicializarComponente();
base.OnInit(e);
}
/// <resumen>
/// Designer admite los métodos requeridos; no use el editor de código para modificar
/// El contenido de este método.
/// </summary>
vacío privado InitializeComponent()
{
this.DataGrid1.ItemDataBound += nuevo System.Web.UI.WebControls.DataGridItemEventHandler(this.DataGrid1_ItemDataBound);
this.Load += nuevo System.EventHandler(this.Page_Load);
}
#endregion
Este es el código de la página generado con VS.Net. Echemos un vistazo. Hay dos métodos, uno es OnInit y el otro es InitializeComponent. comienzo de la inicialización de la página. En InitializeComponent vemos la declaración de evento del control y la declaración de carga de la página.
La siguiente es una descripción extraída de MSDN y una tabla de secuencia de los métodos del ciclo de vida de la página y la activación de eventos:
"Cada vez que se solicita una página ASP.NET, el servidor carga una página ASP.NET y la descarga cuando se completa la solicitud. La página y los controles del servidor que contiene son responsables de ejecutar la solicitud y presentar el HTML al cliente. Aunque la comunicación entre el cliente y el servidor es sin estado e intermitente, el cliente debe percibirla como un proceso continuo.
"Esta ilusión de continuidad es implementada por el marco de la página ASP.NET, la página y sus controles. Después de una devolución de datos, el comportamiento del control debe parecer comenzar desde donde terminó la última solicitud web. Los marcos pueden hacer que la gestión del estado de ejecución sea relativamente Es fácil, pero para lograr efectos de continuidad, los desarrolladores de controles deben conocer el orden de ejecución de los controles. Los desarrolladores de controles deben comprender qué información se puede utilizar y qué datos puede retener el control en cada etapa del ciclo de vida del control. estado en el que se representa un control. Por ejemplo, un control no puede llamar a su padre hasta que se complete el árbol de control en la página". La siguiente tabla proporciona una descripción general de alto nivel de las etapas del ciclo de vida del control. Haga clic en la tabla. enlace."
de etapa | necesita realizar una acción | para anular el método o evento de inicialización |
inicializar | la configuración requerida dentro del ciclo de vida de una solicitud web entrante. Consulte Manejo de eventos heredados. | El evento Init (método OnInit) |
carga el estado de la vista. | Al final de esta fase, la propiedad ViewState del control se completará automáticamente. Para obtener más información, consulte la introducción en Mantenimiento del estado en el control. Un control puede anular la implementación predeterminada del método LoadViewState para restaurarlo a un estado personalizado. | El método LoadViewState |
maneja los datos de devolución | , procesa los datos del formulario entrante y actualiza las propiedades en consecuencia. Consulte Manejo de datos de devolución. Nota Solo los controles que manejan datos de devolución participan en esta fase. | El método LoadPostData (si se implementa IPostBackDataHandler) |
carga y | realiza operaciones comunes a todas las solicitudes, como configurar una consulta de base de datos. En este punto, los controles del servidor en el árbol se crearon e inicializaron, el estado se restauró y los controles del formulario reflejan los datos del cliente. Consulte Manejo de eventos heredados. | Cargar evento (método OnLoad) |
Enviar notificaciones de cambios de devolución de datos | Generar un evento de cambio en respuesta a un cambio de estado entre las devoluciones de datos actuales y anteriores. Consulte Manejo de datos de devolución. Nota En esta fase solo participan los controles que generan eventos de cambio de devolución de datos. | El método RaisePostDataChangedEvent (si se implementa IPostBackDataHandler) |
maneja eventos de devolución de datos. | Maneja eventos del cliente que causan devoluciones de datos y genera los eventos apropiados en el servidor. Consulte Captura de eventos de devolución de datos. Nota En esta fase solo participan los controles que manejan eventos de devolución de datos. | Los prerenderizadores del método RaisePostBackEvent (si se implementa IPostBackEventHandler) |
realizan | cualquier actualización antes de renderizar la salida. Los cambios en el estado de un control durante la fase de prerenderizado se pueden guardar, mientras que los cambios realizados durante la fase de renderizado se pierden. Consulte Manejo de eventos heredados. | El evento PreRender (método OnPreRender) |
guarda el estado | después de esta fase, persistiendo automáticamente la propiedad ViewState del control en un objeto de cadena. Este objeto de cadena se envía al cliente y regresa como una variable oculta. Para mejorar la eficiencia, los controles pueden anular el método SaveViewState para modificar la propiedad ViewState. Consulte Mantenimiento del estado en los controles. | El método SaveViewState |
genera | el resultado que se presenta al cliente. Consulte Representación de controles de servidor ASP.NET. | El método Render |
maneja | todas las operaciones de limpieza finales antes de destruir el control. Las referencias a recursos costosos, como enlaces a bases de datos, deben publicarse en esta etapa. Consulte los métodos en los controles del servidor ASP.NET. | El método Dispose |
descarga | todas las operaciones de limpieza finales antes de destruir el control. Los autores de controles normalmente realizan la limpieza en Dispose sin controlar este evento. | Evento UnLoad (método On UnLoad) |
En esta tabla, podemos ver claramente los métodos llamados y el tiempo de activación de una página desde la carga hasta la descarga. A continuación, lo analizaremos en profundidad.
Después de mirar la tabla anterior, los amigos atentos pueden preguntar, ya que OnInit es el comienzo del ciclo de vida de la página, y hablamos sobre la creación de controles en subclases en la conferencia anterior, aquí en realidad usamos los campos del método InitializeComponent declarados en la clase principal. ya se puede usar, entonces, ¿significa que la subclase se inicializó antes de esto?
En el tercer título, mencionamos que ProcessRequest de la clase de página es el comienzo del ciclo de declaración de página en el verdadero sentido. Este método es llamado por HttpApplication (el método de llamada es más complicado y tendré la oportunidad de escribir uno). artículo separado para explicarlo). Una página El procesamiento de la solicitud comienza a partir de este método. Al descompilar la biblioteca de clases .Net para ver el código fuente, encontramos la clase base de System.Web.WebControls.Page: System.Web. WebControls.TemplateControl (es la página y el control de usuario. Se define un método virtual "FrameworkInitialize" en la clase base), y luego este método se llama primero en ProcessRequest de la página. Encontramos rastros de este método en el código fuente ASPX. generado por el generador. Todos los controles están en Se inicializa en este método y el árbol de control de la página se genera en este momento.
Lo siguiente es simple, analicemos gradualmente cada elemento del ciclo de vida de la página:
1. Inicialización
La inicialización corresponde al evento Init y al método OnInit de la Página.
Si desea reescribir, MSDN recomienda sobrecargar el método OnInti en lugar de agregar un proxy para el evento Init. El primero puede controlar el orden en que se llama al método OnInit de la clase principal, mientras que el primero puede controlar el orden en que se llama al método OnInit de la clase principal. Este último solo se puede usar en la clase principal. Ejecutado después de OnInit (en realidad se llama en OnInit).
2. Cargar el estado de la vista
Este es un método más importante. Sabemos que cada solicitud es en realidad procesada por una instancia de clase de página diferente. Para garantizar el estado entre dos solicitudes, ASP.Net usa ViewState.
El método LoadViewState obtiene el último estado de ViewState y utiliza la recursividad para recorrer todo el árbol de acuerdo con la estructura del árbol de control en la página para restaurar el estado correspondiente a cada control.
3. Procesamiento de datos de devolución
Este método se utiliza para verificar si el estado de los datos de control enviados por el cliente ha cambiado. Prototipo del método:
public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection)
postDataKey es la palabra clave que identifica el control (es decir, la clave en postCollection es una colección que contiene datos de devolución de datos). la devolución Si los datos enviados han cambiado, si es así, devuelve un Verdadero, "LoadPostData devuelve verdadero si el estado del control cambia debido a la devolución de datos; de lo contrario, devuelve falso. El marco de la página rastrea todos los controles que devuelven verdadero y llama a RaisePostDataChangedEvent en estos controles "(Extraído de MSDN)
Este método se define en System.Web.WebControls.Control y también es el método que deben manejar todos los controles personalizados que necesitan manejar eventos. Para la página que estamos discutiendo hoy, puede dejarlo. solo.
4. La carga
corresponde al evento Load y al método OnLoad. Creo que la mayoría de mis amigos estarán familiarizados con este evento. El método Page_Load en la página generada por VS.Net es el método para responder al evento Load. Se activará el evento, y también se ejecutará el método Page_Load. Creo que este también es el primer paso para que la mayoría de la gente comprenda ASP.Net.
El método Page_Load responde al evento Load, que se define en la clase System.Web.WebControl.Control (esta clase es el antepasado de Page y de todos los controles del servidor) y se activa en el método OnLoad.
Es posible que muchas personas hayan encontrado algo así. Escribieron una clase PageBase y luego verificaron la información del usuario en Page_Load. Resultó que, independientemente de si la verificación fue exitosa o no, el Page_Load de la página de la subclase siempre se ejecutará primero. esta vez, es posible que quede alguna información como riesgo de seguridad, el usuario puede ejecutar el método Page_Load en la subclase sin estar autenticado.
La razón de este problema es muy simple, porque el método Page_Load se agrega al evento Load en OnInit, y el método OnInit de la subclase primero agrega el evento Load y luego llama a base.OnInit, lo que hace que la subclase Se agregue primero Page_Load , luego ejecutado primero.
También es muy sencillo resolver este problema. Hay dos métodos:
1) Sobrecargar el método OnLoad en PageBase, luego autenticar al usuario en OnLoad y luego llamar a base.OnLoad, porque el evento Load se activa en OnLoad, por lo que podemos. asegúrese de autenticar al usuario antes de activar el evento de carga.
2) Primero llame a base.OnInit en el método OnInit de la subclase para asegurarse de que la clase principal ejecute Page_Load primero.
5. Envíe una notificación de cambio de devolución.
Este método corresponde al procesamiento de los datos de devolución en el paso 3. Si se procesan los datos de devolución. , Se devuelve True. El marco de la página llamará a este método para activar eventos de cambio de datos, por lo que el evento de cambio de datos de devolución del control personalizado debe activarse en este método.
De manera similar, este método no es muy útil para Page. Por supuesto, también puede definir eventos de cambio de datos en función de Page.
6. Manejar eventos de devolución de datos
Este método es donde se activan la mayoría de los eventos de control del servidor. Cuando la solicitud contiene información sobre los activadores de eventos de control (los eventos de controles del servidor son otro tema, escribiré otro artículo para discutirlo en el futuro cercano), el control de página. Se llamará al método RaisePostBackEvent del control correspondiente para activar el evento del lado del servidor.
Aquí viene otra pregunta común:
los internautas a menudo preguntan por qué los datos enviados no han cambiado después de la modificación.
En la mayoría de los casos, no comprenden el proceso de activación de los eventos del servidor. Podemos ver que el evento del servidor se activa después de la carga de la página. En otras palabras, la página primero ejecutará Page_Load y luego ejecutará el evento de clic del botón (aquí está el botón como ejemplo). Muchos amigos vinculan datos en Page_Load y luego procesan los cambios en el evento del botón. Hay un problema con esto, Page_Load siempre se ejecuta antes del evento del botón, lo que significa que antes de que los datos tengan tiempo de cambiar, el código de enlace de datos en Page_Load se ejecuta primero y los datos originales se asignan al control, luego cuando se ejecuta. Se ejecuta el evento del botón. Lo que realmente se obtiene son los datos originales, por lo que la actualización, por supuesto, no tendrá ningún efecto.
También es muy sencillo cambiar este problema. Un enfoque más razonable es escribir el código de enlace de datos en un método, supongamos que es BindData:
private void BindData().
{
//Enlazar datos
}
Luego modifique PageLoad:
privado vacío Page_Load (objeto remitente, EventArgs e)
{
si(!IsPostBack)
{
BindData(); // Vincular datos cuando se accede a la página por primera vez}
}
Finalmente en el evento del botón:
privado Button1_Click (objeto remitente, EventArgs e)
{
//Actualizar datosBindData();//Volver a vincular datos
}
7.
El procesamiento de la solicitud final de renderizado previo se convertirá en una respuesta enviada de regreso al servidor. La etapa de renderizado previo consiste en realizar los cambios de estado realizados antes del renderizado final, porque antes de renderizar un control, debemos realizar. generar HTML en función de sus propiedades, como el atributo Estilo, que es el ejemplo más típico. Antes del renderizado previo, podemos cambiar el estilo de un control. Cuando se realiza el renderizado previo, podemos guardar el estilo y mostrar HTML. información de estilo como etapa de renderizado.
8. Guarde el estado.
Esta etapa es para el estado de carga. Hemos mencionado muchas veces que se procesan diferentes instancias entre solicitudes, por lo que necesitamos guardar el estado de esta página y controlarla. .
9. En
este punto, el procesamiento de la solicitud de la página básicamente ha llegado a su fin. En el método Render, se recurrirá al árbol de control de toda la página, se llamará al método Render en secuencia y se escribirá el código HTML correspondiente. en el flujo de respuesta final.
10. La eliminación
es en realidad el método Dispose. En esta etapa, se liberarán los recursos ocupados, como las conexiones de bases de datos.
11.
Al final de la descarga, la página ejecutará el método OnUnLoad para activar el evento UnLoad, que maneja el procesamiento final antes de que se destruya el objeto de la página. De hecho, ASP.Net proporciona este evento solo por consideraciones de diseño. de recursos se completa en el método Dispose, por lo que este método se ha vuelto inútil.
Presentamos brevemente el ciclo de vida de la página y brindamos una explicación menos detallada del procesamiento de eventos del lado del servidor. Hoy principalmente quiero que todos comprendan el ciclo de ejecución de la página. Escribiré más sobre los eventos y la vida útil. de los controles del servidor en el futuro artículo para discutir.
Estos contenidos son algunas de mis experiencias en la investigación de páginas cuando estaba aprendiendo ASP.Net. Los detalles específicos no se analizan en detalle para obtener más información, pero he citado algunos errores comunes cometidos por principiantes. Espero que pueda inspirar a todos.