BuildResult.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / xsp / System / Web / Compilation / BuildResult.cs / 8 / BuildResult.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

 
 
/*********************************
 
BuildResult
    BuildResultCompileError
    BuildResultCompiledAssemblyBase
        BuildResultCompiledAssembly 
            BuildResultCustomString
            BuildResultMainCodeAssembly 
            BuildResultResourceAssembly 
        BuildResultCompiledType
            BuildResultCompiledTemplateType 
            BuildResultCompiledGlobalAsaxType
            ImageGeneratorBuildResultCompiledType
    BuildResultNoCompileTemplateControl
        BuildResultNoCompilePage 
        BuildResultNoCompileUserControl
            BuildResultNoCompileMasterPage 
    BuildResultCodeCompileUnit 

**********************************/ 

namespace System.Web.Compilation {

using System; 
using System.IO;
using System.CodeDom; 
using System.CodeDom.Compiler; 
using System.Collections;
using System.ComponentModel.Design; 
using System.Globalization;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security; 
using System.Security.Permissions;
using System.Threading; 
using System.Web.Caching; 
using System.Web.Hosting;
using System.Web.Util; 
using System.Web.UI;
using System.Web.Configuration;

internal enum BuildResultTypeCode { 
    Invalid=-1,
    BuildResultCompiledAssembly = 1, 
    BuildResultCompiledType = 2, 
    BuildResultCompiledTemplateType = 3,
#if ORCAS 
    ImageGeneratorBuildResultCompiledType = 4,
#endif
    BuildResultCustomString = 5,
    BuildResultMainCodeAssembly = 6, 
    BuildResultCodeCompileUnit = 7,
    BuildResultCompiledGlobalAsaxType = 8, 
    BuildResultResourceAssembly = 9, 
}
 
internal abstract class BuildResult {

    // const masks into the BitVector32
    // The 16 lower bits come from the BuildProviderResultFlags enumeration 
    // and should not be used here.  They are set from calling
    // BuildProvider.GetResultFlags. 
    protected const int usesCacheDependency         = 0x00010000; 
    protected const int usesExistingAssembly        = 0x00020000;
    private const int noMemoryCache                 = 0x00040000; 
    protected const int hasAppOrSessionObjects      = 0x00080000;
    protected const int dependenciesHashComputed    = 0x00100000;
    #pragma warning disable 0649
    protected SimpleBitVector32 _flags; 
    #pragma warning restore 0649
 
    internal static BuildResult CreateBuildResultFromCode(BuildResultTypeCode code, 
        VirtualPath virtualPath) {
 
        BuildResult ret = null;

        switch (code) {
            case BuildResultTypeCode.BuildResultCompiledAssembly: 
                ret = new BuildResultCompiledAssembly();
                break; 
 
            case BuildResultTypeCode.BuildResultCompiledType:
                ret = new BuildResultCompiledType(); 
                break;

            case BuildResultTypeCode.BuildResultCompiledTemplateType:
                ret = new BuildResultCompiledTemplateType(); 
                break;
 
            case BuildResultTypeCode.BuildResultCompiledGlobalAsaxType: 
                ret = new BuildResultCompiledGlobalAsaxType();
                break; 

#if ORCAS
            case BuildResultTypeCode.ImageGeneratorBuildResultCompiledType:
                ret = new ImageGeneratorBuildResultCompiledType(); 
                break;
#endif 
 
            case BuildResultTypeCode.BuildResultCustomString:
                ret = new BuildResultCustomString(); 
                break;

            case BuildResultTypeCode.BuildResultMainCodeAssembly:
                ret = new BuildResultMainCodeAssembly(); 
                break;
 
            case BuildResultTypeCode.BuildResultResourceAssembly: 
                ret = new BuildResultResourceAssembly();
                break; 

            case BuildResultTypeCode.BuildResultCodeCompileUnit:
                ret = new BuildResultCodeCompileUnit();
                break; 

            default: 
                Debug.Assert(false, "code=" + code); 
                return null;
        } 

        ret.VirtualPath = virtualPath;

        // Set _nextUpToDateCheck to MinValue, to make sure the next call to IsUpToDate() 
        // actually makes the check
        ret._nextUpToDateCheck = DateTime.MinValue; 
 
        return ret;
    } 

    internal virtual BuildResultTypeCode GetCode() { return BuildResultTypeCode.Invalid; }

    internal int Flags { 
        get { return _flags.IntegerValue; }
        set { _flags.IntegerValue = value; } 
    } 

    private VirtualPath _virtualPath; 
    internal VirtualPath VirtualPath {
        get { return _virtualPath; }
        set { _virtualPath = value; }
    } 

    // Are the BuildResult's VirtualPathDependencies being monitored by a CacheDependency. 
    // If so, then we don't need to check validity after finding the BuildResult in the 
    // memory cache (since it would have been kicked out if it was invalid).
    internal bool UsesCacheDependency { 
        get { return _flags[usesCacheDependency]; }
        set { _flags[usesCacheDependency] = value; }
    }
 
    // Does the appdomain need to be shut down when this item becomes invalid?
    internal bool ShutdownAppDomainOnChange { 
        get { return _flags[(int)BuildProviderResultFlags.ShutdownAppDomainOnChange]; } 
    }
 
    // The list of files (virtual paths) it depends on (for caching purpose)
    private ArrayList _virtualPathDependencies;
    internal ICollection VirtualPathDependencies {
        get { return _virtualPathDependencies; } 
    }
 
    // Hash code based on all the source file dependencies 
    private string _virtualPathDependenciesHash;
    internal string VirtualPathDependenciesHash { 
        get {
            EnsureVirtualPathDependenciesHashComputed();

            return _virtualPathDependenciesHash; 
        }
 
        set { 
            Debug.Assert(_virtualPathDependenciesHash == null);
            _virtualPathDependenciesHash = value; 
        }
    }

    internal bool DependenciesHashComputed { 
        get { return _flags[dependenciesHashComputed]; }
    } 
 
    internal void EnsureVirtualPathDependenciesHashComputed() {
 
        if (!DependenciesHashComputed) {

            // We shouldn't already have a hash
            Debug.Assert(_virtualPathDependenciesHash == null); 

            // Sort the source dependencies to make the hash code predictable 
            if (_virtualPathDependencies != null) 
                _virtualPathDependencies.Sort(InvariantComparer.Default);
 
            _virtualPathDependenciesHash = ComputeSourceDependenciesHashCode(null /*virtualPath*/);

            // It's computed, but it could be null
            _flags[dependenciesHashComputed] = true; 
        }
    } 
 
    // These fields are used to make sure we only check the UpToDate status
    // of the build result once every few seconds (since it's expensive) 
    private DateTime _nextUpToDateCheck = DateTime.Now.AddSeconds(UpdateInterval);
    private int _lock;
    private const int UpdateInterval = 2;   // 2 seconds
 

    internal void SetVirtualPathDependencies(ArrayList sourceDependencies) { 
 
        Debug.Assert(_virtualPathDependencies == null);
        Debug.Assert(sourceDependencies != null); 

        _virtualPathDependencies = sourceDependencies;
    }
 
    internal void AddVirtualPathDependencies(ICollection sourceDependencies) {
 
        if (sourceDependencies == null) 
            return;
 
        if (_virtualPathDependencies == null) {
            _virtualPathDependencies = new ArrayList(sourceDependencies);
        }
        else { 
            _virtualPathDependencies.AddRange(sourceDependencies);
        } 
    } 

    /* 
     * Can the result be unloaded from memory.  Most objects can, but things like
     * Assemblies and Types can't.  This is used to determine the caching behavior.
     */
    internal virtual bool IsUnloadable { get { return true; } } 

    /* 
     * Should the result be cached to disk.  Usually yes, but for things like compile 
     * errors, we only cache them to memory.
     */ 
    internal virtual bool CacheToDisk { get { return true; } }

    /*
     * Should the result be cached to memory.  Usually yes, but for things like top level 
     * assemblies, we only cache them to disk.
     */ 
    internal bool CacheToMemory { 
        get { return !_flags[noMemoryCache]; }
        set { _flags[noMemoryCache] = !value; } 
    }

    /*
     * Time the build result should expire from the memory cache 
     */
    internal virtual DateTime MemoryCacheExpiration { 
        get { 
            return Cache.NoAbsoluteExpiration;
        } 
    }

    /*
     * Sliding expiration for the build result 
     */
    internal virtual TimeSpan MemoryCacheSlidingExpiration { 
        get { 
            return Cache.NoSlidingExpiration;
        } 
    }

    protected void ReadPreservedFlags(PreservationFileReader pfr) {
        string s = pfr.GetAttribute("flags"); 
        if ((s != null) && (s.Length != 0)) {
            Flags = Int32.Parse(s, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture); 
        } 
    }
 
    internal virtual void GetPreservedAttributes(PreservationFileReader pfr) {
        ReadPreservedFlags(pfr);
    }
 
    internal virtual void SetPreservedAttributes(PreservationFileWriter pfw) {
        if (Flags != 0) { 
            pfw.SetAttribute("flags", Flags.ToString("x", CultureInfo.InvariantCulture)); 
        }
    } 

    /*
     * Tell the BuildResult that its dependencies are not up to date, in order
     * to give it a chance to do some cleanup. 
     */
    internal virtual void RemoveOutOfDateResources(PreservationFileReader pfw) {} 
 
    // Compute the current hash code of the preserved data.  Return 0 if the
    // hash code is not valid. 
    internal long ComputeHashCode(long hashCode) {
        return ComputeHashCode(hashCode, 0);
    }
 
    internal long ComputeHashCode(long hashCode1, long hashCode2) {
        HashCodeCombiner hashCodeCombiner = new HashCodeCombiner(); 
 
        // If a hashcode was passed in, start with it
        if (hashCode1 != 0) 
            hashCodeCombiner.AddObject(hashCode1);
        if (hashCode2 != 0)
            hashCodeCombiner.AddObject(hashCode2);
 
        ComputeHashCode(hashCodeCombiner);
 
        return hashCodeCombiner.CombinedHash; 
    }
 
    /*
     * Compute the hash code of what this buid result depends on, excluding
     * the virtual path dependencies (which are handled separately by
     * VirtualPathDependenciesHash). 
     */
    protected virtual void ComputeHashCode(HashCodeCombiner hashCodeCombiner) { 
 
    }
 
    internal virtual string ComputeSourceDependenciesHashCode(VirtualPath virtualPath) {
        // Return an empty string if there are no dependencies.  This is different from
        // null, which means 'don't cache'
        if (VirtualPathDependencies == null) 
            return String.Empty;
 
        // If no virtual path was passed in, use the one from the BuildResult 
        if (virtualPath == null)
            virtualPath = VirtualPath; 

        return virtualPath.GetFileHash(VirtualPathDependencies);
    }
 
    internal bool IsUpToDate(VirtualPath virtualPath) {
 
        // This should never be called on a BuildResult that has already been 
        // determined to be out of date.
        Debug.Assert(_lock >= 0); 
        if (_lock < 0)
            return false;

        // Don't check more than every two seconds 
        DateTime now = DateTime.Now;
        // Due to bug 214038, CBM can be called multiple times in a very short time. 
        if (now < _nextUpToDateCheck && !BuildManagerHost.InClientBuildManager) { 
            Debug.Trace("BuildResult", "IsUpToDate: true since called less than 2 seconds ago. "
                + _nextUpToDateCheck + "," + now); 
            return true;
        }

        // If we don't get the lock, just say it's up to date without checking 
        if (Interlocked.CompareExchange(ref _lock, 1, 0) != 0) {
            Debug.Trace("BuildResult", "IsUpToDate returning true because it didn't get the lock"); 
            return true; 
        }
 
        string newHashCode;

        try {
            newHashCode = ComputeSourceDependenciesHashCode(virtualPath); 
        }
        catch { 
            // Make sure to release the lock if something throws. 
            Interlocked.Exchange(ref _lock, 0);
            throw; 
        }

        // Check if we're up to date.  A null hash code means the cache should not be used.
        if (newHashCode == null || newHashCode != _virtualPathDependenciesHash) { 
            Debug.Trace("BuildResult", "IsUpToDate: '" + VirtualPath + "' is out of date");
 
            // Set the lock to -1 to mark that we're not up to date 
            _lock = -1;
            return false; 
        }

        Debug.Trace("BuildResult", "IsUpToDate: '" + VirtualPath + "' is up to date");
 
        // We're up to date.  Remember the time we checked, and reset the lock
        _nextUpToDateCheck = now.AddSeconds(UpdateInterval); 
        Interlocked.Exchange(ref _lock, 0); 

        return true; 
    }

}
 
internal class BuildResultCompileError: BuildResult {
 
    // The exception in case we cached the result of a failed compilation 
    private HttpCompileException _compileException;
    internal HttpCompileException CompileException { get { return _compileException; } } 

    internal BuildResultCompileError(VirtualPath virtualPath, HttpCompileException compileException) {
        VirtualPath = virtualPath;
        _compileException = compileException; 
    }
 
    /* 
     * Don't cache compile errors to disk
     */ 
    internal override bool CacheToDisk { get { return false; } }

    internal override DateTime MemoryCacheExpiration {
        get { 
            // Only cache compile errors for 10 seconds.  This is to get us out of trouble
            // if the compilation fails due to some strange timing issue, and might succeed 
            // on retry (VSWhidbey 483169) 
            return DateTime.UtcNow.AddSeconds(10);
        } 
    }
}

internal class BuildResultCustomString: BuildResultCompiledAssembly { 

    private string _customString; 
 
    internal BuildResultCustomString() {}
 
    internal BuildResultCustomString(Assembly a, string customString) : base(a) {
        Debug.Assert(customString != null);
        _customString = customString;
    } 

    internal override BuildResultTypeCode GetCode() { 
        return BuildResultTypeCode.BuildResultCustomString; } 

    internal override void GetPreservedAttributes(PreservationFileReader pfr) { 
        base.GetPreservedAttributes(pfr);

        // Retrieve the custom string
        _customString = pfr.GetAttribute("customString"); 
        Debug.Assert(_customString != null);
    } 
 
    internal override void SetPreservedAttributes(PreservationFileWriter pfw) {
        base.SetPreservedAttributes(pfw); 

        // Preserve the custom string
        pfw.SetAttribute("customString", _customString);
    } 

    internal string CustomString { 
        get { return _customString; } 
    }
 
}

internal abstract class BuildResultCompiledAssemblyBase: BuildResult {
 
    internal bool UsesExistingAssembly {
        get { return _flags[usesExistingAssembly]; } 
        set { _flags[usesExistingAssembly] = value; } 
    }
 
    // Assemblies are *not* unloadable, so only allow the build result to be unloaded
    // if there is no assembly
    internal override bool IsUnloadable { get { return (ResultAssembly == null); } }
 
    internal abstract Assembly ResultAssembly { get; set; }
 
    static private string s_codegenDir = null; 

    internal static Assembly GetPreservedAssembly(PreservationFileReader pfr) { 
        string assemblyName = pfr.GetAttribute("assembly");

        if (assemblyName == null)
            return null; 

        // Try to load the assembly 
        try { 
            Assembly a = Assembly.Load(assemblyName);
 
            // VSWhidbey 564168
            // Do not load assemblies or assemblies with references that
            // do not exist or are marked for deletion
 
            // It is possible that Assembly.Load succeeds, even though the
            // underlying DLL was renamed (to .delete).  In that case, we should 
            // not return the assembly, as we would be unable to compile with 
            // a reference to it.
 
            if (AssemblyIsInvalid(a)) {
                // Throw some exception, since the caller doesn't expect null
                throw new InvalidOperationException();
            } 

            // Check references of the assembly, and make sure they exists, 
            // otherwise throw an exception. 
            CheckAssemblyIsValid(a, new Hashtable());
 
            return a;
        }
        catch {
            Debug.Trace("BuildResult", "GetPreservedAssembly: couldn't load assembly '" + assemblyName + "'; deleting associated files."); 

            // Remove the assembly and all the associated files 
            pfr.DiskCache.RemoveAssemblyAndRelatedFiles(assemblyName); 
            throw;
        } 
    }

    // DevDiv Bug 98735
    // Go through the assembly and all references (including deeper levels) to make sure that 
    // each referenced assembly exists and does not have a dot delete.
    // If any referenced assembly is removed or marked for deletion, 
    // we invalidate the base assembly by throwing an InvalidOperationException 
    private static void CheckAssemblyIsValid(Assembly a, Hashtable checkedAssemblies) {
 
        // Keep track of which assemblies we already checked so we can skip them
        checkedAssemblies.Add(a, null);

        foreach (AssemblyName aName in a.GetReferencedAssemblies()) { 
            Assembly referencedAssembly = Assembly.Load(aName);
 
            // If it is in the GAC, skip checking it 
            if (referencedAssembly.GlobalAssemblyCache)
                continue; 

            // Do not validate assemblies other than those we generate.
            // If the assembly is NOT in the codegen folder, skip it
            if (!AssemblyIsInCodegenDir(referencedAssembly)) 
                continue;
 
            // If we have already checked an assembly, don't check it again 
            if (!checkedAssemblies.Contains(referencedAssembly)) {
                if (AssemblyIsInvalid(referencedAssembly)) 
                    throw new InvalidOperationException();

                // Visit nested referenced assemblies
                CheckAssemblyIsValid(referencedAssembly, checkedAssemblies); 
            }
        } 
    } 

    private static bool AssemblyIsInCodegenDir(Assembly a) { 
        string path = Util.GetAssemblyCodeBase(a);
        FileInfo f = new FileInfo(path);
        string assemblyDir = FileUtil.RemoveTrailingDirectoryBackSlash(f.Directory.FullName);
        if (s_codegenDir == null) { 
            s_codegenDir = FileUtil.RemoveTrailingDirectoryBackSlash(HttpRuntime.CodegenDir);
        } 
 
        // check if the assembly is directly under codegen
        // Shadow-copied assemblies are in a deeper directory (eg myapp\zzz\yyy\assembly\dl3\xxxx) 
        if (string.Equals(assemblyDir, s_codegenDir, StringComparison.OrdinalIgnoreCase))
            return true;

        return false; 
    }
 
    private static bool AssemblyIsInvalid(Assembly a) { 
        // If the file does not exist, or if it has a .delete file,
        // then it should not be used 
        string path = Util.GetAssemblyCodeBase(a);
        return (!FileUtil.FileExists(path) || DiskBuildResultCache.HasDotDeleteFile(path));
    }
 

    internal override void SetPreservedAttributes(PreservationFileWriter pfw) { 
        base.SetPreservedAttributes(pfw); 

        if (ResultAssembly != null) { 
            string assemblyName;
            if (ResultAssembly.GlobalAssemblyCache) {
                // If it's in the GAC, store the full name (VSWhidbey 384416)
                assemblyName = ResultAssembly.FullName; 
            }
            else { 
                // Otherwise, store the short name, to avoid uselessly growing the preservation file 
                assemblyName = ResultAssembly.GetName().Name;
            } 
            pfw.SetAttribute("assembly", assemblyName);
        }
    }
 
    /*
     * Tell the BuildResult that its dependencies are not up to date, in order 
     * to give it a chance to do some cleanup. 
     */
    internal override void RemoveOutOfDateResources(PreservationFileReader pfr) { 

        // If the preservation file is pointing to an assembly that was not built
        // for this result, do not attempt to clean it up (see VSWhidbey 74094)
        ReadPreservedFlags(pfr); 
        if (UsesExistingAssembly)
            return; 
 
        // Remove the assembly and all the associated files
        string assemblyName = pfr.GetAttribute("assembly"); 
        if (assemblyName != null) {
            pfr.DiskCache.RemoveAssemblyAndRelatedFiles(assemblyName);
        }
    } 

    protected override void ComputeHashCode(HashCodeCombiner hashCodeCombiner) { 
 
        base.ComputeHashCode(hashCodeCombiner);
 
        // Make the hash code depend on the relevant contents of the  config section

        CompilationSection compConfig = RuntimeConfig.GetConfig(VirtualPath).Compilation;
 
        hashCodeCombiner.AddObject(compConfig.RecompilationHash);
    } 
} 

internal class BuildResultCompiledAssembly: BuildResultCompiledAssemblyBase { 

    private Assembly _assembly;

    internal BuildResultCompiledAssembly() {} 

    internal BuildResultCompiledAssembly(Assembly a) { 
        _assembly = a; 
    }
 
    internal override BuildResultTypeCode GetCode() { return BuildResultTypeCode.BuildResultCompiledAssembly; }

    internal override Assembly ResultAssembly {
        get { return _assembly; } 
        set { _assembly = value; }
    } 
 
    internal override void GetPreservedAttributes(PreservationFileReader pfr) {
        base.GetPreservedAttributes(pfr); 

        ResultAssembly = GetPreservedAssembly(pfr);
    }
} 

/* 
 * Same as BuildResultCompiledAssembly, but with some special behavior specific to 
 * the main code assembly.  Specifically, it adds support for the AppInitialize method
 * and for VB's My.* 
 */
internal class BuildResultMainCodeAssembly: BuildResultCompiledAssembly {

    private const string appInitializeMethodName = "AppInitialize"; 

    private MethodInfo _appInitializeMethod; 
 
    internal BuildResultMainCodeAssembly() {}
 
    internal BuildResultMainCodeAssembly(Assembly a) : base(a) {

        // Look for an AppInitialize static method in the assembly
        FindAppInitializeMethod(); 
    }
 
    internal override BuildResultTypeCode GetCode() { return BuildResultTypeCode.BuildResultMainCodeAssembly; } 

    internal override void GetPreservedAttributes(PreservationFileReader pfr) { 
        base.GetPreservedAttributes(pfr);

        // Does the assembly have an AppInitialize method?
        string appInitializeClass = pfr.GetAttribute("appInitializeClass"); 
        if (appInitializeClass != null) {
 
            // Get the Type that contains the method 
            Type appInitializeType = ResultAssembly.GetType(appInitializeClass);
            Debug.Assert(appInitializeType != null); 

            // Find the method
            _appInitializeMethod = FindAppInitializeMethod(appInitializeType);
            Debug.Assert(_appInitializeMethod != null); 
        }
    } 
 
    internal override void SetPreservedAttributes(PreservationFileWriter pfw) {
 
        base.SetPreservedAttributes(pfw);

        // If there is an AppInitialize method, save the class name that it's in
        if (_appInitializeMethod != null) { 
            pfw.SetAttribute("appInitializeClass", _appInitializeMethod.ReflectedType.FullName);
        } 
    } 

    private void FindAppInitializeMethod() { 

        Debug.Assert(_appInitializeMethod == null);

        // Look in all the public types in the assembly 
        foreach (Type t in ResultAssembly.GetExportedTypes()) {
 
            // Look for an AppInitialize method 
            MethodInfo tmpAppInitializeMethod = FindAppInitializeMethod(t);
 
            if (tmpAppInitializeMethod != null) {

                // Make sure we didn't already have one
                if (_appInitializeMethod != null) { 
                    throw new HttpException(SR.GetString(
                        SR.Duplicate_appinitialize, _appInitializeMethod.ReflectedType.FullName, t.FullName)); 
                } 

                // Keep track of the method 
                _appInitializeMethod = tmpAppInitializeMethod;
            }
        }
    } 

    private MethodInfo FindAppInitializeMethod(Type t) { 
 
        return t.GetMethod(appInitializeMethodName,
            BindingFlags.Public | BindingFlags.Static| BindingFlags.IgnoreCase, 
            null /*Binder*/,
            new Type[0], // Method with no parameters
            null
            ); 
    }
 
    // Call the AppInitialize method if there is one 
    internal void CallAppInitializeMethod() {
        if (_appInitializeMethod != null) { 
            using (new ApplicationImpersonationContext()) {
                using (HostingEnvironment.SetCultures()) {
                    _appInitializeMethod.Invoke(null, null);
                } 
            }
        } 
    } 
}
 
/*
 * Same as BuildResultCompiledAssembly, but with some special behavior specific to
 * resources directory (both global and local)
 */ 
internal class BuildResultResourceAssembly : BuildResultCompiledAssembly {
    internal BuildResultResourceAssembly() { } 
 
    internal BuildResultResourceAssembly(Assembly a) : base(a) { }
 
    internal override BuildResultTypeCode GetCode() { return BuildResultTypeCode.BuildResultResourceAssembly; }

    internal override string ComputeSourceDependenciesHashCode(VirtualPath virtualPath) {
 
        // If no virtual path was passed in, use the one from the BuildResult
        if (virtualPath == null) 
            virtualPath = VirtualPath; 

        // We don't want to use the default ComputeSourceDependenciesHashCode imnplementation, 
        // as it would use all files in the resources dir to calculate the hash.  Instead,
        // we only want the hash the be based on the culture neutral resources, so that
        // changes to culture specific files don't cause a rebuild of the main res assembly
        HashCodeCombiner hashCodeCombiner = new HashCodeCombiner(); 
        hashCodeCombiner.AddResourcesDirectory(virtualPath.MapPathInternal());
        return hashCodeCombiner.CombinedHashString; 
    } 

    // In addition to the standard BuildResult hash code (which drives recompilation of the main 
    // resources assembly), we need an additional one so we know when to rebuild satellites.
    private string _resourcesDependenciesHash;
    internal string ResourcesDependenciesHash {
        get { 
            EnsureResourcesDependenciesHashComputed();
 
            return _resourcesDependenciesHash; 
        }
 
        set {
            Debug.Assert(_resourcesDependenciesHash == null);
            _resourcesDependenciesHash = value;
            Debug.Assert(_resourcesDependenciesHash != null); 
        }
    } 
 
    private void EnsureResourcesDependenciesHashComputed() {
        if (_resourcesDependenciesHash != null) 
            return;

        // Even though we make it dependent on all res files, if we get here we know the neutral
        // ones are up to date, so effectively it's look the culture specific that matter. 
        _resourcesDependenciesHash = HashCodeCombiner.GetDirectoryHash(VirtualPath);
    } 
 
    internal override void GetPreservedAttributes(PreservationFileReader pfr) {
        base.GetPreservedAttributes(pfr); 

        ResourcesDependenciesHash = pfr.GetAttribute("resHash");
    }
 
    internal override void SetPreservedAttributes(PreservationFileWriter pfw) {
        base.SetPreservedAttributes(pfw); 
 
        pfw.SetAttribute("resHash", ResourcesDependenciesHash);
    } 

}

internal class BuildResultCompiledType : BuildResultCompiledAssemblyBase, ITypedWebObjectFactory { 

    // The delegate for fast object instantiation 
    private InstantiateObject _instObj; 
    private bool _triedToGetInstObj;
 
    internal BuildResultCompiledType() {}

    internal BuildResultCompiledType(Type t) {
        _builtType = t; 
    }
 
    internal override BuildResultTypeCode GetCode() { return BuildResultTypeCode.BuildResultCompiledType; } 

    internal override Assembly ResultAssembly { 
        get { return _builtType.Assembly; }
        set { Debug.Assert(false); }
    }
 
    private Type _builtType;
    internal Type ResultType { 
        get { return _builtType; } 
        set { _builtType = value; }
    } 

    // IWebObjectFactory.CreateInstance
    public object CreateInstance() {
 
        // Get the fast object creation delegate on demand
        if (!_triedToGetInstObj) { 
            _instObj = ObjectFactoryCodeDomTreeGenerator.GetFastObjectCreationDelegate(ResultType); 
            _triedToGetInstObj = true;
        } 

        // If the fast factory is not available, just call CreateInstance
        //
        if (_instObj == null) { 
            return HttpRuntime.CreatePublicInstance(ResultType);
        } 
 
        // Call it to instantiate the object
        return _instObj(); 
    }

    // ITypedWebObjectFactory.CreateInstance
    public virtual Type InstantiatedType { 
        get { return ResultType; }
    } 
 
    protected override void ComputeHashCode(HashCodeCombiner hashCodeCombiner) {
 
        base.ComputeHashCode(hashCodeCombiner);

        // Make pages have a dependency on the main local resources assembly, so that they
        // get recompiled when it changes (but not when satellites change). VSWhidbey 277357 
        if (VirtualPath != null) {
 
            // Remove the file name to get its directory 
            VirtualPath virtualDir = VirtualPath.Parent;
 
            Assembly localResAssembly = BuildManager.GetLocalResourcesAssembly(virtualDir);

            if (localResAssembly != null) {
                hashCodeCombiner.AddFile(localResAssembly.Location); 
            }
        } 
    } 

    internal override void GetPreservedAttributes(PreservationFileReader pfr) { 
        base.GetPreservedAttributes(pfr);

        // Get the assembly and type
        Assembly a = GetPreservedAssembly(pfr); 
        Debug.Assert(a != null);
        string typeName = pfr.GetAttribute("type"); 
        ResultType = a.GetType(typeName, true /*throwOnError*/); 
    }
 
    internal override void SetPreservedAttributes(PreservationFileWriter pfw) {
        base.SetPreservedAttributes(pfw);
        pfw.SetAttribute("type", ResultType.FullName);
    } 
}
 
/* 
 * Used for pages, user controls, and master pages
 */ 
internal class BuildResultCompiledTemplateType: BuildResultCompiledType {

    public BuildResultCompiledTemplateType() {}
 
    public BuildResultCompiledTemplateType(Type t) : base(t) {}
 
    internal override BuildResultTypeCode GetCode() { return BuildResultTypeCode.BuildResultCompiledTemplateType; } 

    protected override void ComputeHashCode(HashCodeCombiner hashCodeCombiner) { 

        base.ComputeHashCode(hashCodeCombiner);

        // Make the hash code depend on the relevant contents of the  config section 

        PagesSection pagesConfig = RuntimeConfig.GetConfig(VirtualPath).Pages; 
        hashCodeCombiner.AddObject(Util.GetRecompilationHash(pagesConfig)); 
    }
} 

/*
 * Used for global.asax
 */ 
internal class BuildResultCompiledGlobalAsaxType : BuildResultCompiledType {
 
    public BuildResultCompiledGlobalAsaxType() { } 

    public BuildResultCompiledGlobalAsaxType(Type t) : base(t) { } 

    internal override BuildResultTypeCode GetCode() { return BuildResultTypeCode.BuildResultCompiledGlobalAsaxType; }

    // Does global.asax contain  tags with application or session scope 
    internal bool HasAppOrSessionObjects {
        get { return _flags[hasAppOrSessionObjects]; } 
        set { _flags[hasAppOrSessionObjects] = value; } 
    }
} 

#if ORCAS
internal class ImageGeneratorBuildResultCompiledType : BuildResultCompiledType {
    private OutputCacheInfo _outputCacheInfo; 
    private string _customErrorImageUrl;
 
    public ImageGeneratorBuildResultCompiledType() { 
    }
 
    public ImageGeneratorBuildResultCompiledType(Type t) : base(t) {
    }

    public string CustomErrorImageUrl { 
        get {
            return _customErrorImageUrl; 
        } 
        set {
            _customErrorImageUrl = value; 
        }
    }

    public OutputCacheInfo OutputCacheInfo { 
        get {
            return _outputCacheInfo; 
        } 
        set {
            _outputCacheInfo = value; 
        }
    }

    internal override BuildResultTypeCode GetCode() { 
        return BuildResultTypeCode.ImageGeneratorBuildResultCompiledType;
    } 
 
    internal override void GetPreservedAttributes(PreservationFileReader pfr) {
        base.GetPreservedAttributes(pfr); 
        bool diskCacheable = true;

        int duration = 0;
        string s = pfr.GetAttribute("OutputCache_Duration"); 
        if ((s != null) && (s.Length != 0)) {
            duration = Int32.Parse(s, CultureInfo.InvariantCulture); 
        } 

        OutputCacheLocation location = OutputCacheLocation.Any; 
        s = pfr.GetAttribute("OutputCache_OutputCacheLocation");
        if ((s != null) && (s.Length != 0)) {
            location = (OutputCacheLocation)Enum.Parse(typeof(OutputCacheLocation), s);
        } 

        s = pfr.GetAttribute("OutputCache_DiskCacheable"); 
        if ((s != null) && (s.Length != 0)) { 
            diskCacheable = Boolean.Parse(s);
        } 

        string sqlDependency = pfr.GetAttribute("OutputCache_SqlDependency");
        string varyByCustom = pfr.GetAttribute("OutputCache_VaryByCustom");
        string varyByContentEncoding prf.GetAttribute("OutputCache_VaryByContentEncoding"); 
        string varyByHeader = pfr.GetAttribute("OutputCache_VaryByHeader");
        string varyByParams = pfr.GetAttribute("OutputCache_VaryByParams"); 
 
        _outputCacheInfo = new OutputCacheInfo(varyByContentEncoding, varyByHeader, varyByCustom, varyByParams, sqlDependency, location, duration, diskCacheable);
 
        _customErrorImageUrl = pfr.GetAttribute("OutputCache_CustomErrorImageUrl");
    }

    internal override void SetPreservedAttributes(PreservationFileWriter pfw) { 
        base.SetPreservedAttributes(pfw);
 
        if (_outputCacheInfo != null) { 
            pfw.SetAttribute("OutputCache_Duration", Convert.ToString(_outputCacheInfo.Duration, CultureInfo.InvariantCulture));
            pfw.SetAttribute("OutputCache_OutputCacheLocation", Convert.ToString(_outputCacheInfo.OutputCacheLocation, CultureInfo.InvariantCulture)); 
            pfw.SetAttribute("OutputCache_DiskCacheable", Convert.ToString(_outputCacheInfo.Duration, CultureInfo.InvariantCulture));

            if (_outputCacheInfo.SqlDependency != null) {
                pfw.SetAttribute("OutputCache_SqlDependency", _outputCacheInfo.SqlDependency); 
            }
 
            if (_outputCacheInfo.VaryByCustom != null) { 
                pfw.SetAttribute("OutputCache_VaryByCustom", _outputCacheInfo.VaryByCustom);
            } 

            if (_outputCacheInfo.VaryByContentEncoding != null) {
                pfw.SetAttribute("OutputCache_VaryByContentEncoding", _outputCacheInfo.VaryByContentEncoding);
            } 

            if (_outputCacheInfo.VaryByHeader != null) { 
                pfw.SetAttribute("OutputCache_VaryByHeader", _outputCacheInfo.VaryByHeader); 
            }
 
            if (_outputCacheInfo.VaryByParams != null) {
                pfw.SetAttribute("OutputCache_VaryByParams", _outputCacheInfo.VaryByParams);
            }
        } 

        if ((_customErrorImageUrl != null) && (_customErrorImageUrl.Length != 0)) { 
            pfw.SetAttribute("CustomErrorImageUrl", _customErrorImageUrl); 
        }
    } 
}
#endif

internal abstract class BuildResultNoCompileTemplateControl : BuildResult, ITypedWebObjectFactory { 

    protected Type _baseType; 
    protected RootBuilder _rootBuilder; 
    protected bool _initialized;
 
    internal BuildResultNoCompileTemplateControl(Type baseType, TemplateParser parser) {
        _baseType = baseType;
        _rootBuilder = parser.RootBuilder;
 
        // Cleanup anything that's no longer needed in the ControlBuilder
        _rootBuilder.PrepareNoCompilePageSupport(); 
    } 

    internal override BuildResultTypeCode GetCode() { 
        Debug.Assert(false, "BuildResultNoCompileTemplateControl");
        return BuildResultTypeCode.Invalid;
    }
 
    /*
     * Don't cache the result of no-compile pages to disk (they are reparsed in each appdomain) 
     */ 
    internal override bool CacheToDisk { get { return false; } }
 
    /*
     * Give a 5 minute sliding expiration to no-compile pages
     */
    internal override TimeSpan MemoryCacheSlidingExpiration { 
        get {
            return TimeSpan.FromMinutes(5); 
        } 
    }
 
    // Note that since this is a no-compile control, this is not really the 'base' type,
    // but is in fact the Type we directly instantiate.
    internal Type BaseType {
        get { return _baseType; } 
    }
 
    // IWebObjectFactory.CreateInstance 
    public virtual object CreateInstance() {
 
        // Create the object that the aspx/ascx 'inherits' from
        TemplateControl templateControl = (TemplateControl) HttpRuntime.FastCreatePublicInstance(_baseType);

        // Set the virtual path and TemplateSourceDirectory in the control 
        templateControl.TemplateControlVirtualPath = VirtualPath;
        templateControl.TemplateControlVirtualDirectory = VirtualPath.Parent; 
 
        // Give the TemplateControl a pointer to us, so it can call us back during FrameworkInitialize
        templateControl.SetNoCompileBuildResult(this); 

        return templateControl;
    }
 
    // ITypedWebObjectFactory.CreateInstance
    public virtual Type InstantiatedType { 
        get { return _baseType; } 
    }
 
    internal virtual void FrameworkInitialize(TemplateControl templateControl) {

        HttpContext context = HttpContext.Current;
 
        // Storing the filter resolution service and template control into the context
        // since each thread needs to set them differently. 
        TemplateControl savedTemplateControl = context.TemplateControl; 
        context.TemplateControl = templateControl;
 
        try {
            // Create the control tree

            // DevDiv Bug 59351 
            // Lock during the first time we initialize the control builder with the object,
            // to prevent concurrency issues. 
            if (!_initialized) { 
                lock (this) {
                    _rootBuilder.InitObject(templateControl); 
                }
                _initialized = true;
            }
            else { 
                _rootBuilder.InitObject(templateControl);
            } 
        } 
        finally {
            // Restore the previous template control 
            if (savedTemplateControl != null)
                context.TemplateControl = savedTemplateControl;
        }
    } 
}
 
internal class BuildResultNoCompilePage: BuildResultNoCompileTemplateControl { 

    private TraceEnable _traceEnabled; 
    private TraceMode _traceMode;

    private OutputCacheParameters _outputCacheData;
    private string[] _fileDependencies; 

    private bool _validateRequest; 
    private string _stylesheetTheme; 

    internal BuildResultNoCompilePage(Type baseType, TemplateParser parser) 
        : base(baseType, parser) {

        PageParser pageParser = (PageParser) parser;
 
        //
        // Keep track of relevant info from the parser 
        // 

        _traceEnabled = pageParser.TraceEnabled; 
        _traceMode = pageParser.TraceMode;

        if (pageParser.OutputCacheParameters != null) {
            _outputCacheData = pageParser.OutputCacheParameters; 

            // If we're not supposed to cache it, clear out the field 
            if (_outputCacheData.Duration == 0 || _outputCacheData.Location == OutputCacheLocation.None) { 
                _outputCacheData = null;
            } 
            else {
                // Since we're going to be output caching, remember all the dependencies
                _fileDependencies = new string[pageParser.SourceDependencies.Count];
                int i = 0; 
                foreach (string dependency in pageParser.SourceDependencies) {
                    _fileDependencies[i++] = dependency; 
                } 
                Debug.Assert(i == pageParser.SourceDependencies.Count);
            } 
        }

        _validateRequest = pageParser.ValidateRequest;
        _stylesheetTheme = pageParser.StyleSheetTheme; 
    }
 
    internal override void FrameworkInitialize(TemplateControl templateControl) { 
        Page page = (Page)templateControl;
        page.StyleSheetTheme = _stylesheetTheme; 

        page.InitializeStyleSheet();

        base.FrameworkInitialize(templateControl); 

        if (_traceEnabled != TraceEnable.Default) 
            page.TraceEnabled = (_traceEnabled == TraceEnable.Enable); 
        if (_traceMode != TraceMode.Default)
            page.TraceModeValue = _traceMode; 

        if (_outputCacheData != null) {
            page.AddWrappedFileDependencies(_fileDependencies);
            page.InitOutputCache(_outputCacheData); 
        }
 
        if (_validateRequest) 
            page.Request.ValidateInput();
    } 
}

internal class BuildResultNoCompileUserControl: BuildResultNoCompileTemplateControl {
 
    private PartialCachingAttribute _cachingAttribute;
 
    internal BuildResultNoCompileUserControl(Type baseType, TemplateParser parser) 
        : base(baseType, parser) {
 
        UserControlParser ucParser = (UserControlParser) parser;
        OutputCacheParameters cacheSettings = ucParser.OutputCacheParameters;

        // If the user control has an OutputCache directive, create 
        // a PartialCachingAttribute with the information about it.
        if (cacheSettings != null && cacheSettings.Duration > 0) { 
            _cachingAttribute = new PartialCachingAttribute( 
                cacheSettings.Duration,
                cacheSettings.VaryByParam, 
                cacheSettings.VaryByControl,
                cacheSettings.VaryByCustom,
                cacheSettings.SqlDependency,
                ucParser.FSharedPartialCaching); 
        }
    } 
 
    internal PartialCachingAttribute CachingAttribute {
        get { return _cachingAttribute; } 
    }
}

internal class BuildResultNoCompileMasterPage: BuildResultNoCompileUserControl { 

    private ICollection _placeHolderList; 
 
    internal BuildResultNoCompileMasterPage(Type baseType, TemplateParser parser)
        : base(baseType, parser) { 
        _placeHolderList = ((MasterPageParser)parser).PlaceHolderList;
    }

    // IWebObjectFactory.CreateInstance 
    public override object CreateInstance() {
 
        // Create the master page object that the master 'inherits' from 
        MasterPage masterPage = (MasterPage) base.CreateInstance();
 
        foreach(string placeHolderID in _placeHolderList) {
            masterPage.ContentPlaceHolders.Add(placeHolderID.ToLower(CultureInfo.InvariantCulture));
        }
 
        return masterPage;
    } 
} 

/* 
* This class is used to cache the generated codecompileunit for CBM scenarios,
* when cached on disk, it uses BinaryFormatter to serialize the codecompileunit
* and other compile params.
*/ 
internal class BuildResultCodeCompileUnit : BuildResult {
    private Type _codeDomProviderType; 
    private CodeCompileUnit _codeCompileUnit; 
    private CompilerParameters _compilerParameters;
    private IDictionary _linePragmasTable; 
    private string _cacheKey;

    private const string fileNameAttribute = "CCUpreservationFileName";
 
    internal BuildResultCodeCompileUnit() {
    } 
 
    internal BuildResultCodeCompileUnit(
        Type codeDomProviderType, CodeCompileUnit codeCompileUnit, 
        CompilerParameters compilerParameters, IDictionary linePragmasTable) {

        _codeDomProviderType = codeDomProviderType;
        _codeCompileUnit = codeCompileUnit; 
        _compilerParameters = compilerParameters;
        _linePragmasTable = linePragmasTable; 
    } 

    internal Type CodeDomProviderType { 
        get { return _codeDomProviderType; }
    }

    internal CodeCompileUnit CodeCompileUnit { 
        get { return _codeCompileUnit; }
    } 
 
    internal CompilerParameters CompilerParameters {
        get { return _compilerParameters; } 
    }

    internal IDictionary LinePragmasTable {
        get { return _linePragmasTable; } 
    }
 
    internal override bool CacheToDisk { get { return true; } } 

    internal override BuildResultTypeCode GetCode() { 
        return BuildResultTypeCode.BuildResultCodeCompileUnit;
    }

    private string GetPreservationFileName() { 
        return _cacheKey + ".ccu";
    } 
 
    protected override void ComputeHashCode(HashCodeCombiner hashCodeCombiner) {
 
        base.ComputeHashCode(hashCodeCombiner);

        // Make the hash code depend on the relevant contents of the  and  config sections
        CompilationSection compConfig = RuntimeConfig.GetConfig(VirtualPath).Compilation; 

        hashCodeCombiner.AddObject(compConfig.RecompilationHash); 
 
        PagesSection pagesConfig = RuntimeConfig.GetConfig(VirtualPath).Pages;
        hashCodeCombiner.AddObject(Util.GetRecompilationHash(pagesConfig)); 
    }

    internal override void GetPreservedAttributes(PreservationFileReader pfr) {
        base.GetPreservedAttributes(pfr); 

        String _ccuPreservationFileName = pfr.GetAttribute(fileNameAttribute); 
        _ccuPreservationFileName = Path.Combine(HttpRuntime.CodegenDirInternal, _ccuPreservationFileName); 

        Debug.Assert(FileUtil.FileExists(_ccuPreservationFileName)); 

        using (FileStream stream = File.Open(_ccuPreservationFileName, FileMode.Open)) {
            BinaryFormatter formatter = new BinaryFormatter();
 
            _codeCompileUnit = formatter.Deserialize(stream) as CodeCompileUnit;
            _codeDomProviderType = (Type)formatter.Deserialize(stream); 
            _compilerParameters = (CompilerParameters)formatter.Deserialize(stream); 
            _linePragmasTable = formatter.Deserialize(stream) as IDictionary;
        } 
    }

    internal void SetCacheKey(string cacheKey) {
        _cacheKey = cacheKey; 
    }
 
    internal override void SetPreservedAttributes(PreservationFileWriter pfw) { 
        base.SetPreservedAttributes(pfw);
        string preservationFileName = GetPreservationFileName(); 

        pfw.SetAttribute(fileNameAttribute, preservationFileName);
        preservationFileName = Path.Combine(HttpRuntime.CodegenDirInternal, preservationFileName);
 
        using (FileStream stream = File.Open(preservationFileName, FileMode.Create)) {
            BinaryFormatter formatter = new BinaryFormatter(); 
 
            if (_codeCompileUnit != null) {
                formatter.Serialize(stream, _codeCompileUnit); 
            }
            else {
                formatter.Serialize(stream, new object());
            } 

            formatter.Serialize(stream, _codeDomProviderType); 
            formatter.Serialize(stream, _compilerParameters); 

            if (_linePragmasTable != null) { 
                formatter.Serialize(stream, _linePragmasTable);
            }
            else {
                formatter.Serialize(stream, new object()); 
            }
        } 
    } 

    internal override void RemoveOutOfDateResources(PreservationFileReader pfr) { 
        // Remove the out-of-date .ccu file
        String ccuPreservationFileName = pfr.GetAttribute(fileNameAttribute);
        ccuPreservationFileName = Path.Combine(HttpRuntime.CodegenDirInternal, ccuPreservationFileName);
 
        File.Delete(ccuPreservationFileName);
    } 
} 

} 


                        

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK