Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine the \Temporary ASP.NET Files\root\{site hash} with PowerShell?

ASP.NET makes use of a temporary files directory to store files for Shadow Copying and Dynamic Compilation. A typical path will look like this. Note the hash on the end of the path.

C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\{hash}

I'm using automated deployments and have noticed that these folders and their contents are not automatically removed. I'd like to automate the process of removing unused temp files as part of my deployment process. Such that as soon as the new version of my site is deployed the old temp files are removed.

The hash seems to be generated in a deterministic manner so I'm hoping I'll be able to determine the hash as part of my pre-deployment script and delete it post-deployment.

How is the hash calculated for an ASP.NET website?

References:

  1. How .Net names its temp folder inside C:\Windows\Microsoft.NET\Framework\v{version}\Temporary ASP.NET Files\root
  2. http://blogs.msdn.com/b/junfeng/archive/2004/02/09/69919.aspx
  3. http://dotnetinside.com/en/type/System.Web/ApplicationManager/4.0.0.0
like image 660
Daniel Little Avatar asked Jul 02 '14 06:07

Daniel Little


2 Answers

Well, a few moments with Reflector, searching all members within System.Web for the word "Temporary" shows this call gets me here:

string str2 = AppManagerAppDomainFactory.ConstructSimpleAppName(AppDomainAppVirtualPath);

But then I remember that the source code is available for all of .NET, so I move to the actual code, rather than the reflectored code: https://referencesource.microsoft.com/#System.Web/HttpRuntime.cs,870

Later in that method "SetupCodeGenDirectory" the path appears to be built on top of with

 this._codegenDir = Thread.GetDomain().DynamicDirectory;

So, looks like that hash is from DynamicDirectory. That's over here at http://referencesource.microsoft.com/#mscorlib/system/appdomain.cs#2792 which looks like an extern that is inside some COM Fusion Loader stuff:

[ComImport,InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("7c23ff90-33af-11d3-95da-00a024a85b51")]

But that GUID leads me here http://referencesource.microsoft.com/#mscorlib/microsoft/win32/fusionwrap.cs#94

which implies it's a public key token part:

     public const uint HASH_VALUE            = PUBLIC_KEY_TOKEN + 1;
     public const uint NAME                  = HASH_VALUE + 1;

That perhaps it's NAME? I'm guessing it's yourAssembly.GetPublicKeyToken();

OR, just change the folder that your temporary ASP.NET files go to in config section http://msdn.microsoft.com/en-us/library/system.web.configuration.compilationsection.tempdirectory%28VS.80%29.aspx in system.web in web.config

<compilation tempDirectory="D:\MoveThemHere">
like image 191
Scott Hanselman Avatar answered Nov 18 '22 12:11

Scott Hanselman


I know this is an old question, but in case someone still need it, this is the C# code that makes the trick. I guess it's not that hard to port to powershell.

        string siteId = "/LM/W3SVC/3/ROOT"; // This can be composed by getting the site ID using the ServerManager (Microsoft.Web.Administration)
        string physicalPath = "E:\\home\\mysite\\web\\";

        string v_app_name = HashCode.GetString32((siteId + physicalPath).ToLower(CultureInfo.InvariantCulture)).ToString("x", CultureInfo.InvariantCulture);

        string dir_name_32_bits_app = HashCode.GetString32(v_app_name).ToString("x8");
        string dir_name_64_bits_app = HashCode.GetString64(v_app_name).ToString("x8");

        Console.WriteLine("32 bits: " + dir_name_32_bits_app);
        Console.WriteLine("64 bits: " + dir_name_64_bits_app);

The HashCode class:

public class HashCode
{        
    public static unsafe int GetString32(string s)
    {
        fixed (char* str = s)
        {
            char* chPtr = str;
            int num = 0x15051505;
            int num2 = num;
            int* numPtr = (int*)chPtr;
            for (int i = s.Length; i > 0; i -= 4)
            {
                num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];
                if (i <= 2)
                {
                    break;
                }
                num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1];
                numPtr += 2;
            }
            return (num + (num2 * 0x5d588b65));
        }
    }


    public static unsafe int GetString64(string s)
    {
        fixed (char* str = s)
        {
            int num3;
            char* chPtr = str;
            int num = 0x1505;
            int num2 = num;
            for (char* chPtr2 = chPtr; (num3 = chPtr2[0]) != '\0'; chPtr2 += 2)
            {
                num = ((num << 5) + num) ^ num3;
                num3 = chPtr2[1];
                if (num3 == 0)
                {
                    break;
                }
                num2 = ((num2 << 5) + num2) ^ num3;
            }
            return (num + (num2 * 0x5d588b65));
        }
    }
}
like image 21
Fernando Ramos Avatar answered Nov 18 '22 10:11

Fernando Ramos