8. La aplicación [SimuPaie] – versión 4 – ASP.NET / múltiples vistas / una sola página
Lecturas recomendadas: referencia [1], Desarrollo de WEB con ASP.NET 1.1, párrafos:
-
Componentes de servidor y controlador de aplicaciones
-
Ejemplos de aplicaciones MVC con componentes de servidor ASP
Ahora analizaremos una versión derivada de la aplicación de tres capas ASP.NET que estudiamos anteriormente y a la que se le han agregado nuevas funcionalidades. La arquitectura de nuestra aplicación evoluciona de la siguiente manera:
![]() |
El procesamiento de una solicitud de un cliente se lleva a cabo siguiendo los siguientes pasos:
- el cliente realiza una solicitud a la aplicación.
- La aplicación procesa esta solicitud. Para ello, puede necesitar la ayuda de la capa [métier], la cual a su vez puede requerir la capa [dao] si es necesario intercambiar datos con la base de datos. La aplicación recibe una respuesta de la capa [métier].
- Según esta, elige (3) la vista (= la respuesta) que se enviará al cliente, proporcionándole (4) la información (el modelo) que necesita.
- La respuesta se envía al cliente (5)
Aquí tenemos una arquitectura web conocida como MVC (Modelo – Vista – Controlador):
- [Application] es el controlador. Recibe todas las solicitudes del cliente.
- [Saisies, Simulation, Simulations, ...] son las vistas. Una vista en .NET es código estándar ASP / HTML que contiene componentes que deben inicializarse. Los valores que se deben proporcionar a estos componentes conforman el modelo de la vista.
Aquí implementaremos el patrón de diseño MVC de la siguiente manera:
- las vistas serán componentes [View] dentro de una página única [Default.aspx]
- el controlador es, por lo tanto, el código [Default.aspx.cs] de esta página única.
Solo las aplicaciones básicas pueden soportar esta implementación MVC. De hecho, en cada solicitud, se instancian todos los componentes de la página [Default.aspx], es decir, todas las vistas. Al momento de enviar la respuesta, el código de control de la aplicación elige una de ellas simplemente haciendo visible el componente [View] correspondiente y ocultando los demás. Si la aplicación tiene muchas vistas, la página [Default.aspx] tendrá muchos componentes y su costo de instanciación puede volverse prohibitivo. Además, el modo [Design] de la página corre el riesgo de volverse inmanejable debido a que tiene demasiadas vistas. Este tipo de arquitectura es adecuada para aplicaciones con pocas vistas y desarrolladas por una sola persona. Cuando se puede adoptar, permite desarrollar una arquitectura MVC de manera muy sencilla. Eso es lo que veremos en esta nueva versión.
8.1. Las vistas de la aplicación
Las diferentes vistas que se le presentarán al usuario serán las siguientes:
- la vista [VueSaisies], que muestra el formulario de simulación

- la vista [VueSimulation], utilizada para mostrar el resultado detallado de la simulación:

- la vista [VueSimulations], que muestra la lista de simulaciones realizadas por el cliente

- la vista [VueSimulationsVides], que indica que el cliente no tiene simulaciones o ya no las tiene:

- la vista [VueErreurs], que indica uno o varios errores:

8.2. El proyecto de Visual Web Developer de la capa [web]
El proyecto de Visual Web Developer de la capa [web] es el siguiente:
![]() |
- En [1] se encuentra:
- el archivo de configuración [Web.config] de la aplicación —es idéntico al de la aplicación anterior—.
- el archivo [Global.cs], que administra los eventos de la aplicación web —en este caso, su inicio—, es idéntico al de la aplicación anterior, salvo que también administra el inicio de la sesión del usuario.
- El formulario [Default.aspx] de la aplicación —contiene las diferentes vistas de la aplicación—.
- En [2] se encuentran las referencias del proyecto, que son idénticas a las de la versión anterior
8.3. El archivo [Global.cs]
El archivo [Global.cs], que administra los eventos de la aplicación web, es idéntico al de la aplicación anterior, salvo que además administra el inicio de la sesión del usuario:
Global.cs
using System;
using System.Web;
using Pam.Dao.Entites;
using Pam.Metier.Service;
using Spring.Context.Support;
using System.Collections.Generic;
using istia.st.pam.web;
namespace pam_v4
{
public class Global : HttpApplication
{
// --- datos estáticos de la aplicación ---
public static Employe[] Employes;
public static string Msg = string.Empty;
public static bool Erreur = false;
public static IPamMetier PamMetier = null;
// inicio de la aplicación
public void Application_Start(object sender, EventArgs e)
{
...
}
// inicio de la sesión de un usuario
public void Session_Start(object sender, EventArgs e)
{
// se inserta una lista de simulaciones vacía en la sesión
Session["simulations"] = new List<Simulation>();
}
}
}
- líneas 27-34: se gestiona el inicio de la sesión. En ella incluiremos la lista de simulaciones realizadas por el usuario.
- línea 30: se crea una lista de simulaciones vacía. Una simulación es un objeto de tipo [Simulation] que detallaremos más adelante.
- línea 31: la lista de simulaciones se coloca en la sesión asociada a la clave «simulaciones»
8.4. La clase [Simulation]
Un objeto de tipo [Simulation] sirve para encapsular una fila de la tabla de simulaciones:

Su código es el siguiente:
namespace Pam.Web
{
public class Simulation
{
// datos de una simulación
public string Nom { get; set; }
public string Prenom { get; set; }
public double HeuresTravaillees { get; set; }
public int JoursTravailles { get; set; }
public double SalaireBase { get; set; }
public double Indemnites { get; set; }
public double CotisationsSociales { get; set; }
public double SalaireNet { get; set; }
// constructores
public Simulation()
{
}
public Simulation(string nom, string prenom, double heuresTravailllees, int joursTravailles, double salaireBase, double indemnites, double cotisationsSociales, double salaireNet)
{
{
this.Nom = nom;
this.Prenom = prenom;
this.HeuresTravaillees = heuresTravailllees;
this.JoursTravailles = joursTravailles;
this.SalaireBase = salaireBase;
this.Indemnites = indemnites;
this.CotisationsSociales = cotisationsSociales;
this.SalaireNet = salaireNet;
}
}
}
}
Los campos de la clase corresponden a las columnas de la tabla de simulaciones.
8.5. La página [Default.aspx]
8.5.1. Visión general
La página [Default.aspx] contiene varios componentes [View], uno por cada vista. Su estructura es la siguiente:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="pam_v4.PagePam" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Simulateur de paie</title>
</head>
<body background="ressources/standard.jpg">
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true" />
<asp:UpdatePanel runat="server" ID="UpdatePanelPam" UpdateMode="Conditional">
<ContentTemplate>
<table>
<tr>
<td>
<h2>
Simulateur de calcul de paie</h2>
</td>
<td>
<label>
 </label>
<asp:UpdateProgress ID="UpdateProgress1" runat="server">
<ProgressTemplate>
<img src="images/indicator.gif" />
<asp:Label ID="Label5" runat="server" BackColor="#FF8000"
EnableViewState="False" Text="Calcul en cours. Patientez ....">
</asp:Label>
</ProgressTemplate>
</asp:UpdateProgress>
</td>
<td>
<asp:LinkButton ID="LinkButtonFaireSimulation" runat="server"
CausesValidation="False" OnClick="LinkButtonFaireSimulation_Click">
| Faire la simulation<br /></asp:LinkButton>
<asp:LinkButton ID="LinkButtonEffacerSimulation" runat="server"
CausesValidation="False" OnClick="LinkButtonEffacerSimulation_Click">
| Effacer la simulation<br /></asp:LinkButton>
<asp:LinkButton ID="LinkButtonVoirSimulations" runat="server"
CausesValidation="False" OnClick="LinkButtonVoirSimulations_Click">
| Voir les simulations<br /></asp:LinkButton>
<asp:LinkButton ID="LinkButtonFormulaireSimulation" runat="server"
CausesValidation="False" OnClick="LinkButtonFormulaireSimulation_Click">
| Retour au formulaire de simulation<br /></asp:LinkButton>
<asp:LinkButton ID="LinkButtonEnregistrerSimulation" runat="server"
CausesValidation="False" OnClick="LinkButtonEnregistrerSimulation_Click">
| Enregistrer la simulation<br /></asp:LinkButton>
<asp:LinkButton ID="LinkButtonTerminerSession" runat="server"
CausesValidation="False" OnClick="LinkButtonTerminerSession_Click">
| Terminer la session<br /></asp:LinkButton>
</td>
</table>
<hr />
<asp:MultiView ID="Vues1" ActiveViewIndex="0" runat="server">
<asp:View ID="VueSaisies" runat="server">
...
</asp:View>
</asp:MultiView>
<asp:MultiView ID="Vues2" runat="server">
<asp:View ID="VueSimulation" runat="server">
...
</asp:View>
<asp:View ID="VueSimulations" runat="server">
...
</asp:View>
<asp:View ID="VueSimulationsVides" runat="server">
...
</asp:View>
<asp:View ID="VueErreurs" runat="server">
...
</asp:View>
</asp:MultiView>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
- línea 10: la etiqueta para incluir las extensiones de Ajax
- líneas 11-73: el contenedor UpdatePanel actualizado mediante llamadas Ajax
- líneas 12-72: el contenido del contenedor UpdatePanel
- líneas 13-52: el encabezado que aparecerá en cada vista. Muestra al usuario la lista de acciones posibles en forma de una lista de enlaces.
- línea 33: cabe destacar el atributo CausesValidation="False", que hace que los validadores de la página no se ejecuten implícitamente al hacer clic en el enlace. Cuando este atributo no está presente, su valor por defecto es True. La validación de la página se podrá realizar explícitamente en el código ejecutado del lado del servidor mediante la operación Page.Validate.
- líneas 53-57: un componente [MultiView] con una única vista [VueSaisies]. Por esta razón, en la línea 53 se ha establecido de forma fija el número de la vista que se debe mostrar: ActiveViewIndex="0"
- líneas 53-67: un componente [MultiView] con cuatro vistas: la vista [VueSimulation] en las líneas 59-61, la vista [VueSimulations] en las líneas 62-64, la vista [VueSimulationsVides] en las líneas 65-67 y la vista [VueErreurs] en las líneas 68-70. Un componente [MultiView] solo muestra una vista a la vez. Para mostrar la vista n.º i del componente Vues2, se escribirá el código:
8.5.2. El en cabezal
El encabezado está formado por los siguientes componentes:
![]() |
N.º | Tipo | Nombre | Función |
LinkButton | LinkButtonFaireSimulation | solicita el cálculo de la simulación | |
LinkButton | LinkButtonEffacerSimulation | borra el formulario de entrada | |
LinkButton | LinkButtonVoirSimulations | muestra la lista de simulaciones ya realizadas | |
LinkButton | LinkButtonFormulaireSimulation | vuelve al formulario de ingreso | |
LinkButton | LinkButtonEnregistrerSimulation | guarda la simulación actual en la lista de simulaciones | |
LinkButton | LinkButtonTerminerSession | cierra la sesión actual |
8.5.3. La vista [Saisies]
El componente [View], denominado [VueSaisies], es el siguiente:
![]() |
N.º | Tipo | Nombre | Función |
DropDownList | ComboBoxEmployes | Contiene la lista de nombres de los empleados | |
TextBox | TextBoxHeures | Número de horas trabajadas – número real | |
TextBox | TextBoxJours | Número de días trabajados – número entero | |
RequiredFieldValidator | RequiredFieldValidatorHeures | verifica que el campo [2] [TextBoxHeures] no esté vacío | |
RegularExpressionValidator | RegularExpressionValidatorHeures | verifica que el campo [2] [TextBoxHeures] sea un número real >=0 | |
RequiredFieldValidator | RequiredFieldValidatorJours | verifica que el campo [3] [TextBoxJours] no esté vacío | |
RegularExpressionValidator | RegularExpressionValidatorJours | verifica que el campo [3] [TextBoxJours] sea un número entero >=0 |
8.5.4. La vista [Simulation]
El componente [View] denominado [VueSimulation] es el siguiente:

Está compuesto únicamente por componentes [Label], de los cuales los ID se indican más arriba.
8.5.5. La vista [Simulations]
El componente [View], denominado [VueSimulations], es el siguiente:
![]() |
N.º | Tipo | Nombre | Función |
GridView | GridViewSimulations | Contiene la lista de simulaciones |
Las propiedades del componente [GridViewSimulations] se han definido de la siguiente manera:
![]() |
- en [1]: clic derecho en el [GridView] / opción [Mise en forme automatique]
- a [2]: elegir un tipo de visualización para el [GridView]
![]() |
- en [3]: seleccionar las propiedades del [GridView]
- en [4]: editar las columnas del [GridView]
- en [5]: agregar una columna del tipo [BoundField] que estará vinculada (bound) a una de las propiedades públicas del objeto que se mostrará en la fila de [GridView]. El objeto que se mostrará aquí será un objeto de tipo [Simulation].
![]() |
- en [6]: indique el título de la columna
- en [7]: indique el nombre de la propiedad de la clase [Simulation] que se asociará a esta columna.
- [DataFormatString] indica cómo deben formatearse los valores que se muestran en la columna.
Las columnas del componente [GridViewSimulations] tienen las siguientes propiedades:
N.º | Propiedades |
Tipo: BoundField, HeaderText: Nombre, DataField: Nombre | |
Tipo: BoundField, HeaderText: Apellido, DataField: Apellido | |
Tipo: BoundField, HeaderText: Horas trabajadas, DataField: HeuresTravaillees | |
Tipo: BoundField, HeaderText: Días trabajados, DataField: JoursTravailles | |
Tipo: BoundField, HeaderText: Salario base, DataField: SalaireBase, DataFormatString: {0:C} (formato monetario, C = moneda) – mostrará el símbolo del euro. | |
Tipo: BoundField, HeaderText: Compensaciones, Campo de datos: Indemnites, DataFormatString: {0:C} | |
Tipo: BoundField, HeaderText: Contribuciones sociales, DataField: CotisationsSociales, DataFormatString: {0:C} | |
Tipo: BoundField, HeaderText: Salario neto, DataField: SalaireNet, DataFormatString: {0:C} |
Se debe prestar atención al hecho de que el campo [DataField] debe corresponder a una propiedad existente de la clase [Simulation]. Al finalizar esta fase, se han creado todas las columnas de tipo [BoundField]:
![]() |
- en [1]: las columnas creadas para [GridView]
- en [2]: la generación automática de columnas debe desactivarse cuando es el desarrollador quien las define por sí mismo, tal como acabamos de hacerlo.
Nos queda por crear la columna de enlaces [Retirer]:

![]() |
- en [1]: agregar una columna de tipo [CommandField / Supprimer]
- en [2]: ButtonType=Link para tener un enlace en la columna en lugar de un botón
- en [3]: CausesValidation=False; al hacer clic en el enlace no se ejecutarán los controles de validación que puedan encontrarse en la página. De hecho, la eliminación de una simulación no requiere ninguna verificación de datos.
- en [4]: solo será visible el enlace de eliminación.
- en [5]: el texto de este enlace
8.5.6. La vista [SimulationsVides]
El componente [View], denominado [VueSimulationsVides], contiene simplemente texto:
8.5.7. La vista [Erreurs]
El componente [View], denominado [VueErreurs], es el siguiente:
![]() |
N.º | Tipo | Nombre | Función |
Repetidor | RptErreurs | muestra una lista de mensajes de error |
El componente [Repeater] permite repetir un código ASP.NET / HTML para cada objeto de una fuente de datos, generalmente una colección. Este código se define directamente en el código fuente ASP.NET de la página:
<asp:Repeater ID="RptErreurs" runat="server">
<ItemTemplate>
<li>
<%# Container.DataItem %>
</li>
</ItemTemplate>
</asp:Repeater>
- línea 2: <ItemTemplate> define el código que se repetirá para cada elemento de la fuente de datos.
- línea 4: muestra el valor de la expresión Container.DataItem, que designa el elemento actual de la fuente de datos. Dado que este elemento es un objeto, se utiliza el método ToString de dicho objeto para incluirlo en el flujo HTML de la página. Nuestra colección de objetos será una colección List(Of String) que contiene mensajes de error. Las líneas 3 a 5 incluirán secuencias <li>Message</li> en el flujo HTML de la página.
8.6. El controlador [Default.aspx.cs]
8.6.1. Visión general
Volvamos a la arquitectura MVC de la aplicación:
![]() |
- [Default.aspx.cs], que es el código de control de la página única [Default.aspx], es el controlador de la aplicación.
- [Global] es el objeto de tipo [HttpApplication] que inicializa la aplicación y que cuenta con una referencia a la capa [métier].
El esqueleto del código del controlador [Default.aspx.cs] es el siguiente:
using System.Collections.Generic;
...
public partial class PagePam : Page
{
private void setVues(bool boolVues1, bool boolVues2, int index)
{
// se muestran las vistas solicitadas
// boolVues1: verdadero si la vista múltiple Vistas1 debe estar visible
// boolVues1: verdadero si el grupo de vistas Vistas2 debe estar visible
// índice: índice de la vista de Vistas2 que se mostrará
...
}
private void setMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
{
// se configuran las opciones del menú
// cada valor booleano se asigna a la propiedad Visible del enlace correspondiente
...
}
// carga de la página
protected void Page_Load(object sender, System.EventArgs e)
{
// procesamiento de la solicitud inicial
if (!IsPostBack)
{
...
}
}
protected void LinkButtonFaireSimulation_Click(object sender, System.EventArgs e)
{
...
}
protected void LinkButtonEffacerSimulation_Click(object sender, System.EventArgs e)
{
....
}
protected void LinkButtonVoirSimulations_Click(object sender, System.EventArgs e)
{
...
}
protected void LinkButtonEnregistrerSimulation_Click(object sender, System.EventArgs e)
{
...
}
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
...
}
protected void LinkButtonFormulaireSimulation_Click(object sender, System.EventArgs e)
{
...
}
protected void GridViewSimulations_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
...
}
}
En la solicitud inicial (GET) del usuario, solo se procesa el evento Load de las líneas 24 a 31. En las solicitudes siguientes (POST) realizadas a través de los enlaces del menú, se procesan dos eventos:
- el evento Load (24-31), pero la comprobación del valor booleano Page.IsPostback (línea 27) hace que no se realice ninguna acción.
- el evento relacionado con el enlace en el que se hizo clic:
![]() |
- líneas 33-36: procesan el clic en el enlace [1]
- líneas 38-41: procesan el clic en el enlace [2]
- líneas 43-46: procesan el clic en el enlace [3]
- líneas 58-61: procesan el clic en el enlace [4]
- líneas 48-51: procesan el clic en el enlace [5]
- líneas 53-56: procesan el clic en el enlace [6]
Para factorizar secuencias de código que se repiten con frecuencia, se han creado dos métodos internos:
- setVues, líneas 7-14: establece la vista o las vistas que se mostrarán
- setMenu, líneas 16-21: establece las opciones de menú que se mostrarán
8.6.2. El evento Load
Lecturas recomendadas: referencia [1], Desarrollo WEB con ASP.NET 1.1:
- párrafo «Componente [Repeater] y enlace de datos».
La primera vista que se le muestra al usuario es la del formulario en blanco:

La inicialización de la aplicación requiere acceso a una fuente de datos, lo cual puede fallar. En ese caso, la primera página que se muestra es una página de errores:

El evento [Load] se procesa de manera similar a la de las versiones anteriores de ASP.NET:
// carga de la página
protected void Page_Load(object sender, System.EventArgs e)
{
// procesamiento de la solicitud inicial
if (!IsPostBack)
{
// ¿Errores de inicialización?
if (Global.Erreur)
{
// Visualización de la vista [erreurs]
...
// posicionamiento del menú
...
return;
}
// carga de los nombres de los empleados en el menú desplegable
...
// posicionamiento del menú
...
// visualización de la vista [saisie]
...
}
}
Pregunta: complete el código anterior
8.6.3. Acción: Realizar la simulación
A continuación, la pantalla marcada con (1) es la de la solicitud del usuario, y la marcada con (2), la respuesta que le envía la aplicación web. Desde la pantalla de inicio, el usuario puede iniciar una simulación:


![]() |
El procedimiento que procesa esta acción podría ser similar al siguiente:
protected void LinkButtonFaireSimulation_Click(object sender, System.EventArgs e)
{
// cálculo del salario
// ¿Página válida?
Page.Validate();
if (!Page.IsValid)
{
// visualización de la vista [saisie]
...
return;
}
// la página es válida: se recuperan los datos ingresados
double HeuresTravaillées = ...;
int JoursTravaillés = ...;
// se calcula el salario del empleado
FeuilleSalaire feuillesalaire;
try
{
feuillesalaire = ...
}
catch (PamException ex)
{
// visualización de la vista [erreurs]
...
return;
}
// se guarda el resultado en la sesión
Session["simulation"] = ...
// visualización de resultados
...
// visualización de vistas [saisie, employe, salaire]
...
// visualización del menú
...
}
Pregunta: completa el código anterior
8.6.4. Acción: Guardar la simulación
Una vez realizada la simulación, el usuario puede solicitar su grabación:
![]() |

El procedimiento que procesa esta acción podría ser similar al siguiente:
protected void LinkButtonEnregistrerSimulation_Click(object sender, System.EventArgs e)
{
// se guarda la simulación actual en la lista de simulaciones de la sesión
...
// se muestra la vista [simulations]
...
}
Pregunta: complete el código anterior
8.6.5. Acción: Regresar al formulario de simulación
Lecturas recomendadas: referencia [1], [Développement WEB avec ASP.NET 1.1 ]: la función del campo oculto _VIEWSTATE
Una vez que se muestra la lista de simulaciones, el usuario puede solicitar regresar al formulario de simulación:
![]() |
Cabe señalar que la pantalla (2) muestra el formulario tal como se ingresó. Es importante recordar que estas diferentes vistas pertenecen a una misma página. Entre las distintas consultas, los valores de los componentes se conservan mediante el mecanismo de ViewState si dichos componentes tienen su propiedad EnableViewState establecida en true.
El procedimiento que procesa esta acción podría ser similar al siguiente:
protected void LinkButtonFormulaireSimulation_Click(object sender, System.EventArgs e)
{
// visualización de la vista [saisie]
...
// selección del menú
...
}
Pregunta: completar el código anterior
8.6.6. Acción: Borrar la simulación
Una vez de regreso al formulario de simulación, el usuario puede solicitar borrar los datos ingresados:
![]() |
El procedimiento que procesa esta acción podría ser similar al siguiente:
protected void LinkButtonEffacerSimulation_Click(object sender, System.EventArgs e)
{
// RAZ del formulario
...
}
Pregunta: completar el código anterior
8.6.7. Acción: Ver las simulaciones
El usuario puede solicitar ver las simulaciones que ya ha realizado:
![]() |
![]() |
El procedimiento que procesa esta acción podría ser similar al siguiente:
protected void LinkButtonVoirSimulations_Click(object sender, System.EventArgs e)
{
// se recuperan las simulaciones en la sesión
...
// ¿Hay simulaciones?
if (...)
{
// vista [simulations] visible
...
}
else
{
// vista [SimulationsVides]
...
}
// se fija el menú
...
}
Pregunta: completa el código anterior
8.6.8. Acción: Eliminar una simulación
El usuario puede solicitar la eliminación de una simulación:
![]() |
![]() |
El procedimiento [GridViewSimulations_RowDeleting ] que procesa esta acción podría tener el siguiente aspecto:
protected void GridViewSimulations_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
// se recuperan las simulaciones de la sesión
...
// se elimina la simulación indicada (e.RowIndex es el número de la línea eliminada)
...
// ¿Quedan simulaciones?
if (...)
{
// se completa el GridView
...
}
else
{
// vista [SimulationsVides]
...
}
}
Pregunta: complete el código anterior
8.6.9. Acción: Finalizar la sesión
El usuario puede solicitar finalizar su sesión de simulaciones. Esto descarta el contenido de su sesión y muestra un formulario en blanco:
![]() |
![]() |
El procedimiento que procesa esta acción podría ser similar al siguiente:
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
// se cierra la sesión
...
// mostrar la vista [saisies]
...
// posicionamiento del menú
...
}
Pregunta: completa el código anterior
Ejercicio práctico: implementa en una máquina la aplicación web anterior. Agregale funcionalidad Ajax.






















