none
Type initializer Exception

    Question

  • Hello everyone,
     
                 I was wondering if someone can point me to the correct direction regarding a problem I have been having which
                 is driving me crazy.

                 Here is the short overview:
                 I have an ASP.NET 2.0 application. The problem is that when people are trying to login using my loggin page,
                 if I call one method of my class it throws a "Type initializer for 'myClass' threw an exception".
                 This started happening randomly a month ago, sometimes on x32bit machines and sometimes on x64bit
                 machines, sometimes on machines with .NET2.0 SP1 and sometimes on machines that dont have .NET2.0 SP1.
                 Some of these machines have automatic windows updates on and some of them do not.
     
       Here is the detailed description:
                 
                    Background:
              We have our security project, lets call it 'SS', which takes care of session logging, users, etc etc. We also   
              use an object mapper, lets call it TypePersistor, to map object from database. This mapper uses a class
              called DbFactory, which has a static, but with [ThreadStatic] attribute, property "local", which holds the
              current database connection information. This information gets initialized when the program starts, and up to
              the point of the exception it is correct.

                    Scenario:
              User starts the application, goes to the login page and enters his l/p and clicks logon. I put a break point 
              right on the button click. I start stepping through the code, we initialize our DbFactory, we succesfully
              use TypePersistor to read from the database the user's group information. Then we go to a piece of code
              that looks something like this:

              long sessionID = SSSession.findSession(loginData.User.UserID, loginData.User.CorpID,                  
              (ApplicationCodes)(license.AppID));

    As soon as it hits the statis findSession() method it throws the Type Initializer exception. Here is my
    SSSession class:

    Code Snippet

    [DbRecord("SS_Session", IsView=false, Updatable=true)]
        public class SSSession {

            public static TypePersistor persistor = new 

                                 TypePersistor(typeof(SSSession));

            [DbField("ID"), DbSequence, DbPrimaryKey]
            public readonly long id = CommonCheck.longNotEntered;

            [DbField("USERID")]
            public readonly long userID;

            [DbField("APPL")]
            public readonly ApplicationCodes appl;

            [DbField("STARTTM")]
            public DateTime startTM;

            [DbField("CORPID")]
            public readonly long corpID;

            private SSSession(long userID, long corpID, ApplicationCodes appl) {
                this.userID = userID;
                this.appl = appl;
                this.corpID = corpID;
                startTM = DateTime.Now;
            }

            public static long startSession(long userID, long corpID,

                              ApplicationCodes appl) {
                long sessionID = findSession(userID, corpID, appl);
                if (!CommonCheck.entered(sessionID)) {
                    SSSession s = new SSSession(userID, corpID, appl);
                    SSSession.persistor.Save(s, DbSaveActions.Insert);
                    return s.id;
                } else {               

                    string extraParams = "public static long startSession.";
                    SessionKillLog skl;
                    try {
                        extraParams += "Current Session Count: " + Convert.ToString(SSSession.currentSessionCount(Login.Current.User.CorpID));
                        skl = new SessionKillLog(Login.Current, extraParams);
                    }
                    catch { skl = new SessionKillLog(null, extraParams); }
                    new TypePersistor(typeof(SessionKillLog)).Save(skl);                               
                    endSession(sessionID);
                    return startSession(userID, corpID, appl);
                }
            }

            public static void endSession(long sessionID) {

                DBI.LockManager.removeBySessionID(sessionID);
                SSSession.persistor.Delete(sessionID);
            }

            public static long findSession(long userID, long corpID,

                ApplicationCodes appl) {
                DBI.DbComplexFilter filter = new DBI.DbComplexFilter();
                filter.Add("USERID", DBI.CompareOp.Equals, userID);
                filter.Add("CORPID", DBI.CompareOp.Equals, corpID);
                filter.Add("APPL", DBI.CompareOp.Equals,

                 TypePersistor.DbValueOf(appl));
                SSSession s = SSSession.persistor.FindFirst(filter) as SSSession;
                if (s != null) return s.id;
                return CommonCheck.longNotEntered;
            }

            public static int currentSessionCount(long corpID,

                                           ApplicationCodes appl) {
                DBI.DbComplexFilter filter = new DBI.DbComplexFilter();
                filter.Add("CORPID", DBI.CompareOp.Equals, corpID);
                filter.Add("APPL", DBI.CompareOp.Equals,

                TypePersistor.DbValueOf(appl));
                return (int)(SSSession.persistor.Count(filter));
            }

            public static int currentSessionCount(long corpID) {
                return (int)(SSSession.persistor.Count(
                    new DBI.DbSimpleFilter("CORPID", DBI.CompareOp.Equals,

                    corpID)));
            }

            public static SSSession load(long sessionID) {
                return persistor.Load(sessionID) as SSSession;
            }

            public static void cleanupSessions() {
                persistor.DeleteWhere(new DBI.DbSimpleFilter("STARTTM",

                DBI.CompareOp.EqualsOrLess, DateTime.Now.AddDays(-1.0)));
            }

            public static void cleanupSession(ExceptionsBag bag, long id) {
                int bagCount = bag.err.count;
                if (locksExist(id)) {
                    bag.err.add(new ExceptionsBag.Item(LocalErrors.SS_LocksExist,

                    UserProfile.load(SSSession.load(id).userID).Name));
                }
                if (bagCount != bag.err.count) { return; }
                persistor.DeleteWhere(new DBI.DbSimpleFilter("ID",          

                DBI.CompareOp.Equals, id));
            }
           
            public static bool locksExist(long sessionID) {
                SSSession session = SSSession.load(sessionID) as SSSession;
                if (session != null) {

                    return            
                   (DBI.LockManager.getUserLocks(session.userID).Count > 0);

                }
                else {
                    return false;
                }
            }

            public static void resetUserSessions(long userID) {

    persistor.DeleteWhere(new DBI.DbSimpleFilter("USERID", DBI.CompareOp.Equals, userID));

            }
    }


    We use a lot of our own mapping object, such as filters (DbComplexFilter, etc etc etc) and they have worked correctly for years, so the problem is not with them.

    The exception I get has the has the message of "Type initializer for 'SSSession' threw exception". If i look at the innerException, I get a message saying that 'DbFactory is not setup for current thread'. So basically before calling SSSession.findSession(), we successfully read data from the database using the same absolute funtionality (DbFactory and TypePersistor), but when we call findSession() the DbFactory._local
    is null.

    Here is part of out DbFactory class. "local" is the property that throw the error.

    Code Snippet
        public class DbFactory : IDisposable {

            private Clients.DbClient _client;
            private Syntax.DbSyntax _syntax;
            private IDbConnection _conn;
            private IDbTransaction _trans;

            private int _commandTimeout;

            [ThreadStatic] private static DbFactory _local;

            private static DbFactory local {
                get {
                    if (_local == null)
                        throw new ApplicationException(
                            typeof(DbFactory).Name + " is not set up for current
                              thread");

                    return _local;
                }
            }



    From what I understand, VS2005 cannot step into a different thread then it started debugging on, so it looks like at the point where i am trying to call SSSession.findSession() it jumps into another thread and does what it does. So if this is correct, why would it jump into a second thread all of a sudden? If this is not correct, why can't i step in and break into the method?

    When debugging this issue, I skipped over the code that calls findSession(), and went into code which calls other methods of the same class. The same problem occurs.

    One of the solutions I have been looking into, is if the class does not get initialized correctly. If for some reason, one of the properties of SSSession is throwing an error upon initialization. This seems unlikely because the only property that is not a simple assignment is the TypePersistor and that is used everywhere, without any problems. Also absolutely nothing changed for the properties/constructor for this class for a long time, even before this problem started happening.

    So here are some of the solutions which i found which would fix the problem. Sometimes one of these works,
    sometimes you have to use a combination:

    1). Rebuild the SS project, (which includes this class SSSession).
    2). Restart IIS
    3). Clear ASP.NET cache. (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files)

    My IIS on my computer is 5.1, but this problem also happens on version 6.

    Could someone please advice on what should I do, or how can I find more information on what is causing it?
    If you need more explanation/code please let me know.


    Thank you very much,
    Mike

    Friday, March 28, 2008 2:46 PM

Answers

  • A type initializer is pretty much a static constructor for a class.  The first time the classes static/instace members are accessed the static constructor gets called.  I did not see one in your code there.  For myClass the static constructor would look like the snippet below.  Check your code and see if anything is happening in a static constructor that could be causing problems.


    static myClass()
    {
    // Init Type
    }
    Monday, March 31, 2008 6:58 AM