//------------------------------------------------------------------------------
//
// 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,
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;
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, bool ensureIsUpToDate) {
if (!ensureIsUpToDate) {
return true;
}
// 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; }
internal virtual bool HasResultAssembly { get { return ResultAssembly != null; } }
protected virtual bool IsGacAssembly { get { return ResultAssembly.GlobalAssemblyCache; } }
protected virtual string ShortAssemblyName { get { return ResultAssembly.GetName().Name; } }
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);
}
}
}
internal 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 (HasResultAssembly) {
string assemblyName;
if (IsGacAssembly) {
// 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 = ShortAssemblyName;
}
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 = MTConfigUtil.GetCompilationConfig(VirtualPath);
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); }
}
internal override bool HasResultAssembly { get { return _builtType != null; } }
protected override bool IsGacAssembly {
get {
if (IsDelayLoadType) {
return false;
}
else {
return base.IsGacAssembly;
}
}
}
protected override string ShortAssemblyName {
get {
var delayLoadType = ResultType as DelayLoadType;
if (delayLoadType != null) {
return delayLoadType.AssemblyName;
}
else {
return base.ShortAssemblyName;
}
}
}
private Type _builtType;
internal Type ResultType {
get { return _builtType; }
set { _builtType = value; }
}
private string FullResultTypeName {
get {
var delayLoadType = ResultType as DelayLoadType;
if (delayLoadType != null) {
return delayLoadType.TypeName;
}
else {
return ResultType.FullName;
}
}
}
internal bool IsDelayLoadType { get { return ResultType is DelayLoadType; } }
static internal bool UsesDelayLoadType(BuildResult result) {
BuildResultCompiledType buildResultCompiledType = result as BuildResultCompiledType;
if (buildResultCompiledType != null) {
return buildResultCompiledType.IsDelayLoadType;
}
else {
return false;
}
}
// 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", FullResultTypeName);
}
}
/*
* 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 = MTConfigUtil.GetPagesConfig(VirtualPath);
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