viernes, 1 de julio de 2011

File Change Notification en ASP.NET

Si esto que te voy a contar nunca te ha pasado, estás de enhorabuena. En caso contrario espero que te sirva esta solución para no perder incontables horas navegando por Internet con cara de desahuciado.

El problema es que cuando eliminamos directorios por código, almacenados en la raíz de nuestra aplicación ASP.NET, el AppDomain asociado se reinicia. Esto significa que perderemos cualquier valor almacenado en Session (a no ser que la estés guardando en base de datos), en Cache, volverá a ejecutarse los eventos de Application en global.asax, etc.

Que te pase esto no es tan difícil. Por ejemplo en mi empresa estamos haciendo un programa que sube ficheros y los guardamos en App_Data. Por motivos que no son relevantes para este post, en un momento dado tenemos que eliminar subdirectorios que previamente hemos creado. Pues bien, en ese preciso instante se nos cae el chiringuito y la aplicación se reinicia.

Esto sucede desde ASP.NET 2.0 en adelante (curiosamente no sucede en ASP.NET 1.x) y es porque el componente FCN (File Change Notifications) está constantemente monitorizando cambios en la estructura de disco de nuestra aplicación para que en el caso de haya cambios se vuelva a compilar la aplicación automáticamente, siempre que sea necesario.

Que este componente esté vigilando la carpeta App_Data, lo cierto es que no le encuentro demasiado sentido. Es decir, está claro que agradezco que monitorice el directorio \bin, cambios en ficheros aspx, ascx, etc. ¿Pero en App_Data?

En cualquier caso, la única solución que hemos encontrado ha sido detener este proceso, es decir, decirle a ASP.NET que los cambios en mi aplicación no reinicien mi aplicación (cabe aclarar que el directorio \bin no se puede escapar a esta monitorización y seguirá activo y además casi lo agradezco, sino sería muy drástico).

El método es el siguiente y simplemente hay que llamarlo una única vez en el evento Application_Start (global.asax).

    Public Shared Sub StopFCN()

        Dim p As PropertyInfo = GetType(System.Web.HttpRuntime).GetProperty("FileChangesMonitor", BindingFlags.NonPublic Or BindingFlags.[Public] Or BindingFlags.[Static])

        Dim o As Object = p.GetValue(Nothing, Nothing)

        Dim f As FieldInfo = o.[GetType]().GetField("_dirMonSubdirs", BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.IgnoreCase)

        Dim monitor As Object = f.GetValue(o)

        Dim m As MethodInfo = monitor.[GetType]().GetMethod("StopMonitoring", BindingFlags.Instance Or BindingFlags.NonPublic)

        m.Invoke(monitor, New Object() {})

    End Sub


Si quieres ampliar más información al respecto, puedes visitar los siguientes enlaces:

http://blogs.msdn.com/b/toddca/archive/2005/12/01/499144.aspx

http://www.eggheadcafe.com/software/aspnet/30642781/workaround-for-fcndirectory-delete-bug.aspx

Un saludo!

1 comentario: