[HowTo] Modificar cadena de conexión, la eterna pregunta

Si no la he leído 200 veces en los foros MSDN no la he leído ninguna :-) vayan unos ejemplos:

Es posible modificar el App.config de una aplicación C# en tiempo de ejecución?

Cómo hago para cambiar los datos de conexión en tiempo de ejecución?

Cadena de conexión Dinámica, ¿cómo debo hacer esta modificación desde un windows form en el mismo aplicativo?

Y así unas cuantas. De hecho una búsqueda me ha arrojado más de 3.000 resultados :-S

De todos modos lo que me sorprende no es tanto el alto número de veces que se hace esta pregunta, sino que cada vez que la respondo me digo a mi mismo: Haz un post y publícalo para referenciar a la gente… y siempre se me olvida 😛

Bueno, pues de hoy no pasa. Y es que curiosamente me ha llegado la misma pregunta por dos medios distintos. Uhm… casualidad? No lo creo. Sin duda es una señal divina: El MEV me está hablando y yo -pobre mortal- debo obedecer.

App.config y Machine.config

A ver, el quid de la cuestión es que la primera vez que usamos una cadena de conexión (en un DataSource, Contexto de datos, etc.) el propio Visual Studio genera en el fichero app.config una entrada con nombre para nuestra aplicación. Esta entrada es parecida a esto:

<connectionStrings>

  <clear />

  <add name="YourApp.Properties.Settings.YourAppConnectionString"

    connectionString="Data Source=.sqlexpress;Initial Catalog=YourDataBase;Integrated Security=True"

    providerName="System.Data.SqlClient" />

</connectionStrings>

Y sirve para que si alguna vez deseamos cambiar el nombre del servidor, o la base de datos, o cualquier otro atributo, lo hagamos en un único sitio.

Antes de seguir un detalle: ¿Os habéis fijado si en vuestro app.config tenéis un clear antes de la cadena de conexión? Si no lo tenéis, os aconsejo añadirlo. Este clear lo que hace es no cargar las cadenas de conexión  del fichero machine.config, que es común a todas las aplicaciones.

Y es que cuando se inicia una aplicación de .NET, se cargan las secciones comunes del machine.config y a continuación se añaden las propias de la aplicación definidas en el app.config.

Como por defecto en el machine.config tenemos esto:

<connectionStrings>

    <add name="LocalSqlServer" connectionString="data source=.SQLEXPRESS;Integrated Security=SSPI;

    AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient"/>

</connectionStrings>

Si no usamos el tag clear, al ejecutar nuestra aplicación tendremos dos cadenas de conexión, y la primera será la del machine.config… y eso no nos gusta 😛

Así que asumiendo que ya habéis agregado el tag clear, vamos al turrón.

System.Configuration

En este ensamblado encontraremos todo lo necesario para la gestión de nuestras cadenas de configuración (y muchas cosas más).

Lo primero es agregar una referencia a este ensamblado a nuestro proyecto:

References_system_configuration

Y a continuación crearemos una clase con un par de métodos para leer y guardar las cadenas de conexión en el app.config:

public class ConnectionStringManager

{

    public static string GetConnectionString(string connectionStringName)

    {

        Configuration appconfig =

            ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

        ConnectionStringSettings connStringSettings = appconfig.ConnectionStrings.ConnectionStrings[connectionStringName];

        return connStringSettings.ConnectionString;

    }

 

    public static void SaveConnectionString(string connectionStringName, string connectionString)

    {

        Configuration appconfig =

            ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

        appconfig.ConnectionStrings.ConnectionStrings[connectionStringName].ConnectionString = connectionString;

        appconfig.Save();

    }

}

Básicamente, al primero se le pasa el nombre de la cadena de conexión a recuperar (por si tenemos varias) y nos devuelve la cadena de conexión. Al segundo se le pasa el nombre de la cadena de conexión y la nueva cadena de conexión modificada.

Para hacerlo un poco más sencillo y no tener que recordar el nombre de las cadenas de conexión, vamos a crear algunos métodos más en la clase. Uno que retorne la lista de nombres de las cadenas de conexión del fichero de configuración, y otro que retorne sólo el nombre de la primera (muy útil si sólo tenemos una).

public static List<string> GetConnectionStringNames()

{

    List<string> cns = new List<string>();

    Configuration appconfig =

        ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

    foreach (ConnectionStringSettings cn in appconfig.ConnectionStrings.ConnectionStrings)

    {

        cns.Add(cn.Name);

    }

    return cns;

}

 

public static string GetFirstConnectionStringName()

{

    return GetConnectionStringNames().FirstOrDefault();

}

Incluso, basándonos en este último podemos crear otro que nos devuelva la primera cadena de conexión:

public static string GetFirstConnectionString()

{

    return GetConnectionString(GetFirstConnectionStringName());

}

Let’s play!

A partir de esta clase, trabajar con las cadenas de conexión es muy sencillo. Supongamos que tenemos un formulario similar a esto:

form_sqlserver_settings

Leer los valores de la cadena de conexión y mostrarlos es tan sencillo como esto:

private void showSavedConnectionSettings()

{

    SqlConnectionStringBuilder builder =

        new SqlConnectionStringBuilder(ConnectionStringManager.GetFirstConnectionString());

    connectionServerComboBox.EditValue = builder.DataSource.ToUpper();

    connectionDatabaseComboBox.EditValue = builder.InitialCatalog.ToUpper();

    if (builder.IntegratedSecurity)

    {

        connectionAuthenticationModeRadioGroup.EditValue = 0;

        connectionUsernameTextEdit.Text = string.Empty;

        connectionPasswordTextEdit.Text = string.Empty;

    }

    else

    {

        connectionAuthenticationModeRadioGroup.EditValue = 1;

        connectionUsernameTextEdit.Text = builder.UserID;

        connectionPasswordTextEdit.Text = builder.Password;

    }

}

Es decir, creamos un SqlConnectionStringBuilder a partir de la primera cadena de conexión del fichero de configuración y a partir de aquí, trabajamos por separado con cada una de las partes de la cadena, accediendo a las propiedades del builder (Datasource, InitialCatalog, IntegratedSecurity, etc.). De este modo las mostramos en el form, o dónde queramos…

Guardando que es gerundio

La siguiente pregunta lógica es: ¿Y para guardar sólo uno de los valores en el fichero de configuración? El típico ejemplo es modificar el nombre del servidor al instalar en el cliente final. Para ello vamos a usar también un builder, y vamos a ampliar la clase anterior con algunos métodos más. Para obtener los valores de las propiedades de la cadena de conexión y para guardarlos:

Obtener valores de propiedades de la cadena de conexión:

public static string GetSqlServerServerName()

{

    string cs = GetConnectionString(GetFirstConnectionStringName());

    if (cs != null)

    {

        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(cs);

        return builder.DataSource;

    }

    else

        return null;

}

 

public static string GetSqlServerDatabaseName()

{

    string cs = GetConnectionString(GetFirstConnectionStringName());

    if (cs != null)

    {

        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(cs);

        return builder.InitialCatalog;

    }

    else

        return null;

}

 

public static string GetSqlServerUserName()

{

    string cs = GetConnectionString(GetFirstConnectionStringName());

    if (cs != null)

    {

        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(cs);

        return builder.UserID;

    }

    else

        return null;

}

 

public static string GetSqlServerPassword()

{

    string cs = GetConnectionString(GetFirstConnectionStringName());

    if (cs != null)

    {

        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(cs);

        return builder.Password;

    }

    else

        return null;

}

 

public static bool? GetSqlServerIntegratedSecurity()

{

    string cs = GetConnectionString(GetFirstConnectionStringName());

    if (cs != null)

    {

        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(cs);

        return builder.IntegratedSecurity;

    }

    else

        return null;

}

Guardar valores de propiedades en la cadena de conexión:

public static string SetConnectionStringServerName(

    string connectionString, string serverName)

{

    SqlConnectionStringBuilder builder =

        new SqlConnectionStringBuilder(connectionString);

    builder.DataSource = serverName;

    return builder.ConnectionString;

}

 

public static string SetConnectionStringAutenticationIntegrated(

    string connectionString)

{

    SqlConnectionStringBuilder builder =

        new SqlConnectionStringBuilder(connectionString);

    builder.IntegratedSecurity = true;

    return builder.ConnectionString;

}

 

public static string SetConnectionStringAutenticationSQLServer(

    string connectionString, string username, string password)

{

    SqlConnectionStringBuilder builder =

        new SqlConnectionStringBuilder(connectionString);

    builder.IntegratedSecurity = false;

    builder.UserID = username;

    builder.Password = password;

    return builder.ConnectionString;

}

 

public static string SetConnectionStringDatabaseName(

    string connectionString, string databaseName)

{

    SqlConnectionStringBuilder builder =

        new SqlConnectionStringBuilder(connectionString);

    builder.InitialCatalog = databaseName;

    return builder.ConnectionString;

}

Así pues, para cambiar el nombre del servidor en el app.config bastaría con:

  1. Leer la cadena de conexión actual
  2. Cambiar el nombre del server
  3. Volver a guardar la cadena de conexión
string cs = ConnectionStringManager.GetFirstConnectionString();

string newConStr = ConnectionStringManager.SetConnectionStringServerName(cs, "MyNewServer");

ConnectionStringManager.SaveConnectionString(

    ConnectionStringManager.GetFirstConnectionStringName(), newConStr);

Me han quedado bastantes cosas en el tintero (recuperar los servidores SQL Server de nuestra red local, mostrar las bases de datos de un server, o crear un formulario para el usuario final). Si hay tiempo y pensáis que es un tema de interés lo veremos en futuros posts.

Nos vemos! 😀

[HowTo] Obtener fechas de principio y final de mes… y de trimestre

Vale, lo se. Es una chorrada :-)

Pero es una de esas cosas que no puedes creer que no está implementado en el framework ‘de fábrica’, y si lo está debe estar escondido porque yo no lo he encontrado. Y la cuestión es que ayer necesitaba calcular (a partir de una fecha) las fechas de inicio y final de mes, así como las fechas de inicio y final de trimestre.

Aquí está el código por si alguien se encuentra con el mismo problema:

public static class BaseTypesExtensions

{

    public static int GetQuarter(this DateTime d)

    {

        return ((d.Month - 1) / 3) + 1;

    }

 

    public static DateTime GetMonthFirstDate(this DateTime d)

    {

        return new DateTime(d.Year, d.Month, 1);

    }

 

    public static DateTime GetMonthLastDate(this DateTime d)

    {

        return d.GetMonthFirstDate().AddMonths(1).AddDays(-1);

    }

 

    public static DateTime GetQuarterFirstDate(this DateTime d)

    {

        return new DateTime(d.Year, (d.GetQuarter() * 3) - 2, 1);

    }

 

    public static DateTime GetQuarterLastDate(this DateTime d)

    {

        return d.GetQuarterFirstDate().AddMonths(3).AddDays(-1);

    }

}

Y lo usaríamos de este modo:

var basedate = DateTime.Today.AddYears(-1);

for (int i = 0; i < 23; i++)

{

    basedate = basedate.AddMonths(1);

    var logline = "Date: {0}, Month {1}-{2}, Quarter: {3}-{4}";

    Console.WriteLine(logline, basedate.ToShortDateString(),

        basedate.GetMonthFirstDate().ToShortDateString(), 

        basedate.GetMonthLastDate().ToShortDateString(),

        basedate.GetQuarterFirstDate().ToShortDateString(), 

        basedate.GetQuarterLastDate().ToShortDateString());

}

Produciendo este resultado:

Date: 05/11/2010, Month 01/11/2010-30/11/2010, Quarter: 01/10/2010-31/12/2010

Date: 05/12/2010, Month 01/12/2010-31/12/2010, Quarter: 01/10/2010-31/12/2010

Date: 05/01/2011, Month 01/01/2011-31/01/2011, Quarter: 01/01/2011-31/03/2011

Date: 05/02/2011, Month 01/02/2011-28/02/2011, Quarter: 01/01/2011-31/03/2011

Date: 05/03/2011, Month 01/03/2011-31/03/2011, Quarter: 01/01/2011-31/03/2011

Date: 05/04/2011, Month 01/04/2011-30/04/2011, Quarter: 01/04/2011-30/06/2011

Date: 05/05/2011, Month 01/05/2011-31/05/2011, Quarter: 01/04/2011-30/06/2011

Date: 05/06/2011, Month 01/06/2011-30/06/2011, Quarter: 01/04/2011-30/06/2011

Date: 05/07/2011, Month 01/07/2011-31/07/2011, Quarter: 01/07/2011-30/09/2011

Date: 05/08/2011, Month 01/08/2011-31/08/2011, Quarter: 01/07/2011-30/09/2011

Date: 05/09/2011, Month 01/09/2011-30/09/2011, Quarter: 01/07/2011-30/09/2011

Date: 05/10/2011, Month 01/10/2011-31/10/2011, Quarter: 01/10/2011-31/12/2011

Date: 05/11/2011, Month 01/11/2011-30/11/2011, Quarter: 01/10/2011-31/12/2011

Date: 05/12/2011, Month 01/12/2011-31/12/2011, Quarter: 01/10/2011-31/12/2011

Date: 05/01/2012, Month 01/01/2012-31/01/2012, Quarter: 01/01/2012-31/03/2012

Date: 05/02/2012, Month 01/02/2012-29/02/2012, Quarter: 01/01/2012-31/03/2012

Saludos,

PD – Thx al colega Omar del valle por sugerir una aproximación mucho más sencilla para GetQuarter 😉

MVP por noveno año y cambio de categoría :-D

:-)
Hola a todos!

Un post cortito que estoy de fin de semana.

mvplogohor

Acabo de recibir un correo (o más bien debería decir EL correo) que muchos de nosotros esperamos el 1 de Octubre:

Enhorabuena. Nos complace presentarle el programa de nombramiento MVP de Microsoft® de 2011. Este nombramiento se concede a los líderes excepcionales de la comunidad técnica que comparten de forma activa su experiencia de alta calidad y de la vida real con otras personas. Le agradecemos especialmente la contribución que ha realizado en las comunidades técnicas en el área de Visual C# a lo largo del pasado año.

El correo de la fatalidad. El correo del reconocimiento -o no- como Microsoft MVP para el próximo año. Y parece que se han vuelto a equivocar… por que alguien ha decidido que merezco estar otro año llevando ese pin tan chulo que nos regalan, y rodeado de toda esa gente tan cojonuda. Y perdonar que lo diga tan claro, pero realmente es así.

Por encima de todo (reconocimiento, beneficios, dinero y mujeres) lo mejor de este programa es la gente. Siendo MVP conoces gente que profesionalmente son unos monstruos (de buenos), y además ves cómo estos tíos dedican un % enorme de su tiempo a ayudar y colaborar desinteresadamente, haciendo crecer la comunidad. Que a su vez es la madre de todos los MVPs y de muchos otros, ya que hay gente muuuuy buena y preparada que todavía no ha tenido la oportunidad de entrar en este programa.

Además, este año si no he leído mal el correo se ha reconocido mi contribución al area de C#, en lugar de VB como hasta ahora. Supongo que es normal, ya que hace unos cuantos años que no toco nada de VB, pero de todos modos se agradece.

Muchísimas gracias a todos. De verdad :-)

Ahora permitirme copypastear unas fotos del post del año pasado… que no tengo material aquí dónde estoy de weekend 😛

<copypaste>

Aquí tenéis algunos momentos de estos años:

DCP_1608DCP_1652DCP_1629

P1010037P1010059P1010029

fb1fb2fb3

 

fb6fb4fb5

 

Son simplemente algunos momentos escogidos al azar entre tantos buenos momentos. Encontraréis a algunos de los que ya no están, y también veréis a algunos que casi no se reconocen, jejeje… A ver que día me pongo a revisar más a fondo los cientos de archivos de fotos que tengo (sobretodo de los primeros años), seguro que aparecen auténticas ‘perlas’:-)

Un abrazo enorme a todos, los que son MVP, los que no, y en general a todos aquellos que dedican su tiempo a hacer más grande la comunidad. Todos son MVP, tengan o no tengan la distinción. Chavales, entre todos estamos contribuyendo a hacer algo grande.

</copypaste>

PD – Tengo que deciros que cada año que pasa lo llevo mejor, hoy sólo había entrado a consultar el correo 3 veces 😀