Mostrando las entradas con la etiqueta Programación. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Programación. Mostrar todas las entradas

lunes, 9 de mayo de 2011

.NET Tuple - Alternativa a los objetos personalizados

tuple .NET framework 4.0 trajo muchas mejoras importantes, y una de las más importantes para mi ha sido la incorporación de lo que conocemos como Tupla, que como dice la definición, es una secuencia ordenada de objetos o datos.

Entonces, deduciendo: una tupla podría ser una fila de una tabla de la bd, y esa fila podría ser recuperada y mantenida en memoria en un objeto, correcto? correcto.

Sigamos, una de las carencias que yo experimentaba al programar era el hecho de no poder fácilmente crear objetos que conserven múltiples propiedades sin previamente haber creado la clase personalizada.

Por ejemplo, si yo quería crear una colección con cada una de las propiedades de mi menú principal (url, imagen, target, color, etc…), tenía que crear una clase MenuItem, luego sus propiedades, y luego ya era sencillo crear una colección de elementos MenuItem usando una List(Of MenuItem).

Pero si luego quería armar otro menú con otras propiedades tenía que crear otra clase con otras propiedades… entonces te dabas cuenta que al final estabas creando un montón de clases que no tendrían mucho uso realmente.

Y la inquietud era que si hubiera una forma sencilla de crear algo como clases-al-vuelo, entonces sería más fácil. Y zasssssssssss…. apareció el concepto de Tuple en .NET Framework 4.0, que para mi es justo lo que necesitaba.

Obviamente, esta funcionalidad de Tuplas me facilita muchas más cosas que sólo el reemplazo de objetos personalizados. En codeproject encontré un artículo muy completo, denle una chequeada
http://www.codeproject.com/KB/cs/C_Sharp_4_Tuples.aspx

Les pongo un pequeño extracto de código VB.NET que soluciona el caso que les mencionaba acerca de crear el menú de opciones
Dim Menu As New List(Of Tuple(Of Integer, String, String, String, String, Boolean))
Menu.Add(Tuple.Create(1, "Home", "home.gif", "Default.aspx", "_self", True))
Menu.Add(Tuple.Create(1, "Dashboard", "dashboard.gif", "Dashboard.aspx", "_self", True))
Menu.Add(Tuple.Create(3, "Proyectos", "proyectos.gif", "Projects.aspx", "_self", True))
Menu.Add(Tuple.Create(4, "Reportes", "reportes.gif", "Reports.aspx", "_self", True))
Menu.Add(Tuple.Create(2, "Administración", "admin.gif", "Admin.aspx", "_blank", False))

'luego itero por los elementos de la colección
For Each MenuItem As Tuple(Of Integer, String, String, String, String, Boolean) In Menu

'observen que se ha autogenerado una propiedad .ItemX por cada elemento de la tupla
response.Write(String.Format("{0}-{1}-{2}-{3}-{4}", MenuItem.Item1, MenuItem.Item2, MenuItem.Item3, MenuItem.Item4, MenuItem.Item5))

Next
Como ven, no he tenido que crear una clase personalizada, ni luego instanciarla…etc. Simplemente usamos qué cosa? exacto Tuplas.

Finalmente decirles que con esta funcionalidad, Yo estoy saltando de un pie ;)

Espero que les sea de utilidad ;)

lunes, 22 de junio de 2009

.NET – Agregarle descripcion a un Enum

enum_desc Ya hemos revisado en el post anterior, cómo podemos iterar por los elementos de una enumeración.

Ahora, vamos a ver cómo se hace para añadirle una descripción a una enumeración... y luego, cómo recuperamos esa enumeración.

Para nuestro propósito, vamos a usar Reflection.

1.- Importamos
Imports System.ComponentModel
Imports System.Reflection

2.- Para añadirle una description a nuestro enum, hacemos esto:
Enum Roles
<Description("Administrador general del sistema")> Administrador = 1
<Description("Usuario de la aplicación, con derechos limitados")> Usuario = 2
<Description("Auditor del sistema")> Auditor = 3
<Description("Persona que no es usuario de la aplicación")> Invitado = 4
End Enum
3.- De esta forma recuperamos las descripciones de la enumeración:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim sb As New StringBuilder
Dim enumValores As FieldInfo() = GetType(Roles).GetFields()
For Each info As Reflection.FieldInfo In enumValores
If Not info.IsSpecialName Then

Dim obj As Object = info.GetCustomAttributes(GetType(DescriptionAttribute), False)
Dim desc As DescriptionAttribute = DirectCast(obj(0), DescriptionAttribute)

sb.Append(desc.Description & "<br />")

End If
Next info

Response.Write(sb.ToString)
End Sub


Y es sería todo. ;)

jueves, 18 de junio de 2009

.NET - Recorrer los elementos de un Enum

enum Tenemos un Enum:

Enum Roles
Administrador = 1
Usuario = 2
Auditor = 3
Invitado = 4

End Enum

y queremos recorrer o iterar por sus elementos… cómo lo hacemos?

en realidad es nada dificil, veamos 2 formas:

1.- Obtenemos los valores del Enum en un array, luego de eso iteramos por el array y ya tenemos todos los elementos:

Dim values As Array
values = System.Enum.GetValues(GetType(Roles))
Dim valuesString As New StringBuilder
For Each val As String In values
    valuesString.AppendFormat("{0},", val)
Next
Dim TotalValues As String = valuesString.ToString

Dim names As Array
names = System.Enum.GetNames(GetType(Roles))
Dim namesString As New StringBuilder
For Each name As String In names
    namesString.AppendFormat("{0},", name)
Next
Dim TotalNames As String = namesString.ToString

Para este caso, he tenido que crear dos arrays, uno para obtener los valores… y otro para sus nombres.

También pueden iterar de una sola vez, y obtener ambos datos… pero lo haremos usando Reflection… como se explica en la siguiente forma:

2.- Esta vez, lo que vamos a usar son las funcionalides del espacio de nombres System.Reflection… y de ella la clase FielInfo, que lo que hace es particionar alguna información y exponer dicha metadata.

Si desean saber más sobre FieldInfo, hagan click aquí

Para recorrer por cada uno de los elementos y recuperar su valor y nombre, usamos la siguiente rutina:

Dim enumValores As Reflection.FieldInfo() = GetType(Roles).GetFields()

For Each info As Reflection.FieldInfo In enumValores

If Not info.IsSpecialName Then
Dim val As Integer = info.GetValue(0)
Dim nom As String = info.Name
End If

Next info

Eso sería todo ;)

sábado, 8 de noviembre de 2008

ASP.NET - Lista de todos los paises

Todos en algún momento necesitamos recuperar la lista de países, para mostrarlos tal vez en un dropdownlist.
Hay maneras y maneras de llenar ese dropdownlist... la manera más simple es la sgte:








o peor aún, así:






Osea hardcodear... eso lo puede hacer todo el mundo y no he escrito este post para decirles que lo hagan de esa manera... al contrario, no lo hagan. Les propongo una solución inteligente:

vamos a crear un archivo xml llamado Countries.xml en la raiz de nuestra aplicación web, y allí vamos a guardar la lista de todos los países. Algo así:













Luego, para obtener esos valores desde mi pagina.aspx, añado un dropdownlist llamado ddlCountries a mi pagina. Después, voy al code beside de la página y escribo unas cuantas líneas:
















Es todo. Demasiado simple para ser cierto. Les dejo la lista de países por si no la tuvieran.


[?xml version="1.0" standalone="yes" ?]
[Countries]
[Country Title="Afghanistan" Code="AF"][/Country]
[Country Title="Albania" Code="AL"][/Country]
[Country Title="Algeria" Code="DZ"][/Country]
[Country Title="American Samoa" Code="AS"][/Country]
[Country Title="Andorra" Code="AD"][/Country]
[Country Title="Angola" Code="AO"][/Country]
[Country Title="Anguilla" Code="AI"][/Country]
[Country Title="Antarctica" Code="AQ"][/Country]
[Country Title="Antigua And Barbuda" Code="AG"][/Country]
[Country Title="Argentina" Code="AR"][/Country]
[Country Title="Armenia" Code="AM"][/Country]
[Country Title="Aruba" Code="AW"][/Country]
[Country Title="Australia" Code="AU"][/Country]
[Country Title="Austria" Code="AT"][/Country]
[Country Title="Azerbaijan" Code="AZ"][/Country]
[Country Title="Bahamas" Code="BS"][/Country]
[Country Title="Bahrain" Code="BH"][/Country]
[Country Title="Bangladesh" Code="BD"][/Country]
[Country Title="Barbados" Code="BB"][/Country]
[Country Title="Belarus" Code="BY"][/Country]
[Country Title="Belgium" Code="BE"][/Country]
[Country Title="Belize" Code="BZ"][/Country]
[Country Title="Benin" Code="BJ"][/Country]
[Country Title="Bermuda" Code="BM"][/Country]
[Country Title="Bhutan" Code="BT"][/Country]
[Country Title="Bolivia" Code="BO"][/Country]
[Country Title="Bosnia And Herzegowina" Code="BA"][/Country]
[Country Title="Botswana" Code="BW"][/Country]
[Country Title="Bouvet Island" Code="BV"][/Country]
[Country Title="Brazil" Code="BR"][/Country]
[Country Title="British Indian Ocean Territory" Code="IO"][/Country]
[Country Title="Brunei Darussalam" Code="BN"][/Country]
[Country Title="Bulgaria" Code="BG"][/Country]
[Country Title="Burkina Faso" Code="BF"][/Country]
[Country Title="Burundi" Code="BI"][/Country]
[Country Title="Cambodia" Code="KH"][/Country]
[Country Title="Cameroon" Code="CM"][/Country]
[Country Title="Canada" Code="CA"][/Country]
[Country Title="Cape Verde" Code="CV"][/Country]
[Country Title="Cayman Islands" Code="KY"][/Country]
[Country Title="Central African Republic" Code="CF"][/Country]
[Country Title="Chad" Code="TD"][/Country]
[Country Title="Chile" Code="CL"][/Country]
[Country Title="China" Code="CN"][/Country]
[Country Title="Christmas Island" Code="CX"][/Country]
[Country Title="Cocos (Keeling) Islands" Code="CC"][/Country]
[Country Title="Colombia" Code="CO"][/Country]
[Country Title="Comoros" Code="KM"][/Country]
[Country Title="Congo" Code="CG"][/Country]
[Country Title="Cook Islands" Code="CK"][/Country]
[Country Title="Costa Rica" Code="CR"][/Country]
[Country Title="Cote D'Ivoire" Code="CI"][/Country]
[Country Title="Croatia (Local Name: Hrvatska)" Code="HR"][/Country]
[Country Title="Cuba" Code="CU"][/Country]
[Country Title="Cyprus" Code="CY"][/Country]
[Country Title="Czech Republic" Code="CZ"][/Country]
[Country Title="Denmark" Code="DK"][/Country]
[Country Title="Djibouti" Code="DJ"][/Country]
[Country Title="Dominica" Code="DM"][/Country]
[Country Title="Dominican Republic" Code="DO"][/Country]
[Country Title="East Timor" Code="TP"][/Country]
[Country Title="Ecuador" Code="EC"][/Country]
[Country Title="Egypt" Code="EG"][/Country]
[Country Title="El Salvador" Code="SV"][/Country]
[Country Title="Equatorial Guinea" Code="GQ"][/Country]
[Country Title="Eritrea" Code="ER"][/Country]
[Country Title="Estonia" Code="EE"][/Country]
[Country Title="Ethiopia" Code="ET"][/Country]
[Country Title="Falkland Islands (Malvinas)" Code="FK"][/Country]
[Country Title="Faroe Islands" Code="FO"][/Country]
[Country Title="Fiji" Code="FJ"][/Country]
[Country Title="Finland" Code="FI"][/Country]
[Country Title="France" Code="FR"][/Country]
[Country Title="French Guiana" Code="GF"][/Country]
[Country Title="French Polynesia" Code="PF"][/Country]
[Country Title="French Southern Territories" Code="TF"][/Country]
[Country Title="Gabon" Code="GA"][/Country]
[Country Title="Gambia" Code="GM"][/Country]
[Country Title="Georgia" Code="GE"][/Country]
[Country Title="Germany" Code="DE"][/Country]
[Country Title="Ghana" Code="GH"][/Country]
[Country Title="Gibraltar" Code="GI"][/Country]
[Country Title="Greece" Code="GR"][/Country]
[Country Title="Greenland" Code="GL"][/Country]
[Country Title="Grenada" Code="GD"][/Country]
[Country Title="Guadeloupe" Code="GP"][/Country]
[Country Title="Guam" Code="GU"][/Country]
[Country Title="Guatemala" Code="GT"][/Country]
[Country Title="Guinea" Code="GN"][/Country]
[Country Title="Guinea-Bissau" Code="GW"][/Country]
[Country Title="Guyana" Code="GY"][/Country]
[Country Title="Haiti" Code="HT"][/Country]
[Country Title="Heard And Mc Donald Islands" Code="HM"][/Country]
[Country Title="Holy See (Vatican City State)" Code="VA"][/Country]
[Country Title="Honduras" Code="HN"][/Country]
[Country Title="Hong Kong" Code="HK"][/Country]
[Country Title="Hungary" Code="HU"][/Country]
[Country Title="Iceland" Code="IS"][/Country]
[Country Title="India" Code="IN"][/Country]
[Country Title="Indonesia" Code="ID"][/Country]
[Country Title="Iran (Islamic Republic Of)" Code="IR"][/Country]
[Country Title="Iraq" Code="IQ"][/Country]
[Country Title="Ireland" Code="IE"][/Country]
[Country Title="Israel" Code="IL"][/Country]
[Country Title="Italy" Code="IT"][/Country]
[Country Title="Jamaica" Code="JM"][/Country]
[Country Title="Japan" Code="JP"][/Country]
[Country Title="Jordan" Code="JO"][/Country]
[Country Title="Kazakhstan" Code="KZ"][/Country]
[Country Title="Kenya" Code="KE"][/Country]
[Country Title="Kiribati" Code="KI"][/Country]
[Country Title="Korea, Dem People'S Republic" Code="KP"][/Country]
[Country Title="Korea, Republic Of" Code="KR"][/Country]
[Country Title="Kuwait" Code="KW"][/Country]
[Country Title="Kyrgyzstan" Code="KG"][/Country]
[Country Title="Lao People'S Dem Republic" Code="LA"][/Country]
[Country Title="Latvia" Code="LV"][/Country]
[Country Title="Lebanon" Code="LB"][/Country]
[Country Title="Lesotho" Code="LS"][/Country]
[Country Title="Liberia" Code="LR"][/Country]
[Country Title="Libyan Arab Jamahiriya" Code="LY"][/Country]
[Country Title="Liechtenstein" Code="LI"][/Country]
[Country Title="Lithuania" Code="LT"][/Country]
[Country Title="Luxembourg" Code="LU"][/Country]
[Country Title="Macau" Code="MO"][/Country]
[Country Title="Macedonia" Code="MK"][/Country]
[Country Title="Madagascar" Code="MG"][/Country]
[Country Title="Malawi" Code="MW"][/Country]
[Country Title="Malaysia" Code="MY"][/Country]
[Country Title="Maldives" Code="MV"][/Country]
[Country Title="Mali" Code="ML"][/Country]
[Country Title="Malta" Code="MT"][/Country]
[Country Title="Marshall Islands" Code="MH"][/Country]
[Country Title="Martinique" Code="MQ"][/Country]
[Country Title="Mauritania" Code="MR"][/Country]
[Country Title="Mauritius" Code="MU"][/Country]
[Country Title="Mayotte" Code="YT"][/Country]
[Country Title="Mexico" Code="MX"][/Country]
[Country Title="Micronesia, Federated States" Code="FM"][/Country]
[Country Title="Moldova, Republic Of" Code="MD"][/Country]
[Country Title="Monaco" Code="MC"][/Country]
[Country Title="Mongolia" Code="MN"][/Country]
[Country Title="Montserrat" Code="MS"][/Country]
[Country Title="Morocco" Code="MA"][/Country]
[Country Title="Mozambique" Code="MZ"][/Country]
[Country Title="Myanmar" Code="MM"][/Country]
[Country Title="Namibia" Code="NA"][/Country]
[Country Title="Nauru" Code="NR"][/Country]
[Country Title="Nepal" Code="NP"][/Country]
[Country Title="Netherlands" Code="NL"][/Country]
[Country Title="Netherlands Ant Illes" Code="AN"][/Country]
[Country Title="New Caledonia" Code="NC"][/Country]
[Country Title="New Zealand" Code="NZ"][/Country]
[Country Title="Nicaragua" Code="NI"][/Country]
[Country Title="Niger" Code="NE"][/Country]
[Country Title="Nigeria" Code="NG"][/Country]
[Country Title="Niue" Code="NU"][/Country]
[Country Title="Norfolk Island" Code="NF"][/Country]
[Country Title="Northern Mariana Islands" Code="MP"][/Country]
[Country Title="Norway" Code="NO"][/Country]
[Country Title="Oman" Code="OM"][/Country]
[Country Title="Pakistan" Code="PK"][/Country]
[Country Title="Palau" Code="PW"][/Country]
[Country Title="Panama" Code="PA"][/Country]
[Country Title="Papua New Guinea" Code="PG"][/Country]
[Country Title="Paraguay" Code="PY"][/Country]
[Country Title="Peru" Code="PE"][/Country]
[Country Title="Philippines" Code="PH"][/Country]
[Country Title="Pitcairn" Code="PN"][/Country]
[Country Title="Poland" Code="PL"][/Country]
[Country Title="Portugal" Code="PT"][/Country]
[Country Title="Puerto Rico" Code="PR"][/Country]
[Country Title="Qatar" Code="QA"][/Country]
[Country Title="Reunion" Code="RE"][/Country]
[Country Title="Romania" Code="RO"][/Country]
[Country Title="Russian Federation" Code="RU"][/Country]
[Country Title="Rwanda" Code="RW"][/Country]
[Country Title="Saint K Itts And Nevis" Code="KN"][/Country]
[Country Title="Saint Lucia" Code="LC"][/Country]
[Country Title="Saint Vincent, The Grenadines" Code="VC"][/Country]
[Country Title="Samoa" Code="WS"][/Country]
[Country Title="San Marino" Code="SM"][/Country]
[Country Title="Sao Tome And Principe" Code="ST"][/Country]
[Country Title="Saudi Arabia" Code="SA"][/Country]
[Country Title="Senegal" Code="SN"][/Country]
[Country Title="Seychelles" Code="SC"][/Country]
[Country Title="Sierra Leone" Code="SL"][/Country]
[Country Title="Singapore" Code="SG"][/Country]
[Country Title="Slovakia (Slovak Republic)" Code="SK"][/Country]
[Country Title="Slovenia" Code="SI"][/Country]
[Country Title="Solomon Islands" Code="SB"][/Country]
[Country Title="Somalia" Code="SO"][/Country]
[Country Title="South Africa" Code="ZA"][/Country]
[Country Title="South Georgia , S Sandwich Is." Code="GS"][/Country]
[Country Title="Spain" Code="ES"][/Country]
[Country Title="Sri Lanka" Code="LK"][/Country]
[Country Title="St. Helena" Code="SH"][/Country]
[Country Title="St. Pierre And Miquelon" Code="PM"][/Country]
[Country Title="Sudan" Code="SD"][/Country]
[Country Title="Suriname" Code="SR"][/Country]
[Country Title="Svalbard, Jan Mayen Islands" Code="SJ"][/Country]
[Country Title="Sw Aziland" Code="SZ"][/Country]
[Country Title="Sweden" Code="SE"][/Country]
[Country Title="Switzerland" Code="CH"][/Country]
[Country Title="Syrian Arab Republic" Code="SY"][/Country]
[Country Title="Taiwan" Code="TW"][/Country]
[Country Title="Tajikistan" Code="TJ"][/Country]
[Country Title="Tanzania, United Republic Of" Code="TZ"][/Country]
[Country Title="Thailand" Code="TH"][/Country]
[Country Title="Togo" Code="TG"][/Country]
[Country Title="Tokelau" Code="TK"][/Country]
[Country Title="Tonga" Code="TO"][/Country]
[Country Title="Trinidad And Tobago" Code="TT"][/Country]
[Country Title="Tunisia" Code="TN"][/Country]
[Country Title="Turkey" Code="TR"][/Country]
[Country Title="Turkmenistan" Code="TM"][/Country]
[Country Title="Turks And Caicos Islands" Code="TC"][/Country]
[Country Title="Tuvalu" Code="TV"][/Country]
[Country Title="Uganda" Code="UG"][/Country]
[Country Title="Ukraine" Code="UA"][/Country]
[Country Title="United Arab Emirates" Code="AE"][/Country]
[Country Title="United Kingdom" Code="GB"][/Country]
[Country Title="United States" Code="US"][/Country]
[Country Title="United States Minor Is." Code="UM"][/Country]
[Country Title="Uruguay" Code="UY"][/Country]
[Country Title="Uzbekistan" Code="UZ"][/Country]
[Country Title="Vanuatu" Code="VU"][/Country]
[Country Title="Venezuela" Code="VE"][/Country]
[Country Title="Viet Nam" Code="VN"][/Country]
[Country Title="Virgin Islands (British)" Code="VG"][/Country]
[Country Title="Virgin Islands (U.S.)" Code="VI"][/Country]
[Country Title="Wallis And Futuna Islands" Code="WF"][/Country]
[Country Title="Western Sahara" Code="EH"][/Country]
[Country Title="Yemen" Code="YE"][/Country]
[Country Title="Yugoslavia" Code="YU"][/Country]
[Country Title="Zaire" Code="ZR"][/Country]
[Country Title="Zambia" Code="ZM"][/Country]
[Country Title="Zimbabwe" Code="ZW"][/Country]
[/Countries]

sábado, 18 de octubre de 2008

ASP.NET - Enviar correos mediante plantillas - II

Como les adelantaba en el post anterior:
Que el diseñador haga su trabajo por separado... dale una pagina.htm vacía y que te pase el html de cómo debería verse cada mensaje que se envía por correo...
para ti será muy fácil coger ese html y usarlo como plantilla para enviar mensajes de correo desde tu aplicación web.
Lo bueno?
cada vez que se quiera cambiar el formato del mensaje no tienes que recompilar la aplicación...
simplemente se reemplaza la plantilla y listo!!!

Sigamos. Ya hemos hecho la plantilla que se usará para enviar correos. Ahora necesitamos:
1.-Una funcionalidad que permita recoger los datos de un usuario y,
2.-Una funcionalidad que recupere el html de la plantilla que usaremos para enviar correos.
2.-Una funcionalidad que envíe correos de bienvenida a los usuarios.

Entonces, recogeremos los datos de los usuarios, mediante este formulario en una página default.aspx

Ahora, la pregunta es:
cómo recupero el contenido html de la plantilla?
simple... uso esta función:

    Public Shared Function GetHTMLFromAddress(ByValAddress As String) As String
        Dim 
ASCII As New System.Text.ASCIIEncoding
      
Dim netWeb As New System.Net.WebClient
      
Dim lsWeb As String
        Dim 
laWeb As Byte()

        Try
          
laWeb = netWeb.DownloadData(Address)
            lsWeb = ASCII.GetString(laWeb)
        Catch ex As Exception
          
Throw New Exception(ex.Message.ToString + ex.ToString)
        End Try
        Return 
lsWeb
    End Function

Algunos se preguntarán por qué no uso System.IO.File... para recuperar el contenido html?
porque con esa manera de recuperar el contenido de un archivo bloqueamos el archivo hasta terminar la operación de lectura... y puede ocurrir que dos personas coincidan en el mismo instante en su intento de registrarse en el sistema web y plop!! se cae tu sistema. Ese es el motivo.
En cambio, con la fución GetHTMLFromAddress no ocurre eso.

También necesitamos esta función para reemplazar en la plantilla, para mostrar la url en donde estamos:

    Public Shared Function GetApplicationPath() As String
        Dim 
strPath As String= ""
        If(Not HttpContext.Current.Request.Url Is Nothing) Then
          
strPath = HttpContext.Current.Request.Url.AbsoluteUri.Substring(0, (HttpContext.Current.Request.Url.AbsoluteUri.ToLower.IndexOf(HttpContext.Current.Request.ApplicationPath.ToLower, CType((HttpContext.Current.Request.Url.AbsoluteUri.ToLower.IndexOf(HttpContext.Current.Request.Url.Authority.ToLower) + HttpContext.Current.Request.Url.Authority.Length), Integer)) + HttpContext.Current.Request.ApplicationPath.Length))

End If
      
strPath = strPath & "/"
        Return strPath
    End Function

Luego, imagínense que alguien se registra en el sistema... luego aprieta el botón Registrarse...


Este código iría en el botón registrarse:





Protected Sub btnSend_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSend.Click
Dim urlTemplate As String = Server.MapPath("~/Plantillas/Bienvenida.htm"
        Dim Template As New StringBuilder
Template.Append(GetHTMLFromAddress(urlTemplate))
Template.Replace("$USER_NAME$", txtUserName.Text)
Template.Replace("$USER$", txtEmail.Text)
Template.Replace("$PASSWORD$", "abcde")
Template.Replace("$URL$", GetApplicationPath)

sendMail("unmonitored@jabs.com.pe", txtEmail.Text, "Bienvenido al mundo .NET", Template.ToString)

End Sub

Como ven, luego de recuperar el html de la plantilla, hago un simple reemplazo de algunos textos por los datos que ingresó el usuario y otros de la aplicación.
 Y, para redondear la faena... les adjunto la función que envía los mensajes de bienvenida:



Public Shared Function sendMail(ByVal strFrom As String, ByVal strTo As String, _
ByVal strSubject As String, ByVal strBody As String) As Boolean
Try
Dim Email As New System.Net.Mail.MailMessage(strFrom, strTo)
Email.Subject = strSubject
Email.IsBodyHtml = True
Email.Body = strBody

Dim mailClient As New System.Net.Mail.SmtpClient()
Dim basicAuthenticationInfo As New System.Net.NetworkCredential("ponga su correo aquí", "ponga su password aquí")
mailClient.Host = "ponga su servidor de correo aquí"
            mailClient.UseDefaultCredentials = False
mailClient.Credentials = basicAuthenticationInfo
mailClient.Send(Email)

Catch ex As Exception
Return False

End Try

Return True
End Function

Finalmente vean el mensaje simpaticón que llegaría a su correo...



pero lo más importante... es fácil cambiar el diseño de la plantilla.

Ahora sí, díganle a su jefe que haga todos los cambios que quiera en la plantilla... jeje.


Nota: Para el tema de aquellas plantillas que tienen palabras con acentos, simplemente reemplacen esas palabras con acentos por sus correspondientes en HTML (sólo en la plantilla), veamos:

á = &aacute
é = &eacute
í = &iacute
ó = &oacute
ú = &uacute

osea, si quiero escribir página, escribiré p&aacutegina.
;)

viernes, 26 de setiembre de 2008

ASP.NET - Enviar correos mediante plantillas - I

Casi siempre, las aplicaciones web tienen la necesidad de enviar correos, eso es una verdad aceptada.
Y también sabemos que el envío de correos se realiza de manera sencilla utilizando para ello la clase System.Net. Este post no enseñará a enviar correos, hay miles de páginas que enseñan cómo hacer eso.
Por ejemplo: http://aspnet.4guysfromrolla.com/articles/072606-1.aspx

Mas bien, en lo que nos vamos a centrar nosotros es en: cómo enviamos mensajes de correo agradablemente formateados (tipo páginas web)?...
pero además teniendo en cuenta que las estructuras de los correos deben ir separadas en archivos html...osea plantillas prediseñadas y formateadas para que el usuario simplemente elija cuál plantilla usar.

Algo más, no tenemos por qué tipear en el código (hardcodear) la estructura de la plantilla de correo. Osea, no es necesario que hagas esto:
















funciona? claro que sí... pero no es la mejor forma. Por qué? qué pasa si te piden que cambies el diseño de ese mensaje: al jefe no le gusta pues. Vas a pedirle que te pase un nuevo diseño y lo vas a tipear nuevamente en tu código VB.NET O csharp? Y luego? le vas a preguntar: Así está bien jefecito? Te dirá: Sí, está quedando de la ptm... pero mejor ponle celeste al borde... y así... vas a estar como loquito compilando y recompilando tu aplicación hasta que el jefe aliándose con el diseñador apruebe los cambios. Eso te gusta? noooooooooooo....

La solución? simple: creas una carpeta llamada Plantillas en tu proyecto... allí creas una página html llamada bienvenida.htm... en esta página pones la estructura de lo que debería ser el mensaje de correo de bienvenida. Algo así:
















Fíjate que le he puesto un rectángulo verde a los datos que sí pueden cambiar.
Entonces, lo único que debes hacer cada vez que quieres enviar un correo es mediante código recuperar el html de la página bienvenida.htm y reemplazar los textos encerrados en verdes por los del usuario que recibirá el correo.
Cómo haces eso? eso lo veremos en el próximo post.
Pero creo que ya me entendiste la idea.

martes, 9 de setiembre de 2008

ASP.NET - Asignar la url correcta - II

Estamos analizando maneras de cómo asignarle la url correcta a un tag img y/o a un tag anchor... pero desde el código html... verdad?
digo desde el código html porque desde el code behind la asignación de la ruta a un recurso es mucho más simple.

La alternativa que les propongo es: Page.ResolveUrl y Control.ResolveUrl
Yo les hablaré de Page.ResolveUrl, Uds investiguen acerca de Control.ResolveUrl jeje

Page.ResolveUrl.- Esta propiedad la usamos de esta manera:



y ella nos permitirá asignarle la ruta correcta a una imagen o a una url, sin importarnos donde estemos en ese momento.
Yo particularmente prefiero usar Page.ResolveUrl antes que hacer esto:




ya que a veces esta solución no funcionará... por ejemplo en este caso:




por qué no funcionará? porque este control mapea al conjunto de controles HtmlGenericControl, quienes no saben resolver el "~"
entonces, así si funcionaría:



Tal vez haya mejores maneras de solucionar este tema, sus aportes son bienvenidos.

lunes, 1 de setiembre de 2008

ASP.NET - Asignar la url correcta - I

Todo aquel que desarrolla aplicaciones web, es consciente que a menudo debe lidiar con el tema de estar poniéndole la url correcta para la redirección a otra página o también a cada imagen que inserta en su página web, por decir dos casos, pero hay más situaciones.






Esto no sería un problema en absoluto si toda la aplicación estuviera en un mismo folder... imaginemos:












si quisieras insertar la imagen imagen1.gif en control_de_usuario1.ascx... lo único que tendrías que hacer es poner
[img src="imagen1.gif" border="0" /]
y luego arrastro simplemente control_de_usuario1.ascx a la pagina pagina1.aspx, y listo, la imagen se mostraría sin problemas.
Lamentablemente no todo es de color de rosa en esta vida jeje.

Vamos a otro caso:
qué pasaría si mi aplicación tuviera esta estructura de organización?

y así sucesivamente. Ahora, digamos que en un control_admin1.ascx necesito jalar varias imágenes, el archivo2.css y icono1.gif ... cómo hago?

fácil no? renuncias y se acabó el problema... nooooooooooo.
y que no te parezca complicada esa estructura de arriba ah?, ni absurda... porque hay peores... cada developer implementa su propio infierno jeje, acorde a la necesidad, su experiencia y comodidad.

cómo solucionamos esto?
varias alternativas:
1.- Usar la virgulilla ~ (sólo en controles de servidor)
osea:
y solucionado: la virgulilla lo hizo otra vez!! jeje
En otras palabras, es fácil para un control de servidor resolver esta situación.

Pero no todo en la vida es control de servidor...
qué pasa si tenemos varios tag html anchor [a] para redireccionar a otras páginas. Y para colmo, estamos en un folder muy anidado. La virgulilla no funciona en controles HTML.
Lo que podrías hacer en este caso es convertir a tu control HTML en control de servidor... osea




2.-ponerle el atributo runat="server" a tu control html... y luego lo usarías así:
[a href="~/ruta_a_mi_pagina_deseada/pagina.aspx" runat="server"]ir a otra página[/a]
Pero no es una solución elegante... ni algo que deba sugerir a mis lectores incondicionales jeje... no lo hagan!!

Y Juanito me pregunta:
--Y por qué simplemente no usas puro controles de servidor?
no seas malo, sería consumir recursos innecesariamente.

Afortunadamente Scott y sus chicos han pensado en casi todo. Pero como ya se extendió mucho este artículo... mejor la seguimos mañana.

lunes, 21 de julio de 2008

ASP.NET - Encapsulando el viewstate

Modificado!
Este artículo se centra en una buena práctica de manipulación del viewstate, no en el concepto de viewstate... para aquellos que aún no sepan de viewstate, pueden revisar este artículo: Understanding ASP.NET View State

Hay que encapsular al viewstate, me refiero a que es recomendable meter al viewstate en una propiedad y de esta manera asignamos o recuperamos su valor.

En anteriores posts, hemos sugerido lo mismo para encapsular el objeto session
y para encapsular las configuraciones del web.config.

Y cuando digo que hay que encapsular al viewstate es porque hay que encapsularlo, sino estamos propensos a errores inocentes que nos pueden hacer perder tiempo por errores tan simples como tipear mal el nombre del viewstate (ya que el viewstate es sensible a minúsculas o mayúsculas, osea no es lo mismo Viewstate("View001") que Viewstate("view001") ) o asegurarse que siempre devuelva un valor por defecto... como si fuera poco, nos ahorra tipeo, osea tiempo.

Veamos como es eso de las propiedades.
Digamos que necesito guardar tres valores: Nombre, Apellido y ID... estos valores se manipulan en una página default.aspx... entonces:
1.- En el code-beside añadimos tres propiedades y tres constantes privadas, así:
'default.aspx.vb
Private Const _firstname As String = "Firstname"
Private Const _lastname As String = "Lastname"
Private Const _userID As String = "UserID"

Private Property FirstName() As String
Get
If IsNothing(Viewstate(_firstname)) Then Return String.Empty
Return ViewState(_firstname)
End Get
Set(ByVal value As String)
ViewState(_firstname) = value
End Set
End Property

Private Property LastName() As String
Get
If IsNothing(ViewState(_lastname)) Then Return String.Empty
Return ViewState(_lastname)
End Get
Set(ByVal value As String)
ViewState(_lastname) = value
End Set
End Property

Private Property UserID() As Integer
Get
If IsNothing(ViewState(_userID)) Then Return 0
Return ViewState(_userID)
End Get
Set(ByVal value As Integer)
ViewState(_userID) = value
End Set
End Property

Le podemos añadir todas las propiedades que necesitemos según los requerimientos de la aplicación... por ahora es suficiente como está.


Observe lo simple que resulta cargar las propiedades sin incurrir en errores:
Me.UserID = 1
Me.FirstName = "Gianmarcos"
Me.LastName = "Zignago"

Obviamente si a la propiedad UserID le asignamos un texto... ocurrirá una excepción... si no desean mostrar la pantalla de error que se muestra por defecto, puede personalizar el mensaje.

Es igual de sencillo obtener el valor de estas propiedades:
lblUserID.Text = Me.UserID
lblFirstName.Text = Me.FirstName
lblLastName.Text = Me.LastName


Dense cuenta que además hemos eliminado la posibilidad que devuelva un valor nulo (null en c# y nothing en vb ).

viernes, 11 de julio de 2008

Nivel de confianza Medium en ASP.NET - II

Decíamos en el anterior post que la manera recomendada de hostear múltiples aplicaciones ASP.NET sobre un servidor compartido era configurando el nivel de confianza a Medium. Esto, hay que decirlo, limita el uso de los recursos a los que se puede acceder... por ejemplo:
--No se puede acceder al proveedor de datos administrado ADO.NET OLEDB para acceder a bases de datos.
--No se puede acceder al log de eventos de Windows.
--No se puede usar reflection.
--No se puede acceder al registro de Windows.
--Sólo se puede comunicar con direcciones web externas especificadas en el elemento [trust] del web.config.
--Sólo se puede acceder a archivos que están dentro del directorio virtual de la aplicación.

Esas son las limitaciones, pero no es el fin del mundo... como ves también tiene muchos beneficios... y es que no podrán eliminarse tu aplicación web, ni hurgar en ella.
En realidad, decir que no se puede acceder al registro, ni al log de windows, etc...es mentir, sí se puede... a través de los que se llama políticas personalizadas. Sigue leyendo para que entiendas.

Digamos que tu aplicación necesita acceder a una base de datos ACCESS, para ello habría que usar OLEDB cierto?
pero hemos dicho que en un nivel de confianza Medium no se puede acceder a OLEDB... les mentí.... sí se puede... pero no por default, hay que crear una política personalizada del nivel Medium.
Veamos cómo se crea una política personalizada que lo haga:
1.- Ve a la ruta %windir%\Microsoft.NET\Framework\{Version}\CONFIG y copia el archivo web_MediumTrust.config... luego pégalo en la misma carpeta, ponle otro nombre... digamos oledb_mediumtrust.config
2.- Abre el archivo, fíjate que hay una sección [SecurityClasses], y dentro de ella están los elementos [SecurityClass... ahí debes añadir
[SecurityClass Name="OleDbPermission" Description="System.Data.OleDb.OleDbPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/]
3.- Luego, busca el elemento [NamedPermissionSets], dentro hay elementos [PermissionSet... allí debes añadir
[IPermission class="OleDbPermission" version="1" Unrestricted="true"/]

4.- Ahora modifica el archivo web.config que está en esa misma carpeta, añadiremos la nueva política personalizada que acabamos de crear. Para ello nos vamos a la zona del elemento [securityPolicy] y añadimos el trustLevel de name = CustomOleDB, referenciamos el archivo copiado y renombrado inicialmente, así quedaría:

[securityPolicy]
[trustLevel name="Full" policyFile="internal"/]
[trustLevel name="High" policyFile="web_hightrust.config"/]
[trustLevel name="Medium" policyFile="web_mediumtrust.config"/]
[trustLevel name="Low" policyFile="web_lowtrust.config"/]
[trustLevel name="Minimal" policyFile="web_minimaltrust.config"/]
[trustLevel name="CustomOleDB" policyFile="oledb_mediumtrust.config" /]
[/securityPolicy]


5.- Nada más, acabamos de crear una política personalizada... ahora para usarlo desde tu aplicación web, simplemente pones en tu web.config lo sgte:
[trustLevel = "CustomOleDB" /]

Papayita verdad??
Eso es todo, para despedirme quería recordarles algo: si Ud quiere comprobar si su aplicación está preparada para desenvolverse al 100% en un ambiente Medium, haga las pruebas necesarias en su servidor de pruebas... para esto sólo añade a tu web.config:
[trust level="Medium" originUrl="" /]

miércoles, 25 de junio de 2008

Interesante Propiedad AppendDataBoundItems

AppendDataBoundItems es una propiedad de tipo booleana que poseen varios controles que permiten enlace a datos... como el dropdownlist, el listbox o el radiobuttonlist, y cuando a esta propiedad se le marca como verdadera, nos permite mostrar tanto los elementos que hemos ingresado manualmente en el control como los que han sido ingresados a través de una fuente de datos.
ejemplo:
Digamos que un radiobuttonlist se carga con la información contenida en un dataset, de esta manera:









Hasta ahí todo normal cierto? porque así es como se hace....

pero, qué pasaría si en la vista html nosotros ya hemos agregado un item al control radiobuttonlist... no pasa nada... simplemente no se verá ese item al cargarse la página... simplemente se cargan los elementos cargados a través del code-beside.










Y cómo hacemos para poder incluir en la lista ese elemento adicional que muchas veces necesitamos?
Pues simple, le ponemos su propiedad AppendDataBoundItems = True y asunto resuelto... además podemos hacer que esa opción se muestre seleccionada por defecto.












Esto es especialmente útil en los casos en que el origen de datos es un control datasource... (osea un sqlDatasource, objectDatasource, LinqDatasource, en fin) pues en estos casos toda la configuración se realiza desde la vista diseño... y sin la propiedad AppendDataBoundItems, no tendríamos manera de añadir items adicionales de manera sencilla.

viernes, 13 de junio de 2008

ASP.NET - Encriptar el web.config - II

Hemos visto en este previo post lo fácil que resulta encriptar la sección connectionStrings del web.config...

Esta es una excelente manera de ocultar nuestra información a los malvados... claro!! si alguien logra hurtar nuestro web.config y luego intenta decriptarlo desde otra PC: no podrá hacerlo!! porque la encriptación se hizo utilizando identificadores únicos de la PC inicial.... jojolete!!

La única forma de revertir el proceso de encriptado sería ejecutar esta sentencia desde la línea de comandos (y lógicamente en la PC original):
aspnet_regiis -pd "connectionStrings" -app "/Tests2008"

Eeeeeeeexacto, lo único que ha cambiado es un parámetro... quitamos -pe y pusimos -pd

De esta manera nuestras connectionStrings del web.config retornarían a su estado inicial (osea, no encriptado).

Todo bien? todos contentos? siiiiiiiiiiiiiiiii... excellent!!
qué pasa niño Juanito? por qué pone puchero?
Juanito: es que mi proveedor de hosting nunca me va a dejar manipular la línea de comandos... por lo tanto no podré encriptar mi web.config... buuuuuuuu buuuuuuuu...

Tranquilo niño Juanito... todo tiene solución... para casos como el tuyo hay otras formas de encriptación al web.config...


Entonces haremos lo mismo pero de otra manera... presten atención,

1.- Añadimos una página llamada encriptar.aspx... y le añadimos dos botones:
btnEncriptar y btnDesencriptar, los cuales encriptarán y desencriptarán el web.config respectivamente...
Previamente hay que importar los espacios de nombres:
Imports System.Configuration
Imports System.Web.Configuration












Y eso es todo, nada del otro mundo.

martes, 10 de junio de 2008

ASP.NET - Encriptar el web.config - I

En el web.config guardamos información muy sensitiva, digamos la cadena de conexión a la base de datos, otras veces la lista de usuarios con que se puede acceder a la aplicación, y así sucesivamente... y obviamente debemos darle toda la seguridad del caso.

Ante este tipo de información hay que extremar la medidas de seguridad, si bien es cierto que desde el browser no es posible que te hurten la información del web.config, también es cierto que no es la única manera de que lo obtengan.
A través de FTP pueden descargarse sin problemas el web.config... y para ello sólo se necesita un descuido de tu parte.

La pregunta es: Cómo protejo mi web.config?
Hay varias formas... una de ellas puede ser tener un web.config que simplemente haga referencia a archivos de configuración externos (fuera del directorio virtual), estos archivos de configuración externos guardarán la información sensitiva de manera más segura. Este tema se ha abordado en
previos post.

Otra manera es encriptando la información sensitiva del web.config. Pareciera que esta tarea fuera muy difícil... nada de eso!!! es lo más simple del mundo, veamos:


Digamos que tienes una aplicación web llamada "Tests", ubicada en la siguiente ruta: G:\Inetpub\wwwroot\Tests
Y esta aplicación web guarda en su web.config esta cadena de conexión:








Vamos a empezar encriptando esta cadena de conexión, para eso hacemos lo sgte:

1.-Abrimos la línea de comandos y nos movemos de directorio, vamos a la carpeta v2.0.50727 (porque estamos trabajando con el framework 2.0 para adelante), así debe quedar:







2.- Ahí Escribimos
aspnet_regiis -pef "connectionStrings" "G:\Inetpub\wwwroot\Tests"

o
aspnet_regiis -pe "connectionStrings" -app "/Tests"
Hay que escribir "connectionStrings" tal como se ve... con S mayúscula, sino no reconocerá la orden.

Y presionamos enter, esta sentencia encriptará la sección "connectionStrings" del web.config
El resultado será algo similar a esto:














Si hubiéramos querido encriptar la sección appSettings del web.config... pues hacíamos igual que el ejemplo de arriba... sólo que reemplazábamos la palabra "connectionStrings" x "appSettings".


Nota: la operación de encriptar el web.config se debe realizar sobre la misma máquina de producción... ya que si encriptas el webconfig en una PC y luego la subes encriptada a otra PC: No funcionará... porque el algoritmo de encriptación usa algunos identficadores únicos de la PC para el encriptado... lo cual impedirá que se pueda leer desde otra PC.

Para recuperar la cadena de conexión no hay que hacer magia... no hay que decriptar nada, leyeron?? repito: no hay que decriptar nada... el framework lo hará por nosotros de manera automática... entonces para recuperar la cadena de conexión simplemente hacemos esto:




Esto tiene para rato... la seguimos en el próximo post:
Encriptar el web.config II

lunes, 2 de junio de 2008

ASP.NET - multiples archivos de configuracion III

Vean el post I y post II.
Queda por demostrar lo siguiente:
Se puede personalizar aún más el crear múltiples archivos externos? osea, crear un archivo externo llamado usuarios.config para guardar una lista de usuarios y otro llamado dominios.config para guardar una lista de dominios y otro llamado mascotas.config... etc, y así sucesivamente?
Yo dije que sí. Así que pondremos un caso simple y lo demostraremos:
Quiero tener un archivo externo que me permita guardar la lista de mis mascotas favoritas, luego quiero recuperar esa lista desde mi página web.
Solución:
En el web.config debo crear una sección, vean:













Luego, creo un archivo llamado mascotas.config en la raiz de mi aplicación web,que contenga lo sgte:


















Finalmente, para recuperar los valores de ese archivo externo, simplemente hago referencia al web.config:





















Demasiado simple para ser verdad.

Código fuente
8344656755456764143

viernes, 30 de mayo de 2008

ASP.NET - multiples archivos de configuracion II

Hemos visto en un previo artículo que sí se puede tener múltiples archivos de configuración.

Pero, hagamos un análisis de esto... preguntémonos:
vale la pena? por qué yo guardaría mis configuraciones en archivos separados y además, fuera de la carpeta de mi aplicación?

Realmente hay beneficios importantes, veamos algunos casos que serían ventajosamente resueltos:
1.- Cuando estamos en el proceso de desarrollo/modificación/etc de nuestra aplicación web... usamos una base de datos para pruebas... por lo tanto requerimos que el web.config almacene una cadena de conexión distinta a la que usaremos en producción...

Entonces, sería muy conveniente si nuestra aplicación cuando se pone a producción use las configuraciones tomadas de un archivo externo con la información real no es cierto?... porque así yo no tendría que preocuparme de verificar cuál era la cadena de conexión para esta aplicación y cuál para esta otra, etc... y lo mismo para muchas otras configuraciones... pues simplemente las recuperaría del archivo externo... cherto o no cherto?

2.- Dado que la más común forma de actualizar nuestra aplicación es mediante FTP, cierto o no cierto que la información del usuario y password del FTP puede llegar a las manos equivocadas y ... podrían bajarse tu aplicación web entera y tú ni enterado...

Ahora dime tú... si hubieras guardado las configuraciones importantes de tu aplicación en un archivo externo fuera de tu directorio virtual... pues no hubieran tenido acceso a ella... ves ahora la importancia de guardar las configuraciones en archivos separados?

Yo creo que con esas dos razones basta y sobra... hay más, expónlas tú.

Sigamos con el post, pregunta: se puede personalizar aún más el crear múltiples archivos externos? osea, crear un archivo externo llamado usuarios.config para guardar una lista de usuarios y otro llamado dominios.config para guardar una lista de dominios y otro llamado mascotas.config... etc, y así sucesivamente?
La respuesta es: no lo dudes, claro que sí se puede.
Eso lo veremos en el próximo post.


Multiples archivos de configuracion III

jueves, 29 de mayo de 2008

ASP.NET - multiples archivos de configuracion I

El archivo web.config tiene una sección especial llamada appSettings, en esa sección nosotros podemos guardar configuraciones importantes que se usarán en toda la aplicación... como por ejemplo:
-la ruta donde queremos que se guarden los archivos en el servidor o
-cuál será el skin por defecto de la aplicación o
-el idioma que usará la aplicación... y hasta
-la cadena de conexión a la base de datos... en fin.

Pero esta sección appSettings también puede guardarse en un archivo externo, es decir que el web config sólo contenga la ruta de dónde se guardan las configuraciones de la aplicación, osea quedaría así:


 

Vean que apropiado no es cierto?
lo que estoy haciendo es, en lugar de guardar las configuraciones importantes en el web.config... dejo indicado en la sección appSettings que uso un archivo externo de configuración, el cual está localizado en la ruta c:\OtroWeb.Config... y se vería asi:
OtroWeb.config:


el cual ni siquiera tiene que estar dentro del folder de la aplicación... ni siquiera tiene que estar en un directorio virtual... lo cual lo hace más seguro aún.

Y para recuperar el valor desde la aplicación ... no hay nada especial que hacer, simplemente lo llamas como siempre:


Ademas, el archivo externo con las configuraciones no tiene necesariamente que tener la extensión .config, puede ser c:\OtroWeb.txt o lo que sea...

Pero, es recomendable cambiarle la extensión?
Nooooooo, de todos modos es mejor que tenga la extensión .config.

Y por qué?
pues porque los archivos de configuración, gracias a su extensión .config, son especiales para el browser y... evitan que puedan ser descargados u obtenidos a través de un navegador.

Algo más?
Sí, pongámonos en el caso que creaste la clave/valor cnn, tanto en el web.config como en el archivo externo... osea:
en el web.config:
[add key="cnn" value="server=(local);database=pb;uid=sa;pwd=" /]
en OtroWeb.config:
[add key="cnn" value="server=123.56.76.55;database=pb;uid=sa;pwd=sa" /]

Lo que ocurrirá aquí es que el valor del web.config será ignorado, es decir prevalece el valor del archivo externo... y si fuera que en el web.config creaste algunas claves y en el archivo externo creaste otras claves diferentes... pues no habrá problema... se usarán las claves de ambos archivos.

Otra sección muy importante del web.config y que también puede guardarse en un archivo externo es la sección connectionStrings:
[connectionStrings configSource="database.config" /]

La diferencia aquí es que la ruta del archivo que guarda las connectionStrings debe ser relativa a la aplicación.

Para recuperar el valor:
Hmmmm.... está super flexible... pero, hay más?


Ahhhh quieres más? Lee los siguientes posts:

Multiples archivos de configuracion II
Multiples archivos de configuracion III

lunes, 26 de mayo de 2008

ASP.NET - Encapsulando los AppSettings del Web.Config

Ya en un anterior post, habíamos desarrollado una manera eficiente de trabajar con las sesiones, lo que habíamos hecho era encapsular las sesiones en una clase y acceder a cada sesión a través de propiedades de la clase.

Ahora vamos a mostrar un mecanismo similar para trabajar con el Web.Config, específicamente con la sección de AppSettings, que es donde guardamos configuraciones importantes que usaremos en toda la aplicación... como por ejemplo: la ruta donde queremos que se guarden los archivos en el servidor o cuál será el skin por defecto de la aplicación o el idioma que usará la aplicación... y hasta la cadena de conexión a la base de datos... en fin.








Usualmente, para acceder a cada elemento de la sección [AppSettings] hacemos esto:













y es super sencillo no es cierto?
pero estar haciendo esto cada vez que queremos acceder a los valores del web.config nos hace propensos a cometer errores de tipeo (puedes escribir mal el nombre en una de las ocasiones que intentas usar ese valor.
ejemplo:
appName = ConfigurationManager.AppSettings("xxx_ApName")
y hasta que nos demos cuenta dónde está el error...ufffffff... cuánto tiempo ya perdiste.

Entonces, igual que en estotro post, vamos a crear una clase que guade estos valores...
1.- Hacemos click derecho en el proyecto y elegimos Agregar / Clase...
Le ponemos como nombre AppSettings.vb
2.- Ponemos como primera línea:
Imports System.Configuration
3.- Y para hacerlo más intuitivo envolvemos la clase en un namespace llamado WebConfig
Y así quedaría finalmente:























Fíjense que los valores de las constantes son los nombres que se guardan en el Web.Config... esto es muy importante.
Luego, para acceder a los métodos de la clase... simplemente hacemos:











Coooooool!!