The operating system is not presently configured to run this application

After installing Visual Studio 2010, I started getting an error message every now and then when I would try to view the designer in Visual Studio 2008.

The first popup would say:

The operating system is not presently configured to run this application

Which was followed by the message:

Cannot load MSO.dll

I found that mso.dll was located in “C:Program FilesCommon Filesmicrosoft sharedOFFICE12”, and after adding that path to my PATH environment variable in Windows (I’m running XP Pro) the issue seems to have gone away in VS2008.

Marking things as deprecated in VB.Net

If you have some old classes/methods that you can’t get rid off, but you dont’ want anyone to use them for new development, you should mark them as deprecated, which can be done with the Obsolete tag:

<Obsolete("Don't use this class")> _
Public Class Whatever

End Class

This will cause any reference to Whatever to produce a warning.  You can treat these as errors if you want by using one of the other constructors like this:

<Obsolete("Don't use this class", True) > _
Public Class Whatever

End Class

Customizing Style of RadGrid Edit Items

A developer wanted to customize his “edit” form with a telerik rad grid, and we found it less than simple to change the textboxes and other edit controls to make them more narrow, and/or other customizations.

 

I did some research and came across a few different technique for doing this that I am going to share with everyone.

 

Template Columns

The first option, which is the one he used because it is the easiest, is to convert your columns to “template columns.”  Converting columns changes:

 

<telerik:GridBoundColumn DataField=”EmployeeEmail” DataType=”System.Int32″ HeaderText=”EmployeeEmail”

SortExpression=”EmployeeEmail” UniqueName=”EmployeeEmail” />

 

To this:

 

<telerik:GridTemplateColumn DataField=”EmployeeEmail”

    HeaderText=”EmployeeEmail” SortExpression=”EmployeeEmail”

    UniqueName=”EmployeeEmail”>

    <EditItemTemplate>

        <asp:TextBox ID=”EmployeeEmailTextBox” runat=”server”

            Text=’<%# Bind(“EmployeeEmail”) %>‘></asp:TextBox>

    </EditItemTemplate>

    <ItemTemplate>

        <asp:Label ID=”EmployeeEmailLabel” runat=”server”

            Text=’<%# Eval(“EmployeeEmail”) %>‘></asp:Label>

    </ItemTemplate>

</telerik:GridTemplateColumn>

 

 

As you can see, this gives you control over the actual textbox item that will be displayed when you are in edit mode.

 

But using template columns can also be a bit of a pain, because you losing some of the simplicity that you had before when you simply allowed the rad grid to deal with the details of the display/edit cell items.  This also complicates things when you try to do anything in the ItemDataBound or ItemCreated events on the rad grid.  You can’t just grab the column, you have to dig deeper, looking for the contained child controls to find your actual edit control.

 

ItemDataBound

 

    Protected Sub RadGrid1_ItemDataBound(ByVal sender As Object, ByVal e As Telerik.Web.UI.GridItemEventArgs) Handles RadGrid1.ItemDataBound

        If TypeOf e.Item Is GridEditableItem And e.Item.IsInEditMode Then

            Dim editItem As GridEditableItem = e.Item

            If TypeOf editItem.Item(“EmployeeId”).Controls(0) Is TextBox Then

                CType(editItem.Item(“EmployeeId”).Controls(0), TextBox).Width = 30

            End If

        End If

    End Sub

 

 

In this example, I am setting the width of the EmployeeId textbox to only 30px.

 

 

CreateColumnEditor

 

    Protected Sub RadGrid1_CreateColumnEditor(ByVal sender As Object, ByVal e As Telerik.Web.UI.GridCreateColumnEditorEventArgs) Handles RadGrid1.CreateColumnEditor

        If TypeOf e.ColumnEditor Is GridTextBoxColumnEditor Then

            If e.Column.UniqueName = “FirstName” Then

                CType(e.ColumnEditor, GridTextBoxColumnEditor).TextBoxStyle.Width = 30

                CType(e.ColumnEditor, GridTextBoxColumnEditor).TextBoxControl.Style.Add(“text-align”, “right”)

            End If

        End If

    End Sub

 

 

I believe this event is fired when the grid is creating the edit columns.  You hook into this event, and then modify the textboxstyle in order to change the look of the edit control.

 

 

Defined Column Editor

 

You can achieve the same results as in CreateColumnEditor without writing any code if you drop a GridTextBoxColumnEditor on your page (outside of the RadGrid) like so:

 

<telerik:GridTextBoxColumnEditor ID=”GridTextBoxColumnEditor1″ runat=”server”>

    <TextBoxStyle Width=”50px” />

</telerik:GridTextBoxColumnEditor>

 

And then in your column you specify the ID of the editor you want to use, like this:

 

<telerik:GridBoundColumn DataField=”UserId” DataType=”System.Int32″ HeaderText=”UserId” ColumnEditorID=”GridTextBoxColumnEditor1

    SortExpression=”UserId” UniqueName=”UserId”>

</telerik:GridBoundColumn>

 

 

 

 

CSLA Validation AmbiguousMatchException

Ran into this error today:

failed in property IsDeleted —> System.Reflection.AmbiguousMatchException: Ambiguous match found. at System.RuntimeType.GetPropertyImpl

I knew that we happened to have a property on our class called IsDeleted that shadowed a property in the CSLA base class, but I didn’t think it should be running into this problem.

After tracking down some reference info here http://msdn.microsoft.com/en-us/library/zy0d4103.aspx I found otu that the issue isn’t that we are shadowing, it’s that we are shadowing while at the same time changing the type. 

The documentation seems to indicate that both situations should fail, but in my tests, the only time I got the exception was when my shadowing property had a different type.  In this case, we were using a Nullable(of boolean) while the CSLA element was just a plain old Boolean.

I guess we are going to rename our property to make things easy on ourselves, but seeing as how this is codegenerated, it’s a little more of a pain than you might think.  But, oh well.

Here is some code that produces the error.  If you change the 2nd property type to a string it works ok.

imports Microsoft.VisualBasic
imports System
Imports System.Collections.Generic

public module MyModule
    sub Main
        dim target as new baseclass
        
        dim p as system.Reflection.PropertyInfo  = target.GetType().GetProperty("Prop")
        
        wl( p.GetValue(target, nothing))

        
        RL()
    end sub

    #region "Helper methods"

    sub WL(text as object)
        Console.WriteLine(text)
    end sub

    sub WL(text as object, paramarray args as object())
        Console.WriteLine(text.ToString(), args)
    end sub
        
    sub RL()
        Console.ReadLine()
    end sub
    
    sub Break()
        System.Diagnostics.Debugger.Break()
    end sub

    #end region

end module

public class BaseBaseClass
    public readonly property Prop as string
    get
    return "BaseBaseClass"
    end get
    end property
end class

public class BaseClass
inherits BaseBaseClass

    public readonly property Prop as integer
    get
    return 123
    end get
    end property

end class

Connecting dynamically to mygeneration MyMeta.dbRoot

The amount of time that this cost me is astounding for such a stupid issue.  (And, I’m going to lay the blame fully on whoever wrote the dbRoot object in the MyGeneration project.  Total improper use of properties).

The situation was this: I was trying to dynamically wire up all the plumbing that the mygeneration windows app does for you manually from the ZeusCmd command line.

Doing this would allow me to switch from DB to DB within my code gen application.

Because ZeusCmd runs first (it references my app and passes in what is needed), if you had previously saved a connection in your MyGeneration app, then this connection is used when ZeusCmd runs.  I didn’t want this to happen because as I move from location to location different DB servers are available or not available, so if the last DB server I connected to was at office A, I didn’t want my code gen crashing onload when I am out of said office.

So I ran MyGeneration and changed my connection to be <None> and saved the settings.  Then in my code gen, I tried to manually create the dbRoot object (named meta here) that was previously created for me my ZeusCmd and my saved MyGeneration settings.

Code like this:

meta.Connect("SQL", "Provider=SQLNCLI;Server=cmayt61p;Database=DBName;Trusted_Connection=yes;")

Seemed to do the trick.

However, my codegen started blowing up on my later in the process.  After tracking down the error I find that the mygeneration result column object can’t figure out the .net type that would be the same as a sql server “int”.  Strange, never had these problems before.

A lot of debugging leads me to find that:

meta.DbTarget
meta.Language 

Are both returning “” when before they were returning “SqlClient” and “VB.NET” when I was not dynamically connecting.

So here is where things get bad… anytime I try setting these properties to their values:

meta.DbTarget = "SqlClient"
meta.Language = "VB.NET"

Nothing happens.  The values don’t appear to stick.

Eventually I even start trying to set the LanguageMappingFileName and DbTargetMappingFileName properties as well:

meta.DbTarget = "SqlClient"
meta.Language = "VB.NET"
meta.LanguageMappingFileName = "C:Program FilesMyGeneration13SettingsLanguages.xml"
meta.DbTargetMappingFileName = "C:Program FilesMyGeneration13SettingsDbTargets.xml"

I tried doing these property sets before connecting and after connecting.

I tried returning to having MyGeneration setup the meta object form me (and all these properties have their values) before dynamically connecting (and losing the DbTarget and Language property values).

I even tried creating a brand new dbRoot object, as well as trying to read some hidden values in the IZeusInput object.

But, in the end, it all came down to the this 1 little thing:

You have to set the mapping file properties before you can set the DbTarget and Language properties.

So this will work just fine:

meta.Connect("SQL", "Provider=SQLNCLI;Server=cmayt61p;Database=MSiUpgraded;Trusted_Connection=yes;")
meta.LanguageMappingFileName = "C:Program FilesMyGeneration13SettingsLanguages.xml" meta.DbTargetMappingFileName = "C:Program FilesMyGeneration13SettingsDbTargets.xml" meta.DbTarget = "SqlClient" meta.Language = "VB.NET"

But this won’t:

meta.Connect("SQL", "Provider=SQLNCLI;Server=cmayt61p;Database=MSiUpgraded;Trusted_Connection=yes;")
meta.DbTarget = "SqlClient" meta.Language = "VB.NET" meta.LanguageMappingFileName = "C:Program FilesMyGeneration13SettingsLanguages.xml" meta.DbTargetMappingFileName = "C:Program FilesMyGeneration13SettingsDbTargets.xml"

It just so happened that everywhere that I was testing this stuff in my code, I always set the DbTarget and Language properties first, and they would never stick.

This is not a proper use of properties.  If a property set has conditional logic that will prevent it from setting, there is something wrong here.  At minimum something should happen, an exception being thrown maybe?  The proper thing to do in my mind would be to make DbTarget and Language readonly properties and have functions to set their value, which could return something indicating failure (or throw an exception).

Property gets and sets should do just that, get and set properties.  There shouldn’t be logic in there deciding if and when to actually perform the set that you have coded.  That is the job of a function.

UPDATE: And I discovered as well that you have to connect first before you set any of these values, or none of them will stick.  So you have to 1) connect 2) set the file paths 3) set the language and dbtargets, in that order or nothing works.

CSLA 3.5 Child and Parent Patterns

From this post:
http://forums.lhotka.net/forums/thread/25658.aspx

Child pattern:

[Serializable]
public class Child : BusinessBase<Child>
{
  internal static Child NewChild()
  {
    return DataPortal.CreateChild<Child>();
  }

  internal static Child GetChild()
  {
    return DataPortal.FetchChild<Child>();
  }

  private Child()
  {
    MarkAsChild();
  }

  private void Child_Create()
  {
    // initialize new child here
  }

  private void Child_Fetch()
  {
    // load child data here
  }

  private void Child_Insert()
  {
    // insert child data here
  }

  private void Child_Update()
  {
    // update child data here
  }

  private void Child_DeleteSelf()
  {
    // delete child data here
  }
}

Editable root pattern:

[Serializable]
public class RootParent : BusinessBase<RootParent>
{
  // other class code here ...

  protected override void DataPortal_Insert()
  {
    using (SqlConnection cn = new SqlConnection(...))
    {
      // insert parent data here

      FieldManager.UpdateChildren();
    }
  }

  protected override void DataPortal_Update()
  {
    using (SqlConnection cn = new SqlConnection(...))
    {
      // update parent data here

      FieldManager.UpdateChildren();
    }
  }
}

Editable Root List:

[Serializable]
public class ChildList : BusinessListBase<ChildList, Child>
{
  // other class code here ...

  protected override void DataPortal_Update()
  {
    using (SqlConnection cn = new SqlConnection(...))
    {
      Child_Update();
    }
  }
}

Editable Child List:

[Serializable]
public class ChildList : BusinessListBase<ChildList, Child>
{
  internal ChildList()
  {
    MarkAsChild();
  }

  // other class code here ...
}

If you use the DataPortal methods for creating the child objects (i.e. FetchChild) then you don’t have to bother with the MarkAsChild() stuff.

Turn an Enum into a list in VB.Net with optional CSLA

From time to time you might have an enum that you want to databind to something as if it were a list, so I wrote some classes that turn an Enum into a list that you can databind. 

I created ways to do this in CSLA and also w/o CSLA.  I made the non-CSLA versions 1 work so that you can either use a sub class, or just use generics when defining the type of your list.  You can do the same with the CSLA versions if you want by changing some of the generics, but I didn’t bother.


'*** csla
Dim cslaList As MyTestTypeList = MyTestTypeList.GetList

'*** non-csla with inherited subclass and without
Dim list As New MyTestTypeList2
Dim list2 As New EnumList2(Of MyTestType)


'*** enum we are using
Public Enum MyTestType
something = 1
here = 2
ok = 3
End Enum

'*** csla
<Serializable()> _
Public Class MyTestTypeList
Inherits EnumList(Of mytesttype, MyTestTypeList)

End Class
<Serializable()> _
Public Class EnumList(Of T As Structure, R As EnumList(Of T, R))
Inherits Csla.NameValueListBase(Of String, Integer)

Public Shared Function GetList() As R
Return Csla.DataPortal.Fetch(Of R)()
End Function

Protected Sub New()
' require use of factory method
End Sub

<Csla.RunLocal()> _
Public Overloads Sub DataPortal_Fetch() 'ByVal criteria As Object)
Me.IsReadOnly = False
For Each item As T In [Enum].GetValues(GetType(T))
Dim name As String = [Enum].GetName(GetType(T), item)
Add(New Csla.NameValueListBase(Of String, Integer).NameValuePair(name, [Enum].Parse(GetType(T), name)))
Next
Me.IsReadOnly = True
End Sub
End Class

'*** non-csla
Public Class MyTestTypeList2
Inherits EnumList2(Of MyTestType)

End Class

Public Class EnumList2(Of T As Structure)
Inherits List(Of EnumListItem)

Public Structure EnumListItem
Dim Name As String
Dim Value As Integer
Public Sub New(ByVal name As String, ByVal value As Integer)
Me.Name = name
Me.Value = value
End Sub
End Structure

Public Sub New()
For Each item As T In [Enum].GetValues(GetType(T))
Dim name As String = [Enum].GetName(GetType(T), item)
Add(New EnumListItem(name, [Enum].Parse(GetType(T), name)))
Next
End Sub

End Class

SSRS report fails with vertical text

We ran into an interesting problem today.

A matrix report in SSRS (sqlserver reporting services) 2008 would work just fine when previewing it in VS, and would work fine when viewed directly on the reporting server.  But, if you view it through a asp.net reportviewer control, it would just show the header, a big blank space, and then the footer.

This only happens if you have Vertical text for the row headers.  Remove that and everything is OK.

I began editing the generated CSS/HTML and found that the cells had a number of styles applied, but specifically the one that seemed to break everything was:

WIDTH:100%;

Remove that and the page rendered as expected.

We tried changing a number of parameters to get it to remove the width style but no luck.

We have something that generates images with GDI to do it now, but it’s not ideal.

Getting error reports when a SQL Reporting Subscription Fails

UPDATE 2:

Either this never worked in the first place as I wanted, or MS has changed how they are doing things in SSRS 2008.

I now don’t see any of the errors in the tables I had been looking in, and in fact, the errors don’t show up in any of their logs either.  This is crap.

If you are like me, you don’t like the fact that the first time you realize that a data driven subscriptions in SQL Server Reporting Services has been failing is when someone comes up to you and says “Hey, I did XYZ and I never saw the server kick off an email.” 

Really?  Let me check…. oh, looks like it has been broken for god knows how long.  What the heck?

Well, I wrote a script to notify you when there are errors on the report server.

First, you need to setup Database Mail.  Expand Management, and pick Database Mail.  For my script I used the name “Email Profile” for the “Email Profile” get it?

Then create a trigger on the ExecutionLogStorage table like this:

USE [ReportServer]
GO
/****** Object:  Trigger [dbo].[ExecutionLogStorage_Insert]    Script Date: 05/13/2009 10:20:44 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[ExecutionLogStorage_Insert]
ON [dbo].[ExecutionLogStorage]
AFTER INSERT
AS
BEGIN
    DECLARE @sStatus AS NVARCHAR(32)
    SET @sStatus = (SELECT Status FROM inserted)
    
    IF(@sStatus <> 'rsSuccess')
    BEGIN
        DECLARE @sReportName AS NVARCHAR(425)
        DECLARE @sPath AS NVARCHAR(425)
        DECLARE @ReportId AS UNIQUEIDENTIFIER
        DECLARE @sUserName AS NVARCHAR(260)
        DECLARE @sParameters AS NVARCHAR(4000)
        DECLARE @dTimeEnd AS DATETIME
        DECLARE @iTimeProcessing as int
        
        
        SELECT
          @sReportName = Name,
          @sPath =PATH,
          @ReportId = ReportId,
          @sUserName = username,
          @sParameters = (select CAST(ISNULL(ELS.Parameters,'') AS NVARCHAR(4000)) from ExecutionLogStorage ELS Where LogEntryId = Inserted.LogEntryId),
          @dTimeEnd = TimeEnd,
          @iTimeProcessing = ISNULL(TimeProcessing,0)
        FROM inserted INNER JOIN [Catalog]
        ON inserted.ReportId = CATALOG.[ItemID]
        
        DECLARE @sBody VARCHAR(8000)
        SET @sBody = 'Error with SQL Report '
                    + CAST(@sReportName AS VARCHAR(100))
                    + ' at path '
                    + CAST (@sPath AS VARCHAR(250))
                    + ' with ReportId '
                    + CAST(@ReportId AS VARCHAR(100))
                    + ' and username '
                    + CAST(@sUserName AS VARCHAR(100))
                    + ' Parameters '
                    + CAST(@sParameters  AS VARCHAR(5000))
                    + ' End time '
                    + CAST(@dTimeEnd AS VARCHAR(50))
                    + ' Status '
                    + CAST(@sStatus AS VARCHAR(50))
                    + ' Time Processing '
                    + CAST(@iTimeProcessing AS VARCHAR(50));
        
        DECLARE @sSubject VARCHAR(500)
        SET @sSubject = 'Error With Report ' + @sReportName
        
        EXEC msdb.dbo.sp_send_dbmail
         @profile_name = 'Email Profile',
         @recipients = 'email@address.com',
         @body =  @sBody  ,
         @subject = @sSubject;

    END
    
END

Presto!

 

UPDATE: Added logic to get the status and parameters.

 

ASP.NET Apps Recycling Because of FCN Issues

I have written before about some of the problems that a frequently recycling asp.net application can cause, espically if you are using session for anything.

ASP.NET Process Recycling Too Often

But I ran into a situation where the recycle was caused by the application itself for a client of mine.  I had bought and customized a asp.net application that allows my client to give THEIR clients access to a section of their site where they can upload/download/manage files very nicely.  But after moving to a new hosting environment, users kept losing their login sessions very quickly.

After some research, I found out that session was being used to track if the user was logged in, and session was being lost very quickly because the application was recycling.

I used the following code to help diagnose the cause for the application restarting:

(this goes in Application_End)

Dim runtime As HttpRuntime = GetType(System.Web.HttpRuntime).InvokeMember("_theRuntime", _
    BindingFlags.NonPublic Or _
     BindingFlags.Static Or _
    BindingFlags.GetField, _
    Nothing, Nothing, Nothing)

If runtime Is Nothing Then
    logger.Error("The application is closing at " & Now.ToShortDateString & " " & Now.ToLongTimeString)
    Return
End If

Dim shutDownMessage As String = runtime.GetType().InvokeMember("_shutDownMessage", BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.GetField, Nothing, runtime, Nothing)
'If shutDownMessage = "HostingEnvironment caused shutdown" Then
'    '*** this is normal, you can include this commented out section or not
'    Return
'End If
Dim shutDownStack As String = runtime.GetType().InvokeMember("_shutDownStack", BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.GetField, Nothing, runtime, Nothing)
'*** email this error
logger.Error(String.Format("The application is closing at " & Now.ToShortDateString & " " & Now.ToLongTimeString & " " & vbCrLf & vbCrLf & "_shutDownMessage={0}" & vbCrLf & vbCrLf & "_shutDownStack={1}", shutDownMessage, shutDownStack))


Dim log As New EventLog
log.Source = ".NET Runtime"
log.WriteEntry(String.Format(vbCrLf & vbCrLf & "_shutDownMessage={0}" & vbCrLf & vbCrLf & "_shutDownStack={1}", shutDownMessage, shutDownStack), EventLogEntryType.Error)

The cause was:

Directory rename change notification for 'APP PATH HERE.
Clients dir change or directory rename
HostingEnvironment caused shutdown

Because this app was now hosted with a 3rd party, I didn’t have control over the environment to go see if there was an AV scanner or backup manager running that was touching the files.

However, I because I was able to reproduce the error in my dev environment, I was confident I could rule out those causes.

I eventually found that the problem was 2 fold:

1) The application allows the user to upload files/create folders that reside in subfolders of the application.  The app could think these changes require a recycle.

2) The application creates a temp folder for the user for each session under the root as well.  Changing folder structure can cause a recycle.

So what can be done?

Well, I adapted some code from a few places to turn off the FCN (File change notifications) for sub directories of the website.  This isn’t easy to do if you don’t have something to go off of, becaues you basically have to hijack your way into private methods on classes in the .net framework, using reflection to call methods that you shouldn’t be accessing, in order to turn off specific behavior.

Here are the methods I created to help me do this.  I also have some log4net code in here, so you’ll have to pull that out if you want to use this.

Private Sub TurnOffDirectoryMonitoring()
    Try
        Dim p As System.Reflection.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 asdf As System.Reflection.MethodInfo() = monitor.GetType.GetMethods()

        Dim propIsMonitoring As System.Reflection.MethodInfo = monitor.GetType.GetMethod("IsMonitoring", System.Reflection.BindingFlags.Instance Or System.Reflection.BindingFlags.NonPublic)
        Dim bIsMonitoring As Boolean = propIsMonitoring.Invoke(monitor, Nothing)
        Dim logger As log4net.ILog = log4net.LogManager.GetLogger("File")
        logger.Info("Directory monitoring IsMonitoring was " & bIsMonitoring)


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

        Dim objArray() As Object = {}
        m.Invoke(monitor, objArray)

        logger.Info("Directory monitoring IsMonitoring after change is " & bIsMonitoring)

    Catch ex As Exception
        Dim logger As log4net.ILog = log4net.LogManager.GetLogger("File")
        logger.Error(ex)
    End Try
End Sub

Private Sub CheckDirectoryMonitoring()
    Try
        Dim p As System.Reflection.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 asdf As System.Reflection.MethodInfo() = monitor.GetType.GetMethods()

        Dim propIsMonitoring As System.Reflection.MethodInfo = monitor.GetType.GetMethod("IsMonitoring", System.Reflection.BindingFlags.Instance Or System.Reflection.BindingFlags.NonPublic)
        Dim bIsMonitoring As Boolean = propIsMonitoring.Invoke(monitor, Nothing)
        Dim logger As log4net.ILog = log4net.LogManager.GetLogger("File")
        logger.Info("In CheckDirectoryMonitoring, Directory monitoring IsMonitoring is " & bIsMonitoring)
    Catch ex As Exception
        Dim logger As log4net.ILog = log4net.LogManager.GetLogger("File")
        logger.Error(ex)
    End Try
End Sub

Private Sub CheckFCNMode()
    Try
        Dim p As System.Reflection.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("_FCNMode", BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.IgnoreCase)

        Dim iFCNMode As Integer = f.GetValue(o)
        Dim logger As log4net.ILog = log4net.LogManager.GetLogger("File")
        logger.Info("In CheckFCNMode, FCNMode is " & iFCNMode)
    Catch ex As Exception
        Dim logger As log4net.ILog = log4net.LogManager.GetLogger("File")
        logger.Error(ex)
    End Try
End Sub

These methods are not refactored or “best practice” at all, there is a lot of copy/paste code in here, but you’ll get the idea of what I’m doing.

You can call these methods from the beginning on Application_Start. 

1 thing to note.  I found that my code that checks to make sure that logging was turned off, doesn’t seem to report the right value the first time I check it.  But by the time the first session starts, it has indeed stopped monitoring.

Just try calling these methods from a few places after application_start and you can see what happens.