Marcos de Desarrollo
Diseño e implementación de aplicaciones Web con .NET
Contenido
En este apartado estudiaremos el diseño e implementación de las capas controlador y vista de MiniBank
Configuración de la aplicación Web
Página maestra de MiniBank
Un ejemplo de una acción que realiza una operación que no visualiza resultados
Transferencia bancaria
Un ejemplo de una acción que realiza una operación y visualiza el resultado de la operación
Búsqueda de cuentas bancarias por identificador de cuenta (resultado en una página) o de usuario (resultado en varias páginas)
Internacionalización
Introducción
Configuración: Web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<!‐‐ Cultural preferences of the Web site ‐‐>
<globalization culture="auto" uiCulture="auto" />
<!‐‐ Valid Options: UseUri (True), UseCookies (False), AutoDetect ‐‐>
<sessionState cookieless="AutoDetect" timeout="30" />
<!‐‐ Valid Options: On, Off, RemoteOnly ‐‐>
<customErrors mode="RemoteOnly" defaultRedirect="/Errors/InternalError.aspx">
</customErrors>
<<...>>
</system.web>
<!‐‐ Unity configuration block ‐‐>
<unity>
<!‐‐ Identico a App.config en MiniBank (model) ‐‐>
</unity>
Configuración: Web.config
<applicationSettings>
<Es.Udc.DotNet.MiniBank.Web.Properties.Settings>
<setting name="MiniBank_defaultCount" serializeAs="String">
<value>2</value>
</setting>
...
</Es.Udc.DotNet.MiniBank.Web.Properties.Settings>
</applicationSettings>
No confundir con appSettings
No actualizar esta sección directamente
sobre Web.config, sino desde la pestaña
de configuración del proyecto =>
actualiza Settings.settings y
Settings.designer.cs
Configuración: Web.config
Pestaña Settings en las propiedades del proyecto
Permite acceso "tipado".
P. ej.: Settings.Default.MiniBank_defaultCount;
Configuración: Global.asax
namespace Es.Udc.DotNet.MiniBank.Web
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
Application.Lock();
IUnityContainer container = new UnityContainer();
UnityConfigurationSection section =
(UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(container);
Application["UnityContainer"] = container;
Application.UnLock();
}
<<...>>
Configuración: otras opciones
Contenido
En este apartado estudiaremos el diseño e implementación de las capas controlador y vista de MiniBank
Configuración de la aplicación Web
Página maestra de MiniBank
Un ejemplo de una acción que realiza una operación que no visualiza resultados
Transferencia bancaria
Un ejemplo de una acción que realiza una operación y visualiza el resultado de la operación
Búsqueda de cuentas bancarias por:
identificador de cuenta (resultado en una página)
identificador de usuario (resultado en varias páginas)
Internacionalización
MiniBank.Master: Vista de diseño
MiniBank.Master: Vista de código
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="MiniBank.master.cs"
Inherits="Es.Udc.DotNet.MiniBank.Web.MiniBank" %>
<!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 runat="server">
<title>MiniBank</title>
<meta http‐equiv="Content‐Type" content="text/html; charset=iso‐8859‐1"/>
<link href="~/Img/MiniBank.ico" rel="Shortcut Icon" />
<link href="~/Css/MiniBank.Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="window">
<!‐‐ Body Header. ‐‐>
<div id="header">
<asp:Localize ID="lclHeader" runat="server" meta:resourcekey="lclHeader" />
</div>
MiniBank.Master: Vista de código
<!‐‐ Main Content. ‐‐>
<div id="pageBody">
<div id="sidebar">
<ul>
<li>
<asp:HyperLink ID="lnkHome" runat="server" meta:resourcekey="lnkHome"
NavigateUrl="~/Pages/MainPage.aspx" />
</li>
<!‐‐ Mas HyperLinks... ‐‐>
</ul>
</div>
<div id="content">
<asp:ContentPlaceHolder ID="ContentPlaceHolderMain" runat="server">
</asp:ContentPlaceHolder>
</div>
</div>
<!‐‐ Footer. ‐‐>
<div id="footer">
<asp:Localize ID="lclFooter" runat="server" meta:resourcekey="lclFooter" />
</div>
</div>
</body>
</html>
MiniBank.Master.cs
using System;
namespace Es.Udc.DotNet.MiniBank.Web
{
public partial class MiniBank : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
}
MiniBank.Master.designer.cs
namespace Es.Udc.DotNet.MiniBank.Web {
public partial class MiniBank {
protected global::System.Web.UI.WebControls.Localize lclHeader;
protected global::System.Web.UI.WebControls.HyperLink lnkHome;
protected global::System.Web.UI.WebControls.HyperLink lnkCreate;
<<...>>
protected global::System.Web.UI.WebControls.ContentPlaceHolder
ContentPlaceHolderMain;
protected global::System.Web.UI.WebControls.Localize lclFooter;
}
}
Contenido
En este apartado estudiaremos el diseño e implementación de las capas controlador y vista de MiniBank
Configuración de la aplicación Web
Página maestra de MiniBank
Un ejemplo de una acción que realiza una operación que no visualiza resultados
Transferencia bancaria
Un ejemplo de una acción que realiza una operación y visualiza el resultado de la operación
Búsqueda de cuentas bancarias por:
identificador de cuenta (resultado en una página)
identificador de usuario (resultado en varias páginas)
Internacionalización
Transferencia
Transfer.aspx
SuccessfulOperation.aspx
Transferencia: Transfer.aspx (Vista de diseño)
Transferencia: Transfer.aspx.designer.cs
namespace Es.Udc.DotNet.MiniBank.Web.Pages {
public partial class Transfer {
protected global::System.Web.UI.HtmlControls.HtmlForm TransferForm;
protected global::System.Web.UI.WebControls.Localize lclSourceAccId;
protected global::System.Web.UI.WebControls.Localize lclDestinationAccId;
protected global::System.Web.UI.WebControls.Localize lclAmount;
protected global::System.Web.UI.WebControls.TextBox txtSourceAccId;
protected global::System.Web.UI.WebControls.TextBox txtDestinationAccId;
protected global::System.Web.UI.WebControls.TextBox txtAmount;
protected global::System.Web.UI.WebControls.Label lblSourceAccError;
protected global::System.Web.UI.WebControls.Label lblDestinationAccError;
protected global::System.Web.UI.WebControls.Label lblAmountError;
Transferencia: Transfer.aspx.designer.cs
protected global::System.Web.UI.WebControls.RequiredFieldValidator
rfvSourceAccId;
protected global::System.Web.UI.WebControls.RequiredFieldValidator
rfvDestinationAccId;
protected global::System.Web.UI.WebControls.RequiredFieldValidator
rfvBalance;
protected global::System.Web.UI.WebControls.RegularExpressionValidator
typeSourceAccIdValidator;
protected global::System.Web.UI.WebControls.RegularExpressionValidator
typeDestinationAccId;
protected global::System.Web.UI.WebControls.RegularExpressionValidator
typeAmountValidator;
protected global::System.Web.UI.WebControls.Button btnTransfer;
}
}
Transferencia: Transfer.aspx (Vista de código)
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Transfer.aspx.cs"
Inherits="Es.Udc.DotNet.MiniBank.Web.Pages.Transfer" MasterPageFile="~/MiniBank.Master" %>
<asp:Content ID="content" ContentPlaceHolderID="ContentPlaceHolderMain" runat="server">
<div id="form">
<form id="TransferForm" method="post" runat="server">
<div class="field">
<span class="label">
<asp:Localize ID="lclSourceAccId" runat="server"
Localización explícita. Acceso a archivo
meta:resourcekey="lclSourceAccId" /></span>
de recursos global llamado "Common"
(Common.resx, Common.es-ES.resx, …).
<span class="entry">
<asp:TextBox ID="txtSourceAccId" runat="server" Width="200px"
Mensaje: "Invalid data type"
Columns="16"></asp:TextBox>
<asp:RegularExpressionValidator ID="typeSourceAccIdValidator" runat="server"
ControlToValidate="txtSourceAccId" Text="<%$ Resources: Common, typeError %>" ValidationExpression="(\d)*" CssClass="errorMessage" Display="Dynamic">
</asp:RegularExpressionValidator>
Transferencia: Transfer.aspx (Vista de código)
<asp:RequiredFieldValidator ID="rfvSourceAccId" runat="server"
ControlToValidate="txtSourceAccId" Display="Dynamic"
Text="<%$ Resources: Common, mandatoryField %>" CssClass="errorMessage">
</asp:RequiredFieldValidator>
<asp:Label ID="lblSourceAccError" runat="server" CssClass="errorMessage"
meta:resourcekey="lblSourceAccError">
</asp:Label>
Localización implícita. Acceso a archivo
</span>
de recursos local asociado a
</div>
Transfer.aspx
(Transfer.resx, Transfer.es-Es.resx, …)
<<...>>
Mensaje: "Source Account not Found"
<div class="button">
<asp:Button ID="btnTransfer" runat="server" meta:resourcekey="btnTransfer"
OnClick="BtnTransfer_Click" />
</div>
</form>
Indica el nombre del método que tratará
</div>
el evento OnClick
</asp:Content>
Transferencia: Transfer.aspx.cs
public partial class Transfer : SpecificCulturePage
{
protected void Page_Load(object sender, EventArgs e)
{
lblSourceAccError.Visible = false;
lblDestinationAccError.Visible = false;
lblAmountError.Visible = false;
}
protected void BtnTransfer_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
/* Get data. */
long sourceAccountIdentifier = Convert.ToInt32(txtSourceAccId.Text);
long destinationAccountIdentifier = Convert.ToInt32(txtDestinationAccId.Text);
double amount = Convert.ToInt64(txtAmount.Text);
Transferencia: Transfer.aspx.cs
/* Transfer. */
try
{
/* Get the Service */
IUnityContainer container = (IUnityContainer)Application["unityContainer"];
IAccountService accountService = container.Resolve<IAccountService>();
accountService.Transfer(sourceAccountIdentifier, destinationAccountIdentifier, amount);
Response.Redirect(Response.
ApplyAppPathModifier("./SuccessfulOperation.aspx"));
}
Transferencia: Transfer.aspx.cs
catch (InstanceNotFoundException ex)
{
long key = (long)ex.Key;
/* Process errors and show labels */
if (key.Equals(sourceAccountIdentifier))
lblSourceAccError.Visible = true;
else
lblDestinationAccError.Visible = true;
}
catch (InsufficientBalanceException ex)
{
/* lblAmmountError.Text is something like "Insufficient balance * in source account (balance = {0})" */
String labelText = String.Format(
(string)GetLocalResourceObject("lblAmountError.Text"),
ex.CurrentBalance);
lblAmountError.Text = labelText;
lblAmountError.Visible = true;
}
} // if
} // BtnTransferClick
} // Transfer Class
Queremos que se muestre el saldo
como parte del mensaje, con soporte
para internacionalización
Contenido
En este apartado estudiaremos el diseño e implementación de las capas controlador y vista de MiniBank
Configuración de la aplicación Web
Página maestra de MiniBank
Un ejemplo de una acción que realiza una operación que no visualiza resultados
Transferencia bancaria
Un ejemplo de una acción que realiza una operación y visualiza el resultado de la operación
Búsqueda de cuentas bancarias por:
identificador de cuenta (resultado en una página)
identificador de usuario (resultado en varias páginas)
Internacionalización
Búsqueda de cuentas por identificador de cuenta
FindAccounts.aspx
ShowAccountByAccID.aspx
Búsqueda de cuentas por identificador de usuario
FindAccounts.aspx
ShowAccountsByUserID.aspx
Búsqueda de cuentas: FindAccounts.aspx (Vista de diseño)
Búsqueda de cuentas: FindAccounts.aspx (Vista de código)
<asp:Content ID="content1" ContentPlaceHolderID="ContentPlaceHolderMain"
runat="server">
<div id="form">
<form id="FindForm" method="post" runat="server">
<div class="field">
<span class="label">
<asp:Localize ID="lclIdentifier" runat="server"
meta:resourcekey="lblIdentifier" />
</span>
<span class="entry">
<asp:TextBox ID="txtIdentifier" runat="server" Width="200px"
Columns="16" />
<asp:RegularExpressionValidator ID="typeValidator" runat="server"
ControlToValidate="txtIdentifier" ValidationExpression="(\d)*"
Text="<%$ Resources: Common, typeError %>" Display="Dynamic"
CssClass="errorMessage" />
<asp:RequiredFieldValidator ID="rfvIdentifier" runat="server"
ControlToValidate="txtIdentifier" Display="Dynamic"
Text="<%$ Resources: Common, mandatoryField %>"
CssClass="errorMessage" />
<asp:Label CssClass="errorMessage" ID="lblIdentifierError"
runat="server" meta:resourcekey="lblIdentifierError" />
</span>
</div>
Búsqueda de cuentas: FindAccounts.aspx (Vista de código)
<div class="field">
<span class="label">
<asp:Localize ID="lclFindBy" runat="server"
meta:resourcekey="lclFindBy" />
</span>
<span class="entry">
<asp:DropDownList ID="ddlFindBy" runat="server" Width="200px">
<asp:ListItem Value="accID"
Text="<%$ Resources:Common, accId %>" />
<asp:ListItem Value="userID"
Text="<%$ Resources:Common, userId %>" />
</asp:DropDownList>
</span>
</div>
<div class="button">
<asp:Button ID="btnFind" runat="server" meta:resourcekey="btnFind"
OnClick="BtnFind_Click" />
</div>
</form>
</div>
</asp:Content>
Búsqueda de cuentas: FindAccounts.aspx.cs
public partial class FindAccounts : SpecificCulturePage
{
protected void Page_Load(object sender, EventArgs e)
{
lblIdentifierError.Visible = false;
}
Búsqueda de cuentas: FindAccounts.aspx.cs
protected void BtnFind_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
/* Get data. */
String identifierType = this.ddlFindBy.SelectedValue;
Int32 identifier = Convert.ToInt32(this.txtIdentifier.Text);
/* Do action. */
if (identifierType == "accID")
{
FindAccountByAccountIdentifier(identifier);
}
else
{
String url = String.Format("./ShowAccountsByUserID.aspx?userID={0}", identifier);
Response.Redirect(Response.ApplyAppPathModifier(url));
}
}
Búsqueda de cuentas: FindAccounts.aspx.cs
private void FindAccountByAccountIdentifier(long accountIdentifier)
{
try
{
/* Get the Service */
/* Get Account Data */
Account account = accountService.FindAccount(accountIdentifier);
/* Attach data to context */
Context.Items.Add("account", account);
/* Transfer to visualization WebForm */
Server.Transfer(Response.
ApplyAppPathModifier("./ShowAccountByAccID.aspx"));
}
catch (InstanceNotFoundException)
{
lblIdentifierError.Visible = true;
}
}
}
Búsqueda de cuentas: FindAccounts.aspx.cs
private void FindAccountByAccountIdentifier(long accountIdentifier)
{
try
{
/* Get the Service */
/* Get Account Data */
Account account = accountService.FindAccount(accountIdentifier);
/* Attach data to context */
Context.Items.Add("account", account);
Permite almacenar datos que se
necesitarán más adelante, durante el
mismo postback
/* Transfer to visualization WebForm */
Server.Transfer(Response.
ApplyAppPathModifier("./ShowAccountByAccID.aspx"));
}
catch (InstanceNotFoundException)
{
lblIdentifierError.Visible = true;
}
}
}
Búsqueda de cuentas por identificador de cuenta
FindAccounts.aspx
ShowAccountByAccID.aspx
Búsqueda de cuentas: ShowAccountByAccID.aspx (Vista de diseño)
Búsqueda de cuentas: ShowAccountByAccID.aspx (Vista de código)
<asp:Content ID="content1" ContentPlaceHolderID="ContentPlaceHolderMain" runat="server">
<asp:Table CssClass="accountDetails" ID="TableAccountInfo" runat="server">
<asp:TableRow runat="server">
<asp:TableHeaderCell ID="cellCaptionAccountID" runat="server"
Text="<%$ Resources:Common, accId %>"></asp:TableHeaderCell>
<asp:TableCell ID="cellAccountID" runat="server"></asp:TableCell>
</asp:TableRow>
<asp:TableRow runat="server">
<asp:TableHeaderCell ID="cellCaptionUserID" runat="server"
Text="<%$ Resources:Common, userId %>"></asp:TableHeaderCell>
<asp:TableCell ID="cellUserID" runat="server"></asp:TableCell>
</asp:TableRow>
<asp:TableRow runat="server">
<asp:TableHeaderCell ID="cellCaptionBalance" runat="server"
Text="<%$ Resources:Common, balance %>"></asp:TableHeaderCell>
<asp:TableCell ID="cellBalance" runat="server"></asp:TableCell>
</asp:TableRow>
</asp:Table>
</asp:Content>
Búsqueda de cuentas: ShowAccountByAccID.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
Account account = (Account)Context.Items["account"];
cellAccountID.Text = account.accId.ToString();
cellUserID.Text = account.usrId.ToString();
cellBalance.Text = account.balance.ToString();
}
Búsqueda de cuentas por identificador de usuario
FindAccounts.aspx
ShowAccountsByUserID.aspx
Búsqueda de cuentas: ShowAccountsByUserID.aspx (Vista de diseño)
GridView
Tipos de columnas
BoundField, CheckBox, ButtonField, HyperLinkField, etc.
No es obligatorio indicar las columnas, pueden autogenerarse
AutoGenerateColumns=True muestra todo el contenido del origen de datos
Code‐Behind:
gvXXX.DataSource = <<...>>;
gvXXX.DataBind();
// Origen de Datos: DataTable, ArrayList, ...
GridView
Ofrece la posibilidad de realizar la paginación de los resultados
Propiedades
AllowPaging: habilita la paginación
PageIndex: índice de la página a mostrar (zero‐based)
PageSize: número de registros por página
… pero recupera la totalidad de los datos y posteriormente los pagina
Ideal: recuperar únicamente los datos que serán mostrados
GridView
Opciones:
Opción 1: Separar representación visual de comportamiento
Se ilustra en ShowAccountsByUserID
Opción 2: ObjectDataSource
Se ilustra en ShowAccOperations
GridView
Opción 1: Separar representación visual de comportamiento
Datos se recuperan a partir de un caso de uso que soporta paginación
/* Get Accounts Info */
List<Account> accounts = accountService.FindAccountsByUserIdentifier(userID, startIndex, count);
GridView visualiza los datos
Estableciendo el DataSource adecuado y realizando el DataBind
Paginación se delega en sendos linkButtons para avanzar y retroceder página
Búsqueda de cuentas: ShowAccountsByUserID.aspx (Vista de código)
<asp:Content ID="content1" ContentPlaceHolderID="ContentPlaceHolderMain"
runat="server">
<form runat="server">
<p>
<asp:Label ID="lblNoUserAccounts" meta:resourcekey="lblNoUserAccounts"
runat="server">
</asp:Label>
</p>
<asp:GridView ID="gvUserAccounts" runat="server" CssClass="userAccounts"
GridLines="None" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="accId"
HeaderText="<%$ Resources:Common, accId %>" />
<asp:BoundField DataField="balance"
HeaderText="<%$ Resources:Common, balance %>" />
</Columns>
</asp:GridView>
</form>
Búsqueda de cuentas: ShowAccountsByUserID.aspx (Vista de código)
<!‐‐ "Previous" and "Next" links. ‐‐>
<div class="previousNextLinks">
<span class="previousLink">
<asp:HyperLink ID="lnkPrevious" Text="<%$ Resources:Common, Previous %>"
runat="server" Visible="False">
</asp:HyperLink>
</span>
<span class="nextLink">
<asp:HyperLink ID="lnkNext" Text="<%$ Resources:Common, Next %>"
runat="server" Visible="False">
</asp:HyperLink>
</span>
</div>
</asp:Content>
Los enlaces next y previous son controles asp:HyperLink, que pueden gestionarse
fácilmente desde CB, controlando si deben mostrarse o no, así como la ruta a la que
apuntan.
Búsqueda de cuentas: ShowAccountsByUserID.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
int startIndex, count;
lnkPrevious.Visible = false;
lnkNext.Visible = false;
lblNoUserAccounts.Visible = false;
/* Get User Identifier passed as parameter in the request from * the previous page */
long userID = Convert.ToInt32(Request.Params.Get("userID"));
/* Get Start Index */
try
{
startIndex = Int32.Parse(Request.Params.Get("startIndex"));
}
catch (ArgumentNullException)
{
startIndex = 0;
}
Búsqueda de cuentas: ShowAccountsByUserID.aspx.cs
/* Get Count */
try
{
count = Int32.Parse(Request.Params.Get("count"));
}
catch (ArgumentNullException)
{
count = Settings.Default.MiniBank_defaultCount;
}
/* Get the Service */
IUnityContainer container = ...
/* Get Accounts Info */
List<Account> accounts = accountService.FindAccountsByUserIdentifier(userID, startIndex, count);
if (accounts.Count == 0)
{
lblNoUserAccounts.Visible = true;
return;
}
Búsqueda de cuentas: ShowAccountsByUserID.aspx.cs
this.gvUserAccounts.DataSource = accounts;
this.gvUserAccounts.DataBind();
/* Get the number of accounts in order to manage the previous * and next links */
int numberOfAccounts = accountService.GetNumberOfAccounts(userID);
/* "Previous" link */
if ((startIndex ‐ count) >= 0)
{
String url = Settings.Default.MiniBank_applicationURL +
"/ShowAccountsByUserID.aspx" + "?userID=" + userID +
"&startIndex=" + (startIndex ‐ count) + "&count=" + count;
this.lnkPrevious.NavigateUrl = Response.ApplyAppPathModifier(url);
this.lnkPrevious.Visible = true;
}
Búsqueda de cuentas: ShowAccountsByUserID.aspx.cs
/* "Next" link */
if ((startIndex + count) < numberOfAccounts)
{
String url = Settings.Default.MiniBank_applicationURL +
"/ShowAccountsByUserID.aspx" + "?userID=" + userID +
"&startIndex=" + (startIndex + count) + "&count=" + count;
this.lnkNext.NavigateUrl = Response.ApplyAppPathModifier(url);
this.lnkNext.Visible = true;
}
}
GridView
Opciones:
Opción 1: Separar representación visual de comportamiento
Se ilustra en ShowAccountsByUserID
Opción 2: ObjectDataSource
Se ilustra en ShowAccOperations
Búsqueda de operaciones bancarias
FindAccountOperations.aspx
ShowAccOperations.aspx
GridView
Opción 2: ObjectDataSource
Componente que permite recuperar objetos bajo demanda de un repositorio y enlazarlos como un origen de datos
ObjectDataSource
Propiedades relacionadas con la paginación
EnablePaging
TypeName: indica el tipo de dato que define los métodos empleados para realizar la paginación
e.g.: Es.Udc.DotNet.MiniBank.Model.AccountService.AccountService
SelectMethod: nombre del método que realiza la búsqueda mediante Page‐by‐Page
e.g.: FindAccountOperationsByDate
Los parámetros específicos se indican mediante la colección SelectParameters
.SelectParameters.Add("accountIdentifier", DbType.Int64,
accID.ToString());
.SelectParameters.Add("startDate", DbType.DateTime,
startDate.ToString());
.SelectParameters.Add("endDate", DbType.DateTime,
endDate.ToString());
ObjectDataSource
Propiedades relacionadas con la paginación (cont.)
SelectCountMethod: nombre del método que devuelve el número máximo de registros
e.g.: GetNumberofAccountOperations
StartRowIndexParameterName: nombre del parámetro que indica el registro a partir del cual se búsqueda e.g.: startIndex
MaximumRowsParameterName: Nombre del parámetro que indica el número de registros recuperados por consulta
e.g.: count
ObjectDataSource
Funcionamiento
Se crea automáticamente una instancia del tipo declarado en DataSource.TypeName
pbpDataSource.TypeName = "Es.Udc.DotNet.MiniBank.Model.AccountService.AccountService"; implica una llamada a new AccountService();
Problema: en MiniBank la instanciación de AccountService implica resolución de dependencias, que de esta forma no se realizarán
Solución:
Capturar el evento ObjectCreating y realizar las operaciones necesarias para que se resuelvan las dependencias
ObjectDataSource
Funcionamiento
En Page_Load se declara el delegado
pbpDataSource.ObjectCreating += this.pbpDataSource_ObjectCreating;
Luego se implementa el delegado
protected void pbpDataSource_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
// Aqui se instancia el objeto DataSource.TypeName
// Por defecto: new DataSourceTypeName. Por ej: new AccountService()
// pero se puede dar implementacion alternativa
}
ObjectDataSource
pbpDataSource_ObjectCreating
protected void pbpDataSource_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
/* Get the Service */
IUnityContainer container = (IUnityContainer)
HttpContext.Current.Application["unityContainer"];
IAccountService accountService = new AccountService();
accountService = (IAccountService)
container.BuildUp(accountService.GetType(), accountService);
e.ObjectInstance = accountService;
}
Hace que se carguen las
dependencias de
AccountService.
container.Resolve<IAccountService>();
No funciona.
Búsqueda de operaciones bancarias: ShowAccOperations.aspx (Vista de código)
<asp:Content ID="content" ContentPlaceHolderID="ContentPlaceHolderMain" runat="server">
<p>
<asp:Label ID="lblInvalidAccount" meta:resourcekey="lblInvalidAccount" runat="server" Visible=false></asp:Label>
</p>
<form runat="server">
<asp:GridView ID="gvAccOperations" runat="server" CssClass="accountOperations" AutoGenerateColumns="False" onpageindexchanging="gvAccOperations_PageIndexChanging" ShowHeaderWhenEmpty="True">
<Columns>
<asp:BoundField DataField="Date" HeaderText="<%$ Resources:, date %>" />
<asp:BoundField DataField="Type" HeaderText="<%$ Resources:, type %>" />
<asp:BoundField DataField="Amount" HeaderText="<%$ Resources:, amount %>" />
</Columns>
</asp:GridView>
<br />
</form>
Búsqueda de operaciones bancarias: ShowAccOperations.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
try
{
pbpDataSource.ObjectCreating += this.pbpDataSource_ObjectCreating;
pbpDataSource.TypeName = "Es.Udc.DotNet.MiniBank.Model.AccountService.AccountService";
pbpDataSource.EnablePaging = true;
pbpDataSource.SelectMethod = "FindAccountOperationsByDate";
/* Get Account Identifier */
long accID = Convert.ToInt32(Request.Params.Get("accID"));
/* Get the start and end date (without time) */
DateTime startDate = Convert.ToDateTime(Request.Params.Get("startDate"));
DateTime endDate
//... Búsqueda de operaciones bancarias: ShowAccOperations.aspx.cs (cont)
pbpDataSource.SelectParameters.
Add("accountIdentifier", DbType.Int64, accID.ToString());
pbpDataSource.SelectParameters.
Add("startDate", DbType.DateTime, startDate.ToString());
pbpDataSource.SelectParameters.
Add("endDate", DbType.DateTime, endDate.ToString());
pbpDataSource.SelectCountMethod = "GetNumberofAccountOperations";
pbpDataSource.StartRowIndexParameterName = "startIndex";
pbpDataSource.MaximumRowsParameterName = "count";
gvAccOperations.AllowPaging = true;
int count = Settings.Default.MiniBank_defaultCount;
gvAccOperations.PageSize = count;
gvAccOperations.DataSource = pbpDataSource;
gvAccOperations.DataBind();
}
catch (Exception)
{
lblInvalidAccount.Visible = true;
}
}
Búsqueda de operaciones bancarias: ShowAccOperations.aspx.cs (cont)
protected void gvAccOperations_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
gvAccOperations.PageIndex = e.NewPageIndex;
gvAccOperations.DataBind();
}
protected void pbpDataSource_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
/* Get the Service */
IUnityContainer container = (IUnityContainer)HttpContext.Current.Application["unityContainer"]; IAccountService accountService = new AccountService();
accountService = (IAccountService)container.BuildUp(accountService.GetType(), accountService);
e.ObjectInstance = accountService;
}
Contenido
En este apartado estudiaremos el diseño e implementación de las capas controlador y vista de MiniBank
Configuración de la aplicación Web
Página maestra de MiniBank
Un ejemplo de una acción que realiza una operación que no visualiza resultados
Transferencia bancaria
Un ejemplo de una acción que realiza una operación y visualiza el resultado de la operación
Búsqueda de cuentas bancarias por identificador de cuenta (resultado en una página) o de usuario (resultado en varias páginas)
Internacionalización
Selección de idioma y país Cuando cambia el idioma,
se actualiza la lista de países
y se muestran en el idioma
seleccionado, ordenados
alfabéticamente
SetLocale.aspx
Selección de idioma y país: SetLocale.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
String language;
String country;
if (!IsPostBack)
{
/* * We check if exists a locale in the session. In this case, * we get the language and the region/country from the locale.
* Other case we use the browser preferences to extract the
* language and the region/country
*/
if (!SessionManager.IsLocaleDefined(Context))
{
/* Gets preferred language from browser */
language = GetLanguageFromBrowserPreferences();
country = GetCountryFromBrowserPreferences();
}
Selección de idioma y país: SetLocale.aspx.cs
else
{
Locale locale = SessionManager.GetLocale(Context);
language = locale.Language;
country = locale.Country;
}
/* Finally we update de data of the "Combo", using the
* selected language and region/country.
*/
UpdateComboLanguage(language);
UpdateComboCountry(language, country);
}
}
Selección de idioma y país: SetLocale.aspx.cs
private String GetLanguageFromBrowserPreferences()
{
String language;
CultureInfo cultureInfo = CultureInfo.CreateSpecificCulture(Request.UserLanguages[0]);
language = cultureInfo.TwoLetterISOLanguageName;
return language;
}
Selección de idioma y país: SetLocale.aspx.cs
private String GetCountryFromBrowserPreferences()
{
String country;
CultureInfo cultureInfo = CultureInfo.CreateSpecificCulture(Request.UserLanguages[0]);
if (cultureInfo.IsNeutralCulture)
{
country = "";
}
else
{
// cultureInfoName is something like en‐US
String cultureInfoName = cultureInfo.Name;
// Gets the last two caracters of cultureInfoname
country = cultureInfoName.Substring(cultureInfoName.Length ‐ 2);
}
return country;
}
Selección de idioma y país: SetLocale.aspx.cs
private void UpdateComboLanguage(String selectedLanguage)
{
this.comboLanguage.DataSource = Languages.GetLanguages(selectedLanguage);
this.comboLanguage.DataTextField = "value";
this.comboLanguage.DataValueField = "text";
this.comboLanguage.DataBind();
this.comboLanguage.SelectedValue = selectedLanguage;
}
private void UpdateComboCountry(String selectedLanguage, String selectedCountry)
{
this.comboCountry.DataSource = Countries.GetCountries(selectedLanguage);
this.comboCountry.DataTextField = "value";
this.comboCountry.DataValueField = "text";
this.comboCountry.DataBind();
this.comboCountry.SelectedValue = selectedCountry;
}
Selección de idioma y país: SetLocale.aspx.cs
protected void BtnSetLocale_Click(object sender, EventArgs e)
{
string language = comboLanguage.SelectedValue;
string country = comboCountry.SelectedValue;
Locale locale = new Locale(language, country);
SessionManager.SetLocale(Context, locale);
Response.Redirect(Response.
ApplyAppPathModifier("~/MainPage.aspx"));
}
Selección de idioma y país: SetLocale.aspx.cs
<asp:DropDownList ID="comboLanguage" runat="server" AutoPostBack="True"
Width="100px" OnSelectedIndexChanged="ComboLanguageSelectedIndexChanged">
</asp:DropDownList>
SetLocale.aspx
protected void ComboLanguage_SelectedIndexChanged(object sender, EventArgs e)
{
/* After a language change, the countries are printed in the
* correct language.
*/
this.UpdateComboCountry(comboLanguage.SelectedValue, comboCountry.SelectedValue);
}
SetLocale.aspx.cs
NOTA: prueba a cambiar AutoPostBack="False". ¿Qué ocurre?
SpecificCulturePage
Extiende a System.Web.UI.Page y todas las páginas del sitio deben extenderla
protected override void InitializeCulture()
{
if (SessionManager.IsLocaleDefined(Context))
{
Locale locale = SessionManager.GetLocale(Context);
String culture = locale.Language + "‐" + locale.Country;
CultureInfo cultureInfo;
try
{
cultureInfo = CultureInfo.CreateSpecificCulture(culture);
LogManager.RecordMessage("Specific culture created: " + cultureInfo.Name);
}
catch (ArgumentException)
{
cultureInfo = CultureInfo.CreateSpecificCulture("en‐US");
}
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
}
}
0
Puede agregar este documento a su colección de estudio (s)
Iniciar sesión Disponible sólo para usuarios autorizadosPuede agregar este documento a su lista guardada
Iniciar sesión Disponible sólo para usuarios autorizados(Para quejas, use otra forma )