====== ASP.NET ====== ===== Básico ===== ==== Código ASP.NET ==== Las páginas aspnet son páginas con extensión .aspx donde podemos agregar código aspnet entre código HTML introduciendolo entre ''<% %>''. <% for (int i=0; i <8; i++) { %> Welcome to ASP.NET
<% }%>
En este código podemos acceder a las clases que pone .NET nuestra disposición. Por ejemplo, en el siguiente código se recoge el valor de las variables en la QueryString (la URI de llamada a la página) Name y Category: <% if (Request.QueryString["Lookup"] != null) { %> Hi <%=HttpUtility.HtmlEncode(Request.QueryString["Name"]) %>, you selected: <%=HttpUtility.HtmlEncode(Request.QueryString["Category"]) %> <% } %> ... <%=String.Format("({0}) {1}", DropDownList1.SelectedValue, DropDownList1.SelectedItem.ToString())%> Con esta sintaxis también podemos mostrar texto directamente utilizando ''<%= %>'': <%="Hello World" %> Para incluir código "a saco" utilizaremos '''': Para insertar datos incluidos en recursos, archivos de configuración (''web.config'')... Utilizamos la nomenclatura: ''<%$ ... %>'': Este sólo puede utilizarse dentro de propiedades de controles, si quisiesemos utilizarlo para mostrar un valor necesitaríamos utilizar el control ''Literal'': === Tipos de archivo === * **Extensión .aspx**: páginas web de ASP.NET, contienen el código de la interface de usuario. * **Extensión .ascx**: controles de usuario de ASP.NET, similares a páginas web pero que no pueden ser accedidas directamente. Se utilizan dentro de otras para la reutilización de código. * **Extensión .asmx**: ASP.NET web services. * **Extensión .svc**: ASP.NET web services que utilizan WCF. * **web.config**: Configuración de la aplicación ASP.NET. * **global.asax**: Fichero donde se definen variables globales y reacciones a eventos. * **Extensión .cs**: Código en C#. === Elementos de ASP.NET=== * Una **directiva** es un código que se encuentra en los archivos .aspx y se coloca entre los signos ''<%@'' y ''%>''. Pueden contener atributos que definen sus propiedades siguiendo la siguiente sintaxis: <%@ Nombre atributo="valor" [atributo="valor"...] %> ==== Server Controls y Html Server Controls ==== Los //Html Server Controls// son tags html que se diferencian de las estandard debido a la clausula ''runat="server"'', esto hace que dicho tag se enlace con un objeto en el propio servidor al cual podrá accederse a partir de la id de la tag, el objeto tendra sus propias propiedades y métodos además de que generará un código html que se enviará al cliente. Los objetos que crearán provienen de ''System.Web.HtmlControls'' y, entre otros, son: ''HtmlAnchor, HtmlButton, HtmlForm, HtmlImage, HtmlInputButton, HtmlTable, HtmlTableCell, HtmlTextArea''. Si para una tag concreta no existiese una clase a la que enlazarse directamente lo haría a ''HtmlGenericControl''. \\ \\ De esta forma si tenemos por ejemplo el siguiente código: Podemos asignar la ruta para esta imágen de la siguiente forma: imgSample.Src = "path_to_image/image_name.gif"; O por ejemplo:
...
Y... panel.Visible = false; Los //Server Controls// son //Html Server Controls// pero que no sólo emiten una tag html sino un código algo más extenso que puede contener varias tags colocadas en distinto orden (por ejemplo, también código javascript). Los //Server Controls// tienen las siguientes características: * Se declaran a partir del nombre de la clase: ''asp:nombre''. * Cada declaración de control debe estar cerrada en la misma línea. * Todos los //Server Controls// han de estar dentro de una tag ''form''. Por ejemplo, un //Server Control// muy común es la label, este pasa a convertirse en una tag ''span'': Podemos asignar propiedades y estilos a los controles como si lo hiciesemos a objetos ya creados: Text1.Style["font-size"] = "20px"; Text1.Style["color"] = "red"; Text1.Style.Add("background-color", "lightyellow"); Text1.Value = ""; Text1.Attributes["onfocus"] = "alert(Text1.value)"; El código anterior crearía la siguiente tag html: Podemos agregar todos los ''HtmlControls'' que queramos a partir de la lista ''Controls'' dentro de Page: HtmlTable table1 = new HtmlTable(); ... this.Controls.Add(table1); Para los ''HtmlControls'' existen dos eventos importantes, el ''ServerClick'' y el ''ServerChange''. \\ \\ Un ejemplo de control de servidor:

Name: Category: psychology business popular_comp

En la misma página podemos gestionar los eventos declarando una tag '' Name: El código insertado en un ''script runat="server"'' puede ser accedido desde el código aspnet. <% ... number = subtract(number, 1); ... %> ==== Evento Page_Load ==== La función ''Page_Load'' se llama automáticamente al cargarse una página, siendo esta correspondiente al evento. ==== Code-Behind vs Code-Inline ==== * **Code-Inline** es el modo más parecido al antiguo ASP, todo el código es introducido en el archivo .aspx, resulta útil para aplicaciones pequeñas. * **Code-Behind**, en el que se separa el código del archivo .aspx del de aplicación (.cs). El más interesante es el code-behind, en el que la página se separa en varios archivos (por ejemplo, ''CodeBehind_cs.aspx'' y ''CodeBehind_cs.aspx.cs''), donde el primero contendría toda la parte gráfica de la interficie y el segundo la lógica. El código que se introduciría en la segunda sería una clase parcial que heredase de ''System.Web.UI.Page''. using System; public partial class CodeBehind_cs_aspx : System.Web.UI.Page { protected void Button1_Click(object sender, EventArgs e) { Label1.Text = "Hello " + TextBox1.Text; } } Respecto al Code-Inline decir que es necesario usar la directiva ''@Import'' para hacer accesibles los namespaces de los ensamblados disponibles. ==== Directorios en una aplicación ==== === App_Code === Cuando tenemos un directorio ''App_Code'' en nuestra aplicación podemos agregar en él todo el código que queremos para que sea accesible para todas las páginas. Todos los ficheros que se encuentren en este directorio serán compilados en tiempo de ejecución. \\ Por ejemplo agregamos una clase en el App_Code que no tiene nada que ver con la interface. Luego podemos acceder a dicha clase desde cualquier página. === Bin === Cuando lo que tenemos son librerías ya compiladas y no código, para hacerlas accesibles desde nuestra página lo que haremos será ubicarlas en el directorio ''Bin'' del proyecto. === GAC === Como toda aplicación en .NET, las creadas con aspnet pueden acceder a los ensamblados ubicados en la //Global Assembly Cache//. ==== Estado de la aplicación ==== ASPNET gestiona una serie de instancias de ''HttpApplication'' correspondiendo cada una al transcurso de una visita a la página, es decir, se asigna una instancia a cada una de las peticiones http entrentes. La HttpApplication se crea la primera vez que se hace una petición al servidor, antes que eso aspnet no ejecuta código. Es entonces cuando se agraga a la lista de instancias y se lanza el evento ''Application_Start'' (definido en ''global.asax''); cuando se finaliza se lanza el evento ''Application_End''. === Sesiones === Podemos almacenar datos de usuario para la sesión. \\ En el fichero Global.asax podemos utilizar el diccionario ''Session'' para almacenar los valores que queremos que perduren. // Guardar datos void Session_Start () { Session["BackColor"] = "beige"; } // Recoger datos color = Session["BackColor"]; En el web.config podemos definir el tiempo que se mantiene la sesión activa (por defecto 20 minutos): Si las cookies no están activas, la sesión puede ser tratada a partir de un identificador en la URL, para ello agregaremos lo siguiente al web.config: === Fichero Global.asax === Las funciones del estilo '' Application_Start'', ''Application_End'', ''Session_Start'' o ''Session_End'' van en un archivo localizado en la raíz de la aplicación denominado ''Global.asax''. Este se compila en una clase la primera vez que se hace alguna petición a cualquier recurso dentro de la aplicación. Este tiene una estructura parecida a la siguiente: Si el código necesitase acceder a namespaces adicionales se usaría la directiva ''@Import'' al inicio de la página tal como sigue: <%@ Import Namespace="System.Text" %> La primera vez que la página es abierta se lanza el evento ''Start'': void Application_Start(Object Sender, EventArgs E) { } void Session_Start(Object Sender, EventArgs E) { Response.Write("Session is Starting...
") Session.Timeout = 1 }
Los eventos ''BeginRequest'' y ''EndRequest'' se lanzan por cada petición. * {{sp:asp:globalasax.zip|Aquí}} tienes los archivos de ejemplo de una aplicación denominada ''PruebaASP2''. ==== Navegación entre páginas ==== === Por enlaces === Es el modo más sencillo de navegación entre formularios web, siguiendo el formato de la tag '''' de HTML, mediante el control '''':
WebForm2
Luego podremos cambiar su propiedad ''NavigateUrl'': HyperLink1.NavigateUrl = "WebForm3.aspx" === Response.Redirect === Este método causa que el navegador se conecte a una URL específica; al llamarse se crea una nueva página con un header con código 302 (redirección), cuando el navegador la recibe usa esta información para generar otra petición http. Es decir, la redirección se hace en el lado del cliente. \\ Existe otro formato de llamada que es enviandole además un parámetro boolean. Esto significa que la ejecución de la página actual se ha de terminar, el sistema continuará con la ejecución mientras que el usuario es redireccionado a otra página. \\ Este método es perfecto para conectar recursos fuera del servidor web donde la página esté hospedada, o para conectar con recursos no-aspx, como páginas html. === Server.Transfer === Este método transfiere la ejecución del fichero .aspx actual a otro en el mismo servidor web, terminando su ejecución y control de flujo. La nueva página todavía utilizará el stream response creada anteriormente, es decir, el navegador mostrará la url de la página original (la redirección ocurre en el servidor sin que el navegador lo sepa). \\ A este método podemos pasarle un segundo argumento como ''true'', para que se pase los datos del formulario y de la query string a la página transferida. Para ello deberemos recoger el formulario con ''Context.Handler''. private void Page_Load (object sender, System.EventArgs e) { WebForm1 wf1 = (WebForm1)Context.Handler; Label1.Text=wf1.Name; Label2.Text=wf1.EMail; } === Server.Execute === Este método permite a la página aspx actual ejecutar otra página dentro del mismo web server, después de ser ejecutada, se vuelve a pasar el control a la página original desde donde ''Server.Execute'' fue llamado. Es una técnica análoga a llamar una llamada a una función de una página aspx, esta tendrá acceso a las colecciones del formulario y de la query string de la página original. \\ Por defecto la salida de la página ejectuada se añade a la salida de la actual, pero para tener más control de donde colocar el texto generado podemos enviar por parámetro un objeto ''StringWriter'' sobre el cual se volcará: StringWriter sw = new StringWriter(); Server.Execute("WebForm2.aspx", sw); Literal1.Text = sw.ToString(); === Propiedad PostBackUrl === La propiedad ''PostBackUrl'' en un control de servidor indica a qué página se enviará los datos del formulario, es decir, si asignamos a un botón esta propiedad con valor a otra página cuando se pulse a ese botón se irá automáticamente a la otra página, luego podemos recoger los valores de la anterior página desde ''Request.Form''. Luego podríamos acceder a los controles de la página anterior con: TextBox tb = (TextBox)PreviousPage.FindControl("text1"); ==== Pasar datos entre páginas ==== === Por QueryString === Podemos montar una url como string y llamar a otra página: string MyOccupation = "Software Developer"; string url; url = "page2.aspx?occupation=" + HttpUtility.UrlEncode(MyOccupation); Response.Redirect(url); Y luego recogerla desde la página que hemos llamado: protected void Page_Load(object sender, EventArgs e) { this.TextBox1.Text = Request.QueryString["occupation"]; RetrievedValue = this.TextBox1.Text; } === Por sesiones === Guardando y recogiendo en el diccionario ''Session'': Session["state_index"] = txtstate.text; string state = Session["state_index"]; === Recogiendo las propiedades públicas de la página anterior === Si en una página tubiesemos una propiedad pública podríamos acceder a esta desde el objeto ''PreviousPage''. Podemos indicar el tipo de este objeto, ya que es un no-tipado, indicando en la directiva ''PreviousPageType'' de la página destino el ''VirtualPath'': <%@ PreviousPageType VirtualPath="~/SourcePage.aspx" %> Y luego podremos hacer, por ejemplo: Label1.Text = PreviousPage.CurrentCity; === Recogiendo el valor deseado del formulario === Utilizando el método ''FindControl'', del objeto ''Page.PreviousPage'' pasándole el identificador del control del que queramos recoger la info. TextBox SourceTextBox = (TextBox)Page.PreviousPage.FindControl("TextBox1"); ===== Algunos elementos básicos ===== ==== Response ==== === Método Redirect === El método ''Response.Redirect'' redirecciona el navegador del usuario a una página nueva: Response.Redirect("Controls_NavigationTarget_cs.aspx?name=" + System.Web.HttpUtility.UrlEncode(Name.Text)); === Otros === * ''Clear'': Elimina lo que se ha escrito hasta ahora. * ''ContentType'': Indica el tipo de contenido que se envia para que según este sea tratado por el navegador. ==== Clase Page ==== Todos los web forms que se creen en ASP.NET son clases que heredan de la clase ''System.Web.UI.Page''. \\ Dentro de una clase que herede de Page podemos acceder a las siguientes propiedades: * **Session**, instancia de ''System.Web.SessionState.HttpSessionState'' que corresponde a un diccionario común en toda la sesión del usuario, perfecta para almacenar datos de usuario. * **Application**, instancia de ''System.Web.HttpApplicationState'' que corresponde a un diccionario común en toda la aplicación. * **Cache**, instancia ''System.Web.Caching.Cache'' nos da un mecanismo para optimizar el consumo de memoria. * **Request**, instancia de ''System.Web.HttpRequest'', contiene toda la información enviada por el cliente. * //Form//, corresponde a un diccionario con los valores del formulario. * **Response**, instancia de ''System.Web.HttpResponse'', contiene métodos para la comunicación con el cliente. * //Redirect//, método para indicar que página será la próxima en cargar. * //OutputStream//, corresponde al flujo que se envia al usuario. * //Write//, //BinaryWrite// o //WriteFile// para escribir sobre el output stream como texto o como fichero. * **Server**, instancia de ''System.Web.HttpServerUtility'' provee de una serie de métodos de ayuda para acceder a la información del servidor web. * //HtmlEncode// y //HtmlDecode//, para la conversión de texto simple a texto html y viceversa. * //Transfer//, más rápido que el //Response.Redirect// y con la misma función, pero restringida a la de redirigir únicamente hacia formularios web. * //MapPath//, retorna la dirección física de un fichero pasándole la dirección virtual. * **User**, instancia que implementa ''System.Security.Principal.IPrincipal'', sobre el tipo de usuario que es el cliente. * **Trace**, instancia de ''System.Web.TraceContext'' que permite la escritura de traces de la página. Existe el método ''SetFocus'' que permite indicar qué control recibe el foco. \\ También contiene la propiedad ''IsPostBack'', esta nos indica si es la primera vez que se carga la pagina en ese caso retornará ''false''. ==== La cabecera de la página ==== Como cualquier tag con la propiedad ''runat="server"'' la //head// se convierte en un objeto accesible desde nuestro código siendo del tipo ''HtmlHead''. Contiene las siguientes propiedades: * **Title**: Título de la página que corresponde. * **StyleSheet**: Un objete IStyleSheet que representa la hoja de estilos de la cabecera, como tal podemos eidtarlar utilizando los métodosCreateStyleRule y RegisterStyle. * **Controls**: Podemos añadir o eliminar metadata tags a partir de la colección ''HtmlMeta''. HtmlMeta metaKeywords = new HtmlMeta(); metaKeywords.Name = "keywords"; metaKeywords.Content = ".NET, C#, ASP.NET"; Page.Header.Controls.Add(metaKeywords); ==== Directiva Page ==== Los archivos de páginas (.aspx) comienzan con una directiva ''Page'', la cual indica en qué lenguaje está programada y dónde encontrar el código. Algunos de sus atributos son: * **Language**: Indica el lenguaje utilizado. * **AutoEventWireup**: Indica si los eventos están autoconectados. * **CodeFile**: En páginas compiladas indica el archivo donde está el código al que se hace referencia. * **Inherits**: Indica la clase (que ha de heredar de ''System.Web.UI.Page'') que enlaza. * **ClassName**: Especifica el nombre del resultado de la compilación. * **Trace** y **TraceMode**: Para indicar si se hace tracing de la página y el modo de este. Por ejemplo la siguiente línea en el archivo ''Default.aspx'': <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> Enlaza con la clase ''_Default'' del archivo ''Default.aspx.cs'': public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { ... ==== Otras clases ==== === Units === Para indicar las unidades de medida utilizamos los objetos de la clase ''Unit''. Estos representan un porcentaje, un tamaño fijo... las unidades que podemos expresar en html. Los métodos estáticos de la clase devuelven objetos, aunque también los podemos crear manualmente: pnl.Height = Unit.Pixel(300); pnl.Width = Unit.Percentage(50); ... Unit myUnit = new Unit(300, UnitType.Pixel); pnl.Height = myUnit; === HttpUtility === Con los siguientes métodos: * ''HtmlEncode'': Para codificar strings para colocar en el contenido de la página. * ''UrlEncode'': Para codificar strings para colocar en la dirección de la página. ==== El fichero Web.config ==== Este fichero se ubica en la ruta raíz de la aplicación y mediante él podemos configurarla, el estilo es parecido al [[highlevel:csharp:xtra2#fichero_app.config|app.config]]. === Configuración de connection strings === La cadena de conexión se puede almacenar en el fichero Web.config, en la sección '''', de esta forma es sencillo de mantenerla en un solo lugar para todas las páginas de la aplicación. ==== Gestión de errores ==== Podemos realizarla: * A nivel de métodos, es el de toda la vida, utilizando ''try-catch-finally''. * A nivel de página, consiste en sobreescribir el evento ''OnError'' del objeto Page o el atributo ''errorPage'' de esta (esto es, en la directiva de declaración indicar la url del archivo al que se llamará si ocurre un error). * A nivel de aplicación, consiste en escribir el evento ''OnError'' del objeto Application, dentro del fichero ''global.asax''. Existen dos métodos que pueden ayudarnos a la gestión de errores: * ''Server.GetLastError'': El cual retorna una referencia al objeto Exception que se ha lanzado. * ''Server.ClearError'': El cual limpia el error del servidor, si no es llamado el error se propagará. Es decir, si es un error a nivel de página pasará a ser a nivel de aplicación. El siguiente ejemplo es la sobreescritura del evento OnError: protected override void OnError (System.EventArgs e) { Server.ClearError(); Response.Redirect("~/error.html"); } En el ''web.config'' existe una sección donde podemos especificar la página de error que utilizará ASP.NET a la cual nos redirigirá si ocurre una excepción no manejada. Este modo de controlar errores se basa en los siguientes puntos: * Propiedad ''mode'': especifica como manejar un error: * ''RemoteOnly'', los errores son mostrados para los usuarios remotos, las páginas de error ASP.NET con información detallada sobre el error se darán a los usuarios locales. * ''On'', siempre se muestran las páginas personalizadas, si no estubiese definida una página para un error ASP.NET no mostraría información detallada. * ''Off'', siempre se muestra información detallada sobre el error ocurrido. * Propiedad ''defaultRedirect'': Especifica a qué pagina se redirecciona si ocurre un error. * Elementos ''error'': Los cuales definen la acción para un error particular a partir de las propiedades ''statusCode'', que indica el código de error, y ''redirect'' que indica a qué página se redireccionará si ocurriese dicho error. \\ \\ Hay que tener cuidado, porque si se genera un error mientras se maneja errores puede darse un bucle infinito. ==== Ciclo de vida de una página ASP.NET ==== === Fases === * **Page request**, la petición de la página por parte del cliente. Se crea el objeto ''Page''. * **Start**, inicio, se asignan los ''Request'' y ''Response'', se determina si la petición es ''postback'' o no. * **Page initialization**, inicialización de los controles. * **Load**, si la página es postback se cargan los valores de los controles. * **Validation**, se llama al método ''Validate'' de todos los controles y se asigna la propiedad ''IsValid''. * **Postback event handling**, si la página es postback entonces se llaman a los manejadores de eventos. * **Rendering**, se llama al método ''Render'' de cada control y se va escribiendo en el ''OutputStream'' la respuesta al cliente. * **Unload**, una vez se ha acabado de enviar la página al cliente se eliminan de memoria las propiedades y objetos que ya no se necesitarán. === Orden de llamada de eventos === * **PreInit**. * Para comprobar si ''IsPostBack''. * Para crear o recrear los controles dinámicos. * Asignar la master page o el tema dinámicamente. * Leer propiedades del perfil. * **Init**, se llama cuando todos los controles han sido inicializados y su skin aplicada. * Para leer o inicializar las propiedades de los controles. * **InitComplete**. * **PreLoad**. * **Load**, se llama al OnLoad de la página y al de todos los controles hijo. * Para establecer las conexiones de base de datos. * **Control events**, eventos de los controles. * **LoadComplete**. * **PreRender** * Para hacer los cambios finales al contenido de la página y sus controles. * **SaveStateComplete**. * **Render** * **Unload** === Otros === * Esquema del ciclo de vida página: {{sp:asp:ct.png?10|Esquema}} ==== Cookies ==== Las cookies son pequeños archivos de texto que se guardan en el ordenador del visitante de una web y que luego pueden ser recuperados. Los manejamos a partir del tipo ''System.Web.HttpCookie''. === Crear una cookie === Para crear una cookie simplemente creamos un objeto del tipo ''HttpCookie'' a partir de un identificador y de un valor (en el caso siguiente el identificador es ''subgurim'' y el valor la fecha actual). Podremos decir cuando queremos que la cookie caduque a partir de la propiedad ''Expires''. HttpCookie addCookie = new HttpCookie("subgurim", DateTime.Now.ToString()); addCookie.Expires = DateTime.Today.AddDays(1).AddSeconds(-1); Response.Cookies.Add(addCookie); Podemos agregar la cookie de forma dinámica: Response.Cookies["userName"].Value = "patrick"; Response.Cookies["userName"].Expires = DateTime.Now.AddDays(1); === Coger las cookies del cliente === Podemos recoger una cookie concreta a partir del método ''Request.Cookies.Get'': HttpCookie cogeCookie = Request.Cookies.Get("subgurim"); También podremos cogerla a partir del identificador la lista: HttpCookie cogeCookie = Request.Cookies["subgurim"]; Al estar en una lista podemos recorrer todas las cookies del cliente: foreach (HttpCookie cookie in Request.Cookies) { Response.Write(cookie.Name + ":" + cookie.Value + "
"); }
=== Modificar y eliminar las cookies === Podemos cambiar el valor de una cookie a partir del método ''Response.Cookies.Set'': HttpCookie modificaCookie = Request.Cookies.Get("subgurim"); modificaCookie.Expires = DateTime.Now.AddDays(7); modificaCookie.Value = "hi!"; Response.Cookies.Set(modificaCookie); O eliminarlas a partir del ''Response.Cookies.Remove'': Response.Cookies.Remove("subgurim"); O eliminarlas todas: Response.Cookies.Clear(); Aunque si existen problemas para la eliminación: HttpCookie c1 = Request.Cookies["userName"]; if (c1 != null) { Request.Cookies.Remove("userName"); c1.Expires = DateTime.Now.AddDays(-10); c1.Value = null; Response.SetCookie(c1); } === Cookies con varios valores === Para crear una cookie con varios valores lo haremos como si fuese un array multidimensional. \\ Para asignarla lo haremos así... Response.Cookies["userInfo"]["userName"] = "patrick"; Response.Cookies["userInfo"]["lastVisit"] = DateTime.Now.ToString(); Response.Cookies["userInfo"].Expires = DateTime.Now.AddDays(1); O así: HttpCookie addMultiCookie = new HttpCookie("subgurimMultidimensional"); for (int i = 0; i < 10; i++) { addMultiCookie.Values.Add(i.ToString(), "Elemento " + i.ToString()); addMultiCookie[i.ToString()] = "Elemento " + i.ToString(); } Response.Cookies.Add(addMultiCookie); Y para recogerla de la siguiente forma: HttpCookie cogeMultiCookie = Request.Cookies.Get("subgurimMultidimensional"); string valorCualquiera = cogeMultiCookie.Values.Get("5"); ===== La interface de usuario ===== ==== Estilos ==== En los controles que soportan un modelo ''Style'' podemos establecer sus propiedades visuales a partir de CSS. \\ Dentro de un control la información de estilo se gestiona en su propiedad Style (tipo CssStyleCollection), esta es un diccionario que muestra los estilos indexados por cadenas: Los controles de servidor pueden definirse su visualización a partir de propiedades: También se pueden acceder a propiedades de forma individual a partir de ''PropertyName-SubPropertyName'': En los controles de servidor podemos indicar la clase CSS a partir de la propiedad ''CssClass'': O con la propiedad, simplemente, ''class'':
Una clase css sería: .errorText { color: Red; font-weight: bold; } Pero lo más aconsejable, si utilizamos hojas de estilos (css) es anidar los estilos de la siguiente forma: table.taula { ... } table.taula td { ... } table.taula th { ... } table.taula tr.evenCell { ... } table.taula tr.oddCell { ... } table.taula td.evenCell { ... } table.taula td.oddCell { ... } table.taula td.littleEvenCell { ... } table.taula td.littleOddCell { ... } También podemos definir los estilos a partir de código: Style style = new Style(); style.BorderColor = Color.Black; style.BorderStyle = BorderStyle.Dashed; style.BorderWidth = 1; MyLoginTextBox.ApplyStyle (style); MyPasswordTextBox.ApplyStyle (style); MySubmitButton.ApplyStyle (style); ==== Temas ==== Un tema es un conjunto de ficheros que definen la apariencia de la web. Se ubican en un directorio dentro de nuestro proyecto denominado ''App_Themes'', en este se encuentran ficheros skin, ficheros css y subcarpetas con diversos temas. Los ficheros skin contiene definiciones de estilo para los distintos controles de la aplicación. \\ \\ Podemos asignar un tema a nivel de página o de configuración: * Para asignar un tema a nivel de página, lo que haremos será agregar la directiva ''<%@ Page Theme="..." %>'' al principio de la página indicando el nombre del tema (el nombre de la carpeta bajo el directorio Themes o App_Themes), esto haría que la definición del tema sobreescribiese la del control. En cambio, podemos indicar que sea la del control la que predomine indicando el tema en ''StyleSheetTheme'' en vez de en ''Theme''. * Para asignar un tema a nivel de configuración agregaremos una sección ''pages theme'' en el web.config: Si quisieramos desabilitar los temas para un control pondríamos su propiedad ''EnableTheming'' a ''false''. \\ \\ Podemos crear temas a nivel de máquina colocándolos en la carpeta ''%WINDIR%\Microsoft.NET\Framework\\ASP.NETClientFiles\Themes'' o en''Inetpub\wwwroot\aspnet_client\system_web\\Themes''. \\ \\ Podemos agregar una hoja de estilos a un tema añadiendo el archivo css en el directorio de este, los estilos serán aplicables siempre y cuando la definición del head de la página sea ''''. Un tema podrá contener distintos ficheros .css cuando la página los referencie (mediante una etiqueta '''' en el elemento ). \\ \\ Para asignar un tema en tiempo de ejecución lo asignaremos al objeto ''Page'' durante el evento ''PreInit''. ==== Skins ==== Los skins se definen en archivos .skin dentro del App_Themes, su contenido es la definición de las propiedades visuales de los controles. \\ Para diferenciarlos, se puede definir la propiedad ''SkinID'' para concretar un estilo: Y luego:

Podríamos agrupar los ficheros skin por Tema (propuesta 1) nombrandolos como su SkinID o por control (propuesta 2): Propuesta 1 /WebSite1 /App_Themes /MyTheme Default.skin Red.skin Blue.skin Propuesta 2 /WebSite1 /App_Themes /MyTheme GridView.skin Calendar.skin Label.skin ==== Master Pages ==== La definición de una master page permite definir unos elementos de la página (cabecera, pie de página, navegación...) que serán comunes para todas las páginas asociadas a esta. \\ \\ La definición de una master page es como las demás solo que estas, mediante el control ''ContentPlaceHolder'' puede definir la región que ha de sustituirse. También puede contener contenido por defecto, por si la página derivada no necesita sobreescribirlo. La sintaxis es la siguiente: <%-- ContentPlaceHolder control --%> <%-- ContentPlaceHolder with default content --%>

Welcome to my florist website!

Una master page está en un fichero ''.master'' y para que una página normal derive de esta lo ha de indicar en la propiedad ''MasterPageFile'' en la directiva ''Page'', una vez asociada pasará a denominarse ''Content Page''. <%@ Page MasterPageFile="Site.master" %> Una Content Page puede declarar controles ''Content'' para sobreescribir el contenido de la Master Page, este se asocia a un ''ContentPlaceHolder'' a través de la propiedad ''ContentPlaceHolderID''. <%@ Page MasterPageFile="Site.master" %> With sunshine, water, and careful tending, roses will bloom several times in a season. Es decir, debemos de seguir lo siguiente: - Crear la página master, esta ha de tener una directiva del tipo ''@Master'' en vez de ''@Page''. - Las regiones que se puedan modificar estarán en controles ''''. - Crear una página normal, esta sí que tendrá la directiva ''@Page'' con el agributo ''MasterPageFile'' indicando su propia página master. No deberá de tener más código HTML. - Las áreas que se vayan a sustituir en las masterpages serán controles '''' que definan el atributo ''ContentPlaceHolderID'' que indique el '''' de la página master a sobreescribir. Si la Master Page define elementos a partir de rutas relativas y la Content Page se encuentra en otra ruta se producirán errores de no encontrar la ubicación. Para solucionar esto podemos: * Utilizar URL absolutas. * Utilizar URL relativas de aplicación, donde ''~'' corresponde a la raíz de esta, algo así: ''''. Las Master Pages también pueden contener otras Master Pages, por ejemplo, podríamos tener una Master Page que represente la cabecera/pie de página y la navegación global del sitio, y después Master Pages separadas que deriven de esta para definir los aspectos de las diferentes sub-secciones del sitio. === Comunicación entre la MasterPage y el contenido === Cuando utilizamos la directiva ''MasterType'' en un WebForm estamos especificando el tipo del que será la página maestra. Esto significa que al acceder a la propiedad ''Master'' de la ''Page'' tendremos también acceso a sus propiedades. Si utilizamos MasterPages anidadas no podremos acceder a los datos de la raíz desde el WebForm, pero como lo que realmente estamos indicando es el tipo podemos hacer que las MasterPages hereden de un tipo concreto y en la directiva ''MasterType'' indicar ese. <%@ MasterType VirtualPath="Site.master" %> Por lo tanto, a partir de ahora la Content Page puede referenciar la Master Page mediante la propiedad ''Master'' de la clase ''Page'': Master.FooterText = "This is a custom footer"; AdRotator ad = (AdRotator)Master.FindControl("MyAdRotator"); Para comunicar desde la MasterPage al contenido lo que haremos será lanzar un evento. === Notas === * La MasterPage inserta la el WebForm entre los eventos ''PreInit'' e ''Init''. * Podemos indicar la MasterPage por código, pero antes del evento ''PreInit'' mediante la propiedad ''MasterPageFile'' del objeto Page. * Podemos indicar la MasterPage por defecto a partir del fichero de configuración: ===== Seguridad ===== ===== Perfiles de usuario ===== Los perfiles de usuario se gestionan a partir de objetos ''Profile'' y estos se administran con objetos ''ProfileManager''. ===== WebServices ===== ==== Controladores globales, ficheros .ashx ==== Permiten devolver otro tipo de respuesta que no sea HTML (como por ejemplo XML, JSON...), dándonos la posivilidad de indicar el formato en la cabecera de lo devuelto (''text/plain'', ''text/xml''...). \\ \\ Son clases que se tratan como los formularios web, por una parte tienen el nombre del fichero al cual se hará la petición (fichero .ashx donde se indicará cual es su clase) y por otra code begind (su clase en sí, en un fichero .ashx.cs) en una clase que hereda de la interface ''System.Web.IHttpHandler''. En el método ''ProcessRequest'' será donde coloquemos lo que devolveremos a partir del método ''Write'' del ''HttpContext.Response'' que nos vendrá por parámetro. \\ \\ El siguiente ejemplo utiliza la librería [[fw:othersnet:jsonnet|Json.NET]] para devolver datos en formato JSON (texto plano), por lo tanto primero tenemos el fichero .ashx: <%@ WebHandler Language="C#" CodeBehind="controller.ashx.cs" Class="WebApplication4.controller" %> Y luego su clase correspondiente (fichero ''controller.ashx.cs''): using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WebApplication4 { public class controller : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; context.Response.ContentEncoding = System.Text.Encoding.UTF8; MyClass MyObject = new MyClass() { name = "Pedro", age = 49 }; string json = Newtonsoft.Json.JsonConvert.SerializeObject(MyObject); context.Response.Write(json); } public bool IsReusable { get { return false; } } } } * En el ''HttpContext'' podemos recoger los parámetros mediante la ''QueryString'' (GET) o el ''Form'' (POST). * Si el controlador necesita leer la sesión del usuario que hace la petición necesitará implementar la interfaz ''System.Web.SessionState.IReadOnlySessionState'', si además necesitase guardarla implementaría la ''IRequiresSessionState''. ===== Notas ===== ==== Como... ==== === Agregar una librería === Después de agregar un ensamblado a la carpeta ''bin'' ya podremos utilizarlo en el code-behind, pero para utilizarlo en el code-inline tendremos que agregar la directiva ''Register'' al principio del documento: <%@ Register assembly="ScsComboBox" namespace="SCS.WebControls" tagprefix="scs" %> A partir de entonces los controles dentro de ''SCS.WebControls'' (el namespace del ejemplo) serán accesibles desde ''scs'': === Saber ubicación de la aplicación en disco === Como lo hacemos en cualquier aplicación .NET simplemente tendríamos que consultar: string bdir = System.AppDomain.CurrentDomain.BaseDirectory; === Acceder al Request\Response sin tener acceso a la clase Page === HttpContext.Current.Request.MapPath("~/"); ==== Visual Studio ==== * Para cambiar el navegador por defecto en VS2008: Botón derecho sobre un .aspx -> Browse with. Ahora podemos agregar nuevos navegadores y escoger el de por defecto. * Para distribuir la aplicación ASP.NET desde Visual Studio .NET podemos indicar que se copien los archivos necesario a una carpeta, directorio virtual, FTP... Desde el menú -> Generar -> Publicar la aplicación.