IIS Set Expiration Dates adds the expiration header only to static content

12 Steps To Faster Web Pages With Visual Round Trip Analyzer recommends (among others useful suggestions) to  Set Expiration Dates – follow Using Content Expiration (IIS 6.0), .
 
 
Finally the post  IIS Content expiration header and ASP.NET cleared my concerns:
IIS is smart enough to add the expiration header only to static content.
It automatically adds the header to images and css files, without touching
the aspx pages.

 But, like the author of the post, I am also wonder , how does IIS determine what extensions fall under static content? Is
there a way to modify this list?
Related: a few useful advices from Best practices for creating websites in IIS 6.0  
Custom Headers:
Remove the X-Powered-By: ASP.NET header. You really don’t need it unless you want to attach Visual Studio Remote Debugger to your IIS. Otherwise, it’s just sending 21 bytes on every response.
  • Add “From” header and set the server name. I do this on each webserver and specify different names on each box. It’s handy to see from which servers requests are being served. When you are trying to troubleshoot load balancing issues, it comes handy to see if a particular server is sending requests. 
  • Also turn on IIS 6.0 gzip compression.  Note that enabling in IIS 6.0 in the Properties, Service tab is not good enough.
  • More links:
     
    Advertisements

    Helper functions to find pattern contaned in string from pattern List

    Below are a few helper functions for List<string> generic class.

    They could be modified to be extension methods.

     

       //See also StringArrayHelper.cs, CollectionsHelper.cs

            public static class ListOfStringsHelper

            {

                public static bool StringContainsAnyFromList(List<string> patternsList, string sMsg)

                {

                    bool bFound = patternsList.Exists(

                        delegate(string pattern)

                        {

                            return sMsg.Contains(pattern);

                        }

                        );

                    return bFound;

                }

                public static string FindFirstListItemContainedInString(List<string> patternsList, string sMsg)

                {

                    string sFound = patternsList.Find(

                        delegate(string pattern)

                        {

                            return sMsg.Contains(pattern);

                        }

                       );

                    return sFound;

                }

            }

     

    Se also My StringHelper class 

    ToString function for Generic List

    Below is the method to output Generic list of objects as string.

     

    UPDATE: I’ve replaced my original function with the code suggested by James Curran (see his comment below).

     

        public static string ToString<T>(IEnumerable<T> messages, string sComment)
        {
            StringBuilder sRet = new StringBuilder(sComment);
            if (messages != null)
            {
                foreach (T msg in messages)
                {
                    sRet.AppendLine(msg.ToString());
                }
            }
            return sRet.ToString();
        }

            /// <summary>

            /// 
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="messages"></param>
            /// <param name="separator"></param>
            /// <param name="sComment"></param>
            /// <returns></returns>
            /// See also http://www.codemeit.com/linq/c-array-delimited-tostring.html
            public static string ToString<T>(this IEnumerable<T> messages, string separator, string sComment)
            {
                if (messages == null)
                    throw new ArgumentException("source can not be null.");
                StringBuilder sb = new StringBuilder(sComment);
                if (string.IsNullOrEmpty(separator))
                {
                    separator = Environment.NewLine;
                }
                if (messages != null)
                {
                    foreach (T msg in messages)
                    {
                        if (msg != null)         
    {
    sb.Append(msg.ToString());
    sb.Append(separator);
    
         }  }
                }
                string sRet = StringHelper.TrimEnd(sb.ToString(), separator);
                return sRet;
            }
     

    Similar function implemented as an extension method described in post:

    Separator Delimited ToString for Array, List, Dictionary, Generic IEnumerable

     

    Access to Relative To Application Root File

    Sometimes you have a file relative to the root of application, that you want to read from your code. However when your code is build on development machine, the binary files are located in “bindebug”,”binrelease” or just “bin”(for VB or Web projects). And you need to make copy of files relative to bin/debug folder.

    The function below helps to find the file, even if it was not copied to bin subfolder. (Should I name it ResolvePath smilar to Page.ResolveUrl?)

     

    Note, that in most cases Visual Studio file “Copy to Output Directory” Property will be sufficient to achieve the same result.

            /// <summary>

            /// Function to find file in a root, even if bin directory is passed, which actually can be @”bindebug”,@”binrelease” or just @”bin”

            /// </summary>

            /// <param name=”sBinDirectory”></param>

            /// <param name=”sRelativeFilePath”></param>

            /// <param name=”bThrowExceptionIfNotExist”></param>

            /// <returns></returns>

            public static string GetPathForRelativeToRootFile(string sBinDirectory, string sRelativeFilePath, bool bThrowExceptionIfNotExist)

            {

                string sOriginalFullName = Path.Combine(sBinDirectory, sRelativeFilePath);

                string sFullName = sOriginalFullName;

                bool bExists = false;

                //Check if templateFileDirectory exists, if not and is not debug version, going up two levels to find template folder

                if (!File.Exists(sOriginalFullName))

                {

                    sBinDirectory = StringHelper.TrimEnd(sBinDirectory, @””).ToLower();

                    //string sNewDir = “”;

                    string sEndBin = @”bindebug”;

                    bExists = IsFileInParentDirExist(sBinDirectory, sEndBin, sRelativeFilePath, ref sFullName);

                    if (bExists == false)

                    {

                        sEndBin = @”binrelease”;

                        bExists = IsFileInParentDirExist(sBinDirectory, sEndBin, sRelativeFilePath, ref sFullName);

                    }

                    if (bExists == false)

                    {

                        sEndBin = @”bin”;

                        bExists = IsFileInParentDirExist(sBinDirectory, sEndBin, sRelativeFilePath, ref sFullName);

                    }

                }

                else

                {

                    bExists = true;

                }

                if (bExists == false)

                {

                    if (bThrowExceptionIfNotExist == true)

                    {

                        throw new FileNotFoundException(“File not found in directory “ + sBinDirectory, sRelativeFilePath);

                    }

                    else

                    {

                        return sOriginalFullName;

     

                    }

                }

                return sFullName;

            }

            //        ///

            /// <summary>

            /// helper method to be called from GetPathForRelativeToRootFile with different sEndBin parameters

            /// </summary>

            /// <param name=”sBinDirectory”></param>

            /// <param name=”sEndBin”></param>

            /// <param name=”sRelativeFilePath”></param>

            /// <param name=”sFullName”></param>

            /// <returns></returns>

            private static bool IsFileInParentDirExist(string sBinDirectory, string sEndBin, string sRelativeFilePath, ref string sFullName)

            {

                bool bExists = false;

                if (sBinDirectory.EndsWith(sEndBin))

                {

                    string sNewDir = StringHelper.TrimEnd(sBinDirectory, sEndBin);

                    sFullName = Path.Combine(sNewDir, sRelativeFilePath);

                    if (File.Exists(sFullName))

                    {

                        bExists = true;

                    }

                }

                return bExists;

            }

    Slightly related functions for ASP.NET discussed in ResolveUrl() without Page Rick Strahl‘s post.

    Debugging Windows Services with “Edit & Continue”

    I needed to debug Windows Services. But I didn’t like  suggested in multiple articles Debugger.Launch.
     
    I was able
    2. Add in my service project a Reference to AndersonImes.ServiceProcess.dll
    3. Change in the Main() function
    //ServiceBase.Run(ServicesToRun);
    ServicesLoader.StartServices(ServicesToRun,true);
    Note that  AutoStart boolean second parameter is very convenient for immediate start of debugging, in particular if you have only one service.
     
    And all VS debugging features, including F5 and Edit&Continue are available.
    If you have some problems with this approach, see Five ways debugging .NET Windows service

    Understand Project dependency Hierarchy in VS solution

    I have a huge VS solution(with more than 60 projects) and for some projects order of references is not obvious.

    If you do not understand the hierarchy,you will get circular dependency“:Adding this project as a reference would cause a circular dependency.”
     
    Unfortunately, Visual Studio doesn’t create diagram to show projects hierarchy. 
     
    Open Source Project dependency graph generator didn’t help me, because it created only 2 levels of hierarchy for my huge solution. Also for project with . in the name(e.g. MyCompany.DataLayer.MyProject.csproj) it draw each part of the name as separate white box.

     The useful thing is  that the utility creates dep.txt, that can be used as a reference to understand depenancies, which can be quicker than view References of each project in VS.
    I found 2 codeplex projects Dependency Visualizer  and  Dependency Finder , that I haven’t explore yet.
     
    File dependency analysis  also addressed by commercial Project Analyzer product., but it doesn’t have evaluation version.

    Avoid throwing exception from asynchronous delegate.

    I am using delegate to invoke asyncronous call of the function. Sometimes the function can throw exception.
    As described in thread Re: exception handling with events , article “Handling Exceptions Thrown from an Asynchronous Delegate“(and in many other places)
    “You should call EndInvoke in a try/catch block to catch any exceptions
    your asynchronous method threw”. I followed the same approach in my Asynchronous long-running tasks in ASP.NET application  
    The code is like the following:
     RecalculateDelegate dlgt = new RecalculateDelegate(CallbackWithException);
    IAsyncResult asyncResult = dlgt.BeginInvoke(params, null, asyncState); 
     try
    {
    bool bRet=dlgt.EndInvoke(asyncResult);// 
      if (bRet == false
      {
        Debug.Assert(false, “To Implement”); 
      }
    }
     
    catch (Exception exc)
     {
       EventSources.RaiseErrorMessage(EventSources.MyEventSource, message, ExceptionSeverity.Error, exc);
      } 
    However when I tried to debug, VS showed me the message “An exception of type ‘xxx’ occurred in xxx.dll but was not handled in user code”. After this it also not executing catch block, but hangs for a while and then timeouts in the client(the code is located in .Net Remoting server method.)

     In production (Release mode without any debugging) it seems  that catch block is invoked(I can see event log entries).

     The discussion Exceptions in asynchronous delegates  suggests to change VS setting to avoid the message. However I feel that more reliable approach will be catch (and log) all exceptions in the delegate function to ensure that they are not thrown asyncronously.

     Related posts:
    Strange: calling EndInvoke from an AsyncCallback – why UnhandledException -too long and WinForms specific.