locked
What happens on Website restart in IIS 7.5 RRS feed

  • Question

  • User769474054 posted

    Hi,

    I have a webapp that throws a 500 Internal Server Error. but when I restart the website in IIS , it works as expected. I am using Caching in my web App with the below setting and this is referenced on website loading. 

     if (HttpContext.Current.Cache["ProjectConfig"] == null)
                            {
                                HttpContext.Current.Cache.Insert("ProjectConfig", TrackerMaster.InitTFS(), null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(2));
                                TrackerDB.DBConnection = ConfigurationManager.ConnectionStrings["DBConnStr"].ConnectionString;
                                
                            }

    I am not sure how to debug whats causing the issue. Will the cache be cleared and re created on website restart? any pointers on how does a site restart fix the issue?

    Tuesday, October 9, 2018 11:17 PM

Answers

  • User283571144 posted

    Hi pavanlalit,

    As far as I know,  the HttpContext.Current is null in the CacheExpiredHandler.So you will get none object error.

    I suggest you could try to use the "HttpRuntime.Cache.Add" instead of the "HttpContext.Current.Cache.Insert".

    Then it will work well.

    More details, you could refer to below codes:

    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Web;
    using System.Web.Caching;
    using System.Web.Http;
    
    namespace WebApiNormall
    {
        public static class WebApiConfig
        {
            private static Object thisLock = new Object();
            static CacheItemRemovedCallback onCacheExpire = null;
            public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
                MakeOrGetCache();
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
            }
            private static void CacheExpiredHandler(string key, object value, CacheItemRemovedReason reason)
            {
    
               HttpRuntime.Cache.Add("ProjectConfig", "test", null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1), CacheItemPriority.Default, onCacheExpire);
                 //HttpContext.Current.Cache.Insert("ProjectConfig", "test", null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1), CacheItemPriority.Default, onCacheExpire);
    
    
    
                //TrackerDB.DBConnection = ConfigurationManager.ConnectionStrings["DBConnStr"].ConnectionString;
            }
    
            private static void MakeOrGetCache()
            {
                try
                {
                    if (HttpContext.Current.Cache["ProjectConfig"] == null)
                    {
                        lock (thisLock)
                        {
                            if (HttpContext.Current.Cache["ProjectConfig"] == null)
                            {
                                onCacheExpire = new CacheItemRemovedCallback(CacheExpiredHandler);
                                HttpContext.Current.Cache.Insert("ProjectConfig", "test", null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1), CacheItemPriority.Default, onCacheExpire);
                                //TrackerDB.DBConnection = ConfigurationManager.ConnectionStrings["DBConnStr"].ConnectionString;
    
                            }
                        }
                    }
    
                    //if (HttpContext.Current.Application["MailCSS"] == null)
                    //{
                    //    lock (thisLock)
                    //    {
                    //        if (HttpContext.Current.Application["MailCSS"] == null)
                    //        {
                    //            using (StreamReader textReader = File.OpenText(System.Web.Hosting.HostingEnvironment.MapPath("~/Mail.css")))
                    //            {
                    //                HttpContext.Current.Application["MailCSS"] = textReader.ReadToEnd();
                    //            }
                    //        }
                    //    }
                    //}
                }
                catch (Exception ex) { Debug.WriteLine("Error settting up cache " + ex.Message); }
            }
        }
    }
    

    Best Regards,

    Brando

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, October 11, 2018 7:29 AM

All replies

  • User409696431 posted

    Since the 500 error is a very general error, all you know is that something bad happened, and that restarting cleared it.  Yes, recycling an application pool or resetting IIS clears the IIS cache, but that doesn't mean that caching is the source of your problem, since a lot of errors are cleared by recycling the application pool or resetting IIS.

    If you have access to the IIS logs, you can get more information on the cause of the errors.
    You could also (temporarily) set the site to show detailed errors in the browser and see if that provides useful information.

    Wednesday, October 10, 2018 1:20 AM
  • User1120430333 posted

    The 500 error means an unhandled .NET exception was thrown, the Web server swallowed it and threw the 500 error. That is what is happening. You don't have any global exception handling in the solution to catch unhandled exceptions and log the exception to a logger so you can see the exception. 

    Wednesday, October 10, 2018 3:07 AM
  • User769474054 posted

    Hi Kathy,

    The 500 sub status code is 0 so its 500.0 error. I tried putting some catch block and figured out that the application failing when retrieving the projects info from the Cache as "Object reference not set to an instance of the object" 

    literally below.

    Dictionary<string, DTDProjectInfo> config = HttpContext.Current.Cache["ProjectConfig"] as Dictionary<string, DTDProjectInfo>;
                    List<string> projects = config.Keys.ToList<string>();
                    return projects.OrderBy(o => o).ToList();

    So, the natural question is to check for null if cache is empty. But I was wondering how different in returning null here vs a fresh restart of the website because, on both ends, it would have no cache(null basically) which should ideally create the cache. but on a website restart it creates the cache but in the above code, it throws error. 

    I am setting the Cache in the WebAPIConfig.cs file of the API here

    public static void Register(HttpConfiguration config)
            {
                
                MakeOrGetCache();
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "{controller}/{action}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
            }
    
            private static void MakeOrGetCache()
            {
                try 
                {
                    if (HttpContext.Current.Cache["ProjectConfig"] == null)
                    {
                        lock (thisLock)
                        {
                            if (HttpContext.Current.Cache["ProjectConfig"] == null)
                            {
                                HttpContext.Current.Cache.Insert("ProjectConfig", TrackerMaster.InitTFS(), null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(2));
                                TrackerDB.DBConnection = ConfigurationManager.ConnectionStrings["DBConnStr"].ConnectionString;
                                
                            }
                        }
                    }

    why would it throw the error after the app has started and when the cache returns null vs on fresh start thats  my question. how do I fix this and make cache when I read the projects. Any pointers please?

    Wednesday, October 10, 2018 5:54 PM
  • User475983607 posted

    pavanlalit

    why would it throw the error after the app has started and when the cache returns null vs on fresh start thats  my question. how do I fix this and make cache when I read the projects. Any pointers please?

    You have a bug in the code base and need to troubleshoot to find and fix the bug.

    The MakeOrGetCache only sets the cache once when the app starts and sets the expiration to 2 hours.  The cache is coded to expire if there is no activity for 2 hours.  There is no indication if a cache expiration is handled in the code base.  I assume this situation is not handled since the cache is null during run-time. 

    I recommend asking a peer to review your code.

    Wednesday, October 10, 2018 6:59 PM
  • User769474054 posted

    Hi mgebhard,

    Yes, the cache expires after 2 hrs of inactivity, but when any user accesses the application after the cache is expired, the cache should be re-created right? if, thats not the case, any user accesses the page after the cache expires, the caches should be created in the code itself correct?

    can you please elaborate on handling the cache expiration? if possibel give an example of what you mean and how to handle it?

    Wednesday, October 10, 2018 8:02 PM
  • User475983607 posted

    pavanlalit

    Yes, the cache expires after 2 hrs of inactivity, but when any user accesses the application after the cache is expired, the cache should be re-created right? if, thats not the case, any user accesses the page after the cache expires, the caches should be created in the code itself correct?

    Yes, if the cache has expired the cache must be reloaded before it can be accessed.  The code you've shown populates the cache when the application starts.  There is no indication whatsoever that the code base is re-populating an expired cache.  You are the only one that can verify this as you have the code.

    pavanlalit

    can you please elaborate on handling the cache expiration? if possibel give an example of what you mean and how to handle it?

    You've already posted this type of code.  I recommend refactoring the code into a class that handles adding and removing cache items and re-populating cache.   You can also reload the cache by taking advantage of the CacheItemRemovedCallback.

    Otherwise, you'll end up duplicating the MakeOrGetCache() code everywhere cache is accessed.

    if (HttpContext.Current.Cache["ProjectConfig"] == null)
    {
    	//Populate cache
    }

    The cache documentation covers these feature.

    https://docs.microsoft.com/en-us/dotnet/api/system.web.caching.cache?view=netframework-4.7.2

    Wednesday, October 10, 2018 8:26 PM
  • User769474054 posted

    Hi mgebhard,

    Thanks for the pointer. I went ahead and implemented the following in my webAPIconfig.cs. I used the `CacheItemRemoveCallback` property 

     public static class WebApiConfig
        {
            private static Object thisLock = new Object();
            static CacheItemRemovedCallback onCacheExpire = null;
            public static void Register(HttpConfiguration config)
            {
                MakeOrGetCache();
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "{controller}/{action}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
            }
    
            private static void CacheExpiredHandler(string key, object value, CacheItemRemovedReason reason)
            {
                HttpContext.Current.Cache.Insert("ProjectConfig", TrackerMaster.InitTFS(), null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(2), CacheItemPriority.Default, onCacheExpire);
                TrackerDB.DBConnection = ConfigurationManager.ConnectionStrings["DBConnStr"].ConnectionString;
            }
    
            private static void MakeOrGetCache()
            {
                try 
                {
                    if (HttpContext.Current.Cache["ProjectConfig"] == null)
                    {
                        lock (thisLock)
                        {
                            if (HttpContext.Current.Cache["ProjectConfig"] == null)
                            {
                                onCacheExpire = new CacheItemRemovedCallback(CacheExpiredHandler);
                                HttpContext.Current.Cache.Insert("ProjectConfig", TrackerMaster.InitTFS(), null, Cache.NoAbsoluteExpiration, TimeSpan.FromHours(2), CacheItemPriority.Default, onCacheExpire);
                                TrackerDB.DBConnection = ConfigurationManager.ConnectionStrings["DBConnStr"].ConnectionString;
                               
                            }
                        }
                    }
    
                    if (HttpContext.Current.Application["MailCSS"] == null)
                    {
                        lock (thisLock)
                        {
                            if (HttpContext.Current.Application["MailCSS"] == null)
                            {
                                using (StreamReader textReader = File.OpenText(System.Web.Hosting.HostingEnvironment.MapPath("~/Mail.css")))
                                {
                                    HttpContext.Current.Application["MailCSS"] = textReader.ReadToEnd();
                                }
                            }
                        }
                    }
                }
                catch (Exception ex) { new TrackerMailer().NotifyAdminOfError("Error settting up cache " + ex.Message); }
            }
           
        }

    I deployed this and waiting to see if it works.I will get to know soon though.Meanwhile, please let me know your comments on it.

    Wednesday, October 10, 2018 9:01 PM
  • User283571144 posted

    Hi pavanlalit,

    As far as I know,  the HttpContext.Current is null in the CacheExpiredHandler.So you will get none object error.

    I suggest you could try to use the "HttpRuntime.Cache.Add" instead of the "HttpContext.Current.Cache.Insert".

    Then it will work well.

    More details, you could refer to below codes:

    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Web;
    using System.Web.Caching;
    using System.Web.Http;
    
    namespace WebApiNormall
    {
        public static class WebApiConfig
        {
            private static Object thisLock = new Object();
            static CacheItemRemovedCallback onCacheExpire = null;
            public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
                MakeOrGetCache();
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
            }
            private static void CacheExpiredHandler(string key, object value, CacheItemRemovedReason reason)
            {
    
               HttpRuntime.Cache.Add("ProjectConfig", "test", null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1), CacheItemPriority.Default, onCacheExpire);
                 //HttpContext.Current.Cache.Insert("ProjectConfig", "test", null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1), CacheItemPriority.Default, onCacheExpire);
    
    
    
                //TrackerDB.DBConnection = ConfigurationManager.ConnectionStrings["DBConnStr"].ConnectionString;
            }
    
            private static void MakeOrGetCache()
            {
                try
                {
                    if (HttpContext.Current.Cache["ProjectConfig"] == null)
                    {
                        lock (thisLock)
                        {
                            if (HttpContext.Current.Cache["ProjectConfig"] == null)
                            {
                                onCacheExpire = new CacheItemRemovedCallback(CacheExpiredHandler);
                                HttpContext.Current.Cache.Insert("ProjectConfig", "test", null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1), CacheItemPriority.Default, onCacheExpire);
                                //TrackerDB.DBConnection = ConfigurationManager.ConnectionStrings["DBConnStr"].ConnectionString;
    
                            }
                        }
                    }
    
                    //if (HttpContext.Current.Application["MailCSS"] == null)
                    //{
                    //    lock (thisLock)
                    //    {
                    //        if (HttpContext.Current.Application["MailCSS"] == null)
                    //        {
                    //            using (StreamReader textReader = File.OpenText(System.Web.Hosting.HostingEnvironment.MapPath("~/Mail.css")))
                    //            {
                    //                HttpContext.Current.Application["MailCSS"] = textReader.ReadToEnd();
                    //            }
                    //        }
                    //    }
                    //}
                }
                catch (Exception ex) { Debug.WriteLine("Error settting up cache " + ex.Message); }
            }
        }
    }
    

    Best Regards,

    Brando

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, October 11, 2018 7:29 AM