Condividi tramite


ASP.NET File Change Notifications, exactly which files and directories are monitored?

Perhaps one of the most loved and hated features of ASP.NET is the ability to detect file changes and automatically recompile or reconfigure the application.  In development scenarios it’s very nice because you can access the application in a browser at the same time you’re modifying ASPX, ASAX, DLL, CONFIG, and other application files, and you don’t have to stop the web server process in order to update DLLs or configuration.  The changes are picked up immediately, but in order to make this possible we have to recycle the AppDomain.  In deployment scenarios, this feature can be a problem.  There are many files and folders (e.g. global.asax, web.config, BIN, App_Code, etc) that trigger an AppDomain unload when changed.  A subsequent request to the application will cause the AppDomain to be loaded again and the new files will be compiled, if necessary.  Restarting the application is expensive due to the disk access and recompilation of files.  Many applications also have expensive initialization steps that occur when the AppDomain is loaded, such as accessing SQL to populate local stores with frequently accessed data.  So what exactly does ASP.NET monitor and how?

ASP.NET uses the Win32 function ReadDirectoryChangesW to monitor directories and files.  Given a directory handle, this function will let you know lots of information about changes to the directory or the files and directories contained within it.  By passing different flags, you tell it exactly what information you’re interested in and it informs you when there are changes.  ASP.NET monitors directories with the following flags (they are fairly self-explanatory, but you can refer to ReadDirectoryChangesW documentation for details):

FILE_NOTIFY_CHANGE_FILE_NAME
FILE_NOTIFY_CHANGE_DIR_NAME
FILE_NOTIFY_CHANGE_CREATION
FILE_NOTIFY_CHANGE_SIZE
FILE_NOTIFY_CHANGE_LAST_WRITE
FILE_NOTIFY_CHANGE_SECURITY

The above flags are the ones that ASP.NET uses, but not all of them are used for each directory handle that is monitored.  So which directories are monitored?  By default in ASP.NET 2.0, there are six directory monitors for each application path, and two additional directory monitors for each virtual subdirectory path.  This is best explained with an example.  Suppose that we have an application with a virtual path of "/vpath" and a physical path of "c:\ppath".  If you make a request to a file located at "/vpath/f.aspx", the following directory monitors will be created: 

#1) The application physical root path and all of its subdirectories are monitored for subdirectory name changes or deletions.  To be more precise, if FILE_NOTIFY_INFORMATION.Action is FILE_ACTION_RENAMED_OLD_NAME or FILE_ACTION_REMOVED, the AppDomain is unloaded.  This means that if you rename or delete a subdirectory beneath the application physical root, the application will be restarted.  This is discussed in Todd Carter's blog post.

ReadDirectoryChangesW is called with these arguments:

Directory= "c:\ppath"
WatchSubtree= True
NotifyFilter= FILE_NOTIFY_CHANGE_DIR_NAME

The stack trace for the call is:

   at System.Web.DirMonCompletion..ctor(DirectoryMonitor dirMon, String dir, Boolean watchSubtree, UInt32 notifyFilter)
   at System.Web.DirectoryMonitor.StartMonitoring()
   at System.Web.DirectoryMonitor.StartMonitoringFile(String file, FileChangeEventHandler callback, String alias)
   at System.Web.FileChangesMonitor.StartMonitoringDirectoryRenamesAndBinDirectory(String dir, FileChangeEventHandler callback)
   at System.Web.HttpRuntime.HostingInit(HostingEnvironmentFlags hostingFlags)

#2)  The "bin", "App_Code", "App_WebReferences", "App_GlobalResources", and "App_Browsers" subdirectories of the application root folder are monitored for creation, deletion, renaming, ACL changes, changes to the last-write time, and changes to the size.  If any of these things change, the AppDomain is unloaded.  Note that one directory monitor is created to monitor all five of these subfolders when they do not exist so that ASP.NET can catch their creation.  If they do exist, then a unique directory monitor is created for that subdirectory.  So if "bin" exists and the other four do not exist, you will have a total of two directory monitors, one for "bin" and one that monitors for the creation of the other four.  Or if "bin" and "App_Code" exist but the others do not, you will have three directory monitors, one for "bin", one for "App_Code", and one that monitors for the creation of the other three.

ReadDirectoryChangesW is called with these arguments:

Directory= "c:\ppath"
WatchSubtree= False
NotifyFilter= FILE_NOTIFY_CHANGE_FILE_NAME
                  | FILE_NOTIFY_CHANGE_DIR_NAME
                  | FILE_NOTIFY_CHANGE_CREATION
                  | FILE_NOTIFY_CHANGE_SIZE
                  | FILE_NOTIFY_CHANGE_LAST_WRITE
                  | FILE_NOTIFY_CHANGE_SECURITY

The stack trace for the call is:

   at System.Web.DirMonCompletion..ctor(DirectoryMonitor dirMon, String dir, Boolean watchSubtree, UInt32 notifyFilter)
   at System.Web.DirectoryMonitor.StartMonitoring()
   at System.Web.DirectoryMonitor.StartMonitoringFile(String file, FileChangeEventHandler callback, String alias)
   at System.Web.FileChangesMonitor.ListenToSubdirectoryChanges(String dirRoot, String dirToListenTo)
   at System.Web.FileChangesMonitor.StartMonitoringDirectoryRenamesAndBinDirectory(String dir, FileChangeEventHandler callback)
   at System.Web.HttpRuntime.HostingInit(HostingEnvironmentFlags hostingFlags)

#3) The machine.config and root web.config file are monitored for changes.  A change to either of these files will unload the AppDomain.

ReadDirectoryChangesW is called with these arguments:

Directory= "%WINDIR%\Microsoft.NET\Framework\v2.0.50727\Config"
WatchSubtree= FALSE
NotifyFilter= FILE_NOTIFY_CHANGE_FILE_NAME
                  | FILE_NOTIFY_CHANGE_DIR_NAME
                  | FILE_NOTIFY_CHANGE_CREATION
                  | FILE_NOTIFY_CHANGE_SIZE
                  | FILE_NOTIFY_CHANGE_LAST_WRITE
                  | FILE_NOTIFY_CHANGE_SECURITY

The stack trace for the call is:

   at System.Web.DirMonCompletion..ctor(DirectoryMonitor dirMon, String dir, Boolean watchSubtree, UInt32 notifyFilter)
   at System.Web.DirectoryMonitor.StartMonitoring()
   at System.Web.DirectoryMonitor.StartMonitoringFile(String file, FileChangeEventHandler callback, String alias)
   at System.Web.FileChangesMonitor.StartMonitoringFile(String alias, FileChangeEventHandler callback)
   at System.Web.Configuration.WebConfigurationHost.StartMonitoringStreamForChanges(String streamName, StreamChangeCallback callback)
   at System.Configuration.BaseConfigurationRecord.MonitorStream(String configKey, String configSource, String streamname)
   at System.Configuration.BaseConfigurationRecord.InitConfigFromFile()
   at System.Configuration.BaseConfigurationRecord.Init(IInternalConfigRoot configRoot, BaseConfigurationRecord parent, String configPath, String locationSubPath)
   at System.Configuration.RuntimeConfigurationRecord.Create(InternalConfigRoot configRoot, IInternalConfigRecord parent, String configPath)
   at System.Configuration.Internal.InternalConfigRoot.GetConfigRecord(String configPath)
   at System.Configuration.Internal.InternalConfigRoot.GetUniqueConfigRecord(String configPath)
   at System.Web.Configuration.HttpConfigurationSystem.GetUniqueConfigRecord(String configPath)
   at System.Web.CachedPathData.Init(CachedPathData parentData)
   at System.Web.CachedPathData.GetConfigPathData(String configPath)
   at System.Web.CachedPathData.GetConfigPathData(String configPath)
   at System.Web.CachedPathData.GetConfigPathData(String configPath)
   at System.Web.CachedPathData.GetConfigPathData(String configPath)
   at System.Web.Configuration.RuntimeConfig.GetAppLKGConfig()
   at System.Web.HttpRuntime.GetInitConfigSections
   at System.Web.HttpRuntime.HostingInit(HostingEnvironmentFlags hostingFlags)

#4)  The web.config of parent applications are monitored.  In this example, the root application "/" is the only parent.  A change to this file will unload the AppDomain.

ReadDirectoryChangesW is called with these arguments:

Directory= "c:\inetpub\wwwroot"
WatchSubtree= False
NotifyFilter= FILE_NOTIFY_CHANGE_FILE_NAME
                  | FILE_NOTIFY_CHANGE_DIR_NAME
                  | FILE_NOTIFY_CHANGE_CREATION
                  | FILE_NOTIFY_CHANGE_SIZE
                  | FILE_NOTIFY_CHANGE_LAST_WRITE
                  | FILE_NOTIFY_CHANGE_SECURITY

The stack trace for the call is:
  

   at System.Web.DirMonCompletion..ctor(DirectoryMonitor dirMon, String dir, Boolean watchSubtree, UInt32 notifyFilter)
   at System.Web.DirectoryMonitor.StartMonitoring()
   at System.Web.DirectoryMonitor.StartMonitoringFile(String file, FileChangeEventHandler callback, String alias)
   at System.Web.FileChangesMonitor.StartMonitoringFile(String alias, FileChangeEventHandler callback)
   at System.Web.Configuration.WebConfigurationHost.StartMonitoringStreamForChanges(String streamName, StreamChangeCallback callback)
   at System.Configuration.BaseConfigurationRecord.MonitorStream(String configKey, String configSource, String streamname)
   at System.Configuration.BaseConfigurationRecord.InitConfigFromFile()
   at System.Configuration.BaseConfigurationRecord.Init(IInternalConfigRoot configRoot, BaseConfigurationRecord parent, String configPath, String locationSubPath)
   at System.Configuration.RuntimeConfigurationRecord.Create(InternalConfigRoot configRoot, IInternalConfigRecord parent, String configPath)
   at System.Configuration.Internal.InternalConfigRoot.GetConfigRecord(String configPath)
   at System.Configuration.Internal.InternalConfigRoot.GetUniqueConfigRecord(String configPath)
   at System.Web.Configuration.HttpConfigurationSystem.GetUniqueConfigRecord(String configPath)
   at System.Web.CachedPathData.Init(CachedPathData parentData)
   at System.Web.CachedPathData.GetConfigPathData(String configPath)
   at System.Web.CachedPathData.GetConfigPathData(String configPath)
   at System.Web.Configuration.RuntimeConfig.GetAppLKGConfig()
   at System.Web.HttpRuntime.GetInitConfigSections
   at System.Web.HttpRuntime.HostingInit(HostingEnvironmentFlags hostingFlags)

#5)   The web.config in the application root is monitored.  A change to this file will unload the AppDomain.

ReadDirectoryChangesW is called with these arguments:

Directory= "c:\ppath"
WatchSubtree= False
NotifyFilter= FILE_NOTIFY_CHANGE_FILE_NAME
                  | FILE_NOTIFY_CHANGE_DIR_NAME
                  | FILE_NOTIFY_CHANGE_CREATION
                  | FILE_NOTIFY_CHANGE_SIZE
                  | FILE_NOTIFY_CHANGE_LAST_WRITE
                  | FILE_NOTIFY_CHANGE_SECURITY

The stack trace for the call is:

   at System.Web.DirMonCompletion..ctor(DirectoryMonitor dirMon, String dir, Boolean watchSubtree, UInt32 notifyFilter)
   at System.Web.DirectoryMonitor.StartMonitoring()
   at System.Web.DirectoryMonitor.StartMonitoringFile(String file, FileChangeEventHandler callback, String alias)
   at System.Web.FileChangesMonitor.StartMonitoringFile(String alias, FileChangeEventHandler callback)
   at System.Web.Configuration.WebConfigurationHost.StartMonitoringStreamForChanges(String streamName, StreamChangeCallback callback)
   at System.Configuration.BaseConfigurationRecord.MonitorStream(String configKey, String configSource, String streamname)
   at System.Configuration.BaseConfigurationRecord.InitConfigFromFile()
   at System.Configuration.BaseConfigurationRecord.Init(IInternalConfigRoot configRoot, BaseConfigurationRecord parent, String configPath, String locationSubPath)
   at System.Configuration.RuntimeConfigurationRecord.Create(InternalConfigRoot configRoot, IInternalConfigRecord parent, String configPath)
   at System.Configuration.Internal.InternalConfigRoot.GetConfigRecord(String configPath)
   at System.Configuration.Internal.InternalConfigRoot.GetUniqueConfigRecord(String configPath)
   at System.Web.Configuration.HttpConfigurationSystem.GetUniqueConfigRecord(String configPath)
   at System.Web.CachedPathData.Init(CachedPathData parentData)
   at System.Web.CachedPathData.GetConfigPathData(String configPath)
   at System.Web.Configuration.RuntimeConfig.GetAppLKGConfig()
   at System.Web.HttpRuntime.GetInitConfigSections
   at System.Web.HttpRuntime.HostingInit(HostingEnvironmentFlags hostingFlags) 

#6)  The hash.web file located in the "hash" subdirectory of the Temporary ASP.NET Files folder is monitored.  This monitor was added to support development scenarios, in which both the ClientBuildManager and the runtime BuildManager are updating the application files.  Basically, since there are two build managers, there was a need to keep them in sync, and the hash.web file is used for that purpose.

ReadDirectoryChangesW is called with these arguments:

Directory= "%WINDIR%\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\repro\19a9eafa\c159e372\hash"
WatchSubtree= False
NotifyFilter= FILE_NOTIFY_CHANGE_FILE_NAME
                  | FILE_NOTIFY_CHANGE_DIR_NAME
                  | FILE_NOTIFY_CHANGE_CREATION
                  | FILE_NOTIFY_CHANGE_SIZE
                  | FILE_NOTIFY_CHANGE_LAST_WRITE
                  | FILE_NOTIFY_CHANGE_SECURITY

The stack trace for the call is:

   at System.Web.DirMonCompletion..ctor(DirectoryMonitor dirMon, String dir, Boolean watchSubtree, UInt32 notifyFilter)
   at System.Web.DirectoryMonitor.StartMonitoring()
   at System.Web.DirectoryMonitor.StartMonitoringFile(String file, FileChangeEventHandler callback, String alias)
   at System.Web.FileChangesMonitor.StartMonitoringFile(String alias, FileChangeEventHandler callback)
   at System.Web.Compilation.BuildManager.CheckTopLevelFilesUpToDate2(StandardDiskBuildResultCache diskCache)
   at System.Web.Compilation.BuildManager.CheckTopLevelFilesUpToDate(StandardDiskBuildResultCache diskCache)
   at System.Web.Compilation.BuildManager.RegularAppRuntimeModeInitialize()
   at System.Web.Compilation.BuildManager.Initialize()
   at System.Web.Compilation.BuildManager.InitializeBuildManager()
   at System.Web.HttpRuntime.HostingInit(HostingEnvironmentFlags hostingFlags)

 

As mentioned earlier, the six directory monitors mentioned above are created when a request is made to "/vpath/f.aspx".  If there is a subdirectory and a request is made to "/vpath/subdir/f.aspx", then two additional directory monitors will be created:  

#7)  The web.config in any subdirectory of the application is monitored.  A change to this file will unload the AppDomain.

ReadDirectoryChangesW is called with these arguments:

Directory= "c:\ppath\subdir"
WatchSubtree= False
NotifyFilter= FILE_NOTIFY_CHANGE_FILE_NAME
                  | FILE_NOTIFY_CHANGE_DIR_NAME
                  | FILE_NOTIFY_CHANGE_CREATION
                  | FILE_NOTIFY_CHANGE_SIZE
                  | FILE_NOTIFY_CHANGE_LAST_WRITE
                  | FILE_NOTIFY_CHANGE_SECURITY

The stack trace for the call is:

   at System.Web.DirMonCompletion..ctor(DirectoryMonitor dirMon, String dir, Boolean watchSubtree, UInt32 notifyFilter)
   at System.Web.DirectoryMonitor.StartMonitoring()
   at System.Web.DirectoryMonitor.StartMonitoringFile(String file, FileChangeEventHandler callback, String alias)
   at System.Web.FileChangesMonitor.StartMonitoringFile(String alias, FileChangeEventHandler callback)
   at System.Web.Configuration.WebConfigurationHost.StartMonitoringStreamForChanges(String streamName, StreamChangeCallback callback)
   at System.Configuration.BaseConfigurationRecord.MonitorStream(String configKey, String configSource, String streamname)
   at System.Configuration.BaseConfigurationRecord.InitConfigFromFile()
   at System.Configuration.BaseConfigurationRecord.Init(IInternalConfigRoot configRoot, BaseConfigurationRecord parent, String configPath, String locationSubPath)
   at System.Configuration.RuntimeConfigurationRecord.Create(InternalConfigRoot configRoot, IInternalConfigRecord parent, String configPath)
   at System.Configuration.Internal.InternalConfigRoot.GetConfigRecord(String configPath)
   at System.Configuration.Internal.InternalConfigRoot.GetUniqueConfigRecord(String configPath)
   at System.Web.Configuration.HttpConfigurationSystem.GetUniqueConfigRecord(String configPath)
   at System.Web.CachedPathData.Init(CachedPathData parentData)
   at System.Web.CachedPathData.GetConfigPathData(String configPath)
   at System.Web.CachedPathData.GetConfigPathData(String configPath)
   at System.Web.CachedPathData.GetVirtualPathData(VirtualPath virtualPath, Boolean permitPathsOutsideApp)
   at System.Web.HttpContext.GetFilePathData()
   at System.Web.HttpContext.GetConfigurationPathData()
   at System.Web.ClientImpersonationContext.Start(HttpContext context, Boolean throwOnError)
   at System.Web.HttpApplication.OnThreadEnter()

#8)  The "App_LocalResources" subdirectory of each virtual subdirectory is monitored for creation, deletion, renaming, ACL changes, changes to the last-write time, and changes to the size.  If any of these things change, the AppDomain is unloaded.  This monitor is created on the virtual directory itself if the "App_LocalResources" folder does not exist; otherwise, the monitor is created on the "App_LocalResources" directory.

ReadDirectoryChangesW is called with these arguments:

Directory= "c:\ppath\subdir"
WatchSubtree= False
NotifyFilter= FILE_NOTIFY_CHANGE_FILE_NAME
                  | FILE_NOTIFY_CHANGE_DIR_NAME
                  | FILE_NOTIFY_CHANGE_CREATION
                  | FILE_NOTIFY_CHANGE_SIZE
                  | FILE_NOTIFY_CHANGE_LAST_WRITE
                  | FILE_NOTIFY_CHANGE_SECURITY

The stack trace for the call is:

   at System.Web.DirMonCompletion..ctor(DirectoryMonitor dirMon, String dir, Boolean watchSubtree, UInt32 notifyFilter)
   at System.Web.DirectoryMonitor.StartMonitoring()
   at System.Web.DirectoryMonitor.StartMonitoringFile(String file, FileChangeEventHandler callback, String alias)
   at System.Web.FileChangesMonitor.ListenToSubdirectoryChanges(String dirRoot, String dirToListenTo)
   at System.Web.FileChangesMonitor.StartListeningToVirtualSubdirectory(VirtualPath virtualDir)
   at System.Web.Compilation.BuildManager.EnsureFirstTimeDirectoryInit(VirtualPath virtualDir)
   at System.Web.Compilation.BuildManager.GetBuildResultFromCacheInternal(String cacheKey, Boolean keyFromVPP, VirtualPath virtualPath, Int64 hashCode)
   at System.Web.Compilation.BuildManager.GetVPathBuildResultFromCacheInternal(VirtualPath virtualPath)
   at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal
   at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert
   at System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean noAssert)
   at System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath
   at System.Web.UI.PageHandlerFactory.GetHandlerHelper(HttpContext context, String requestType, VirtualPath virtualPath, String physicalPath)
   at System.Web.UI.PageHandlerFactory.System.Web.IHttpHandlerFactory2.GetHandler
   at System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig)
   at System.Web.HttpApplication.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 

So what about global.asax, or the f.aspx page that we used in the example?  Aren't they monitored?  Yes, they are, but they piggy back on one of the directory monitors listed above.  In the example, both global.asax and f.aspx would be added to the directory monitor described in #5.  Each directory monitor is capable of monitoring many different files, each with a unique callback for notification upon any changes.  I hope this helps your understanding. I've also included an ASPX page code sample below that will display the number of requests, number of AppDomain restarts, and number of active directory monitors.  I'm not sure why you would want to know how many directory monitors are active in your application, but if someone asks you, you can always requests this page and answer them.  :)

 

 <%@ import namespace="System.Diagnostics"%>
<%@ import namespace="System.Reflection"%>
 <script runat="server" language="c#">
void Page_Load() {
    PerformanceCounter pc1 = new PerformanceCounter("ASP.NET Applications", 
                                                    "Requests Total", 
                                                    "__Total__");
    
    PerformanceCounter pc2 = new PerformanceCounter("ASP.NET", 
                                                    "Application Restarts");
    
    Type t = typeof(HttpRuntime).Assembly.GetType(
                                               "System.Web.DirMonCompletion");
    
    int dirMonCount = (int) t.InvokeMember("_activeDirMonCompletions",
                                           BindingFlags.NonPublic 
                                           | BindingFlags.Static
                                           | BindingFlags.GetField, 
                                           null, 
                                           null, 
                                           null); 
      
    // The perf client polls the server every 400 milliseconds
    System.Threading.Thread.Sleep(800);
    
    Response.Output.WriteLine(
                            "Requests={0},Restarts={1},DirMonCompletions={2}",
                            pc1.NextValue(), 
                            pc2.NextValue(), 
                            dirMonCount);
}
</script>

 

 -Thomas

Comments

  • Anonymous
    November 02, 2007
    Hate to say, your color scheme makes reading this very hard.

  • Anonymous
    November 02, 2007
    Do you think the contrast is the problem (text should be brighter, background darker), or is it that you do not like light text on a dark background?  I personally find the color scheme as easy to read as the more traditional black text on a white background.  Thanks for the feedback, and I will look into making this easily readable for everyone.

  • Anonymous
    September 11, 2008
    Knowing when to restart IIS to pick up various types of changes to your application has traditionally

  • Anonymous
    February 11, 2009
    也许你知道,修改站点的某些特定文件和目录会导致整个站点重启或者重新编译。也许你不注意,你不会知道删除或重命名站点下的任意目录,会导致整个站点重启。这个问题其实是很多Session丢失的根源,比如《关于...

  • Anonymous
    August 19, 2009
    We have looked at the conditions that you have mentioned for the AppDomina to Restart. We have a ASP.Net 1.1 application and we are getting the [AppDomainUnloadedException]: Attempted to access an unloaded AppDomain.   at System.Threading.Thread.SetCompressedStackInternal(IntPtr unmanagedCompressedStack)   at System.Threading.Thread.SetCompressedStack(CompressedStack stack)   at System.Xml.XmlTextReader.CreateScanner()   at System.Xml.XmlTextReader.Init()   at System.Xml.XmlTextReader.Read()   at System.Xml.XmlReader.MoveToContent()   at System.Web.Configuration.XmlUtil.OpenXmlTextReader()   at System.Web.Configuration.HttpConfigurationRecord..ctor(String filename, HttpConfigurationRecord parent, Boolean inheritable, String path, String mappedPhysicalPath) Description : An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately. Parser Error Message: The XML file c:winntmicrosoft.netframeworkv1.1.4322Configmachine.config could not be loaded.  Attempted to access an unloaded AppDomain. We added a code snippet in the Global.ASAX n Application_End to log the failure event in the Event viewer. The message logged was: _shutDownMessage=Overwhelming Change Notification in F:DataWebSitesDiffExDiffEx_Webservice Change in GLOBAL.ASAX CONFIG change _shutDownStack=   at System.Environment.GetStackTrace(Exception e)   at System.Environment.GetStackTrace(Exception e)   at System.Environment.get_StackTrace()   at System.Web.HttpRuntime.ShutdownAppDomain()   at System.Web.HttpApplicationFactory.OnAppFileChange(Object sender, FileChangeEvent e)   at System.Web.DirectoryMonitor.OnFileChange(FileAction action, String fileName)   at System.Web.DirMonCompletion.OnFileChange(FileAction action, String fileName). We were doing continuous logging using Log4Net in the application root directory and understood that this could be causing the issue to occur. We moved the logging outside this directory and the problem seemed to have gone away. This application was working with this logging for a long time, but the question why is issue coming up now. We have done some changes in the code and that was nothing to do with the logging, one some performance changes that take a bit more memory than usual. Please suggest, any help will be appreciated.

  • Anonymous
    April 26, 2011
    thanks thomas... this is very helpful article... i know now what i need to do...

  • Anonymous
    March 08, 2012
    Is there any way to change this behaviour?  I'm running project that generates asp pages dynamicaly and then external process deletes unnecessary files, and sure it's not acceptable to run session start/end each time it happens.

  • Anonymous
    March 09, 2012
    I've been off the ASP.NET team for a couple years now, but if you're not using ASP.NET's compilation system, which does have a few extension points, then what you're doing probably is not supported.   Perhaps you should be using the BuildProvider (msdn.microsoft.com/.../system.web.compilation.buildprovider.aspx) class?  I'm no expert in this area, especially since I'm not on the ASP.NET team anymore, but you can probably find help at http://forums.asp.net/ or http://stackoverflow.com. Thanks, Thomas

  • Anonymous
    August 16, 2014
    The comment has been removed