Como muchos sabréis ya, seguramente aquellos que tengais proyectos en la nube de Azure, la topología de Sql Azure puede darnos unos cuantos quebraderos de cabeza, puesto que, en determinadas condiciones podríamos tener pérdidas de conexiones. En la wiki de Technet hay un articulo muy bueno explicando tanto la topología de SQL de Azure así como los distintos problemas y sus motivos. Navegando por la web hay cantidad de articulos referidos a como manejar los problemas de conexión en ADO.NET tradicional, sin embargo, no hay esta información sobre como manejar estos problemas con Entity Framework, de hecho, hasta he leído que esto invalidaba el uso de EF en AZURE. Pues bien, a lo largo de este post veremos como manejarnos con AZURE y EF de una forma realmente sencilla. Para ello haremos un par de casos, el primero utilizando EF sin artefacto de generación y posteriormente con un artefacto cualquiera, STE por ejemplo.
Para el primer caso, sabemos que el contexto de trabajo de ADO.NET Entity Framework nos ofrece un método parcial OnContextCreated dónde nosotros podemos escribir código una vez que un contexto de trabajo de EF se crea. La llamada a este método parcial está en cada uno de los constructores de la clase. En este método parcial podríamos escribir el siguiente código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<span class="kwrd">partial</span> <span class="kwrd">void</span> OnContextCreated() { Connection.Open(); var storeConnection = (SqlConnection)((EntityConnection)Connection).StoreConnection; <span class="kwrd">try</span> { <span class="rem">// Issue a low overhead test command</span> <span class="kwrd">new</span> SqlCommand(<span class="str">"declare @i int"</span>, storeConnection).ExecuteNonQuery(); } <span class="kwrd">catch</span> (SqlException) { <span class="rem">// Close and reopen the connection</span> <span class="rem">// ADO.NET should take care of invalidating the pool</span> <span class="rem">// since an exception was already detected</span> Connection.Close(); Connection.Open(); } } |
Como se puede apreciar, este código unicamente recupera la conexión interna del contexto de trabajo y ejecuta un comando ‘tonto’ contra la base de datos. Sin nos encontraramos ante el caso de una conexión perdida, este comando fallaría entrando en nuestro manejador de excepción. En este manejardor, cerramos y abrimos la conexion, esto en ADO.NET nos garantiza que el pool de conexiones se invalida, el siguiente artículo hablar claramente sobre las invalidaciones del pool en ADO.NET.
En el caso de que estemos trabajando con algún artefacto de generación de código como STE, podremos ver como el método parcial OnContextCreated ya no está disponible. Lógicamente, al tener nuestras plantillas T4, el uso de métodos parciales ya no tiene demasiado sentido puesto que el código a generar lo podemos escribir directamente en la plantilla. No obstante, para no complicar demasiado el ejemplo del post, podemos agregar dentro de los constructores de nuestro contexto en la plantilla, una llamada a OnContextCreated, como se ve a continuación, y establecer este método directamente dentro de nuestra plantilla.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<span class="kwrd">public</span> <#=code.Escape(container)#>() : <span class="kwrd">base</span>(ConnectionString, ContainerName) { Initialize(); OnContextCreated(); } <span class="kwrd">public</span> <#=code.Escape(container)#>(<span class="kwrd">string</span> connectionString) : <span class="kwrd">base</span>(connectionString, ContainerName) { Initialize(); OnContextCreated(); } <span class="kwrd">public</span> <#=code.Escape(container)#>(EntityConnection connection) : <span class="kwrd">base</span>(connection, ContainerName) { Initialize(); OnContextCreated(); } |
1 |
  |
En el proyecto NLayerApp de Microsoft en su version 1.0, que espero ya conozca, puede ver un ejemplo completo de una solución de Azure con este workaround para Sql Azure.
Saludos
Unai
Me ha venido de lujo!! Gracias!!
Hola Unai, creía que esto me solucionaría el problema pero sigo teniendo :
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible…
Cuando pongo mi aplicación (basada en NLayerApp) en Staging/Production. En local va perfecta incluso con la base de datos apuntando al mismo servidor de SQL Azure. Alguna idea??
Tu error no está relacionado con esto, un error del tipo que comento es tan aleatorio y raro que no creo que lo puedas ver contastemente con lo cual tienes alguna cadena de conexion incorrecta, el cortafuegos o cualquier otro error….
Saludos
Unai