Come probabilmente saprete, i provider vengono caricati in memoria, attraverso l’utilizzo di classi statiche, all’avvio dell’applicazione web. Proprio perchè il loro ciclo di vita dipende strettamente da quello dell’applicazione, è impossibile modificarne le proprietà, come ad esempio la stringa di connessione al database.
Ma perchè doverla modificare? Un esempio potrebbe essere quello che segue.
Abbiamo la necessità di definire due diverse strighe di connessione, una per l’ambiente di sviluppo e l’altra per quello di produzione. Generalmente esse verranno salvate all’interno del file web.config nella sezione connectionStrings:
<connectionStrings>
<!-- Sviluppo -->
<add name="DebugConnString" connectionString="Data Source=ServerSviluppo;Initial Catalog=MioDatabase;" providerName="System.Data.SqlClient"/>
<!-- Produzione -->
<add name="ProductionConnString" connectionString="Data Source=ServerProduzione;Initial Catalog=MioDatabase;" providerName="System.Data.SqlClient"/>
</connectionStrings>
E potrebbero essere utilizzate, ad esempio, per un Membership Provider:
<membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="30">
<providers>
<clear />
<add
name="SqlProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="DebugConnString"
applicationName="MiaApplicazione"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
requiresUniqueEmail="true"
passwordFormat="Hashed" />
</providers>
</membership>
Passando da un ambiente all’altro ci troviamo quindi a dover modificare manualmente il file web.config per selezionare la stringa di connessione necessaria, senza pensare ai problemi che potrebbero derivare da una eventuale dimenticanza.
La soluzione a questi problemi consiste nell’utilizzo della Reflection, che ci consente di andare a modificare le variabili di una classe, anche quando queste sono state dichiarate private. Il codice che segue va aggiunto al file Global.asax:
<%@ Application Language="C#" %>
<%@ Import Namespace="System.Reflection" %>
<%@ Import Namespace="System.Configuration" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
// Cerco il provider
MembershipProvider mp = Membership.Provider;
Type t = mp.GetType();
// Cerco la variabile privata _sqlConnectionString all'interno dell'istanza
// del provider
FieldInfo info = t.GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.NonPublic);
// La modifico a seconda di quella che ci serve
// Soltanto il codice necessario verrà effettivamente compilato
#if DEBUG
// Siamo in sviluppo
info.SetValue(mp,
ConfigurationManager.ConnectionStrings["DebugConnString"].ConnectionString);
#else
// Siamo in produzione
info.SetValue(mp,
ConfigurationManager.ConnectionStrings["ProductionConnString"].ConnectionString);
#endif
}
</script>
Anche se è da considerarsi più un “trucco” che una pratica di programmazione corretta, questo sistema funziona e può tornare utile in molte situazioni.