Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / xsp / System / Web / Compilation / AssemblyBuilder.cs / 1 / AssemblyBuilder.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Web.Compilation { using System; using System.Security.Permissions; using System.IO; using System.Collections; using System.Collections.Specialized; using System.Collections.Generic; using System.Reflection; using System.Text; using System.Globalization; using System.Security; using System.Security.Cryptography; using System.Xml; using System.Xml.Schema; using System.CodeDom; using System.CodeDom.Compiler; using System.Web.Hosting; using System.Web.Util; using System.Web.UI; using System.Web.Configuration; using System.Web.Management; /* * This class is used to handle a single compilation using a CodeDom compiler. * It is instantiated via CompilerType.CreateAssemblyBuilder. */ [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] public class AssemblyBuilder { private CompilationSection _compConfig; // Field relating to the checksum calculation private static HashAlgorithm s_md5HashAlgorithm; private static Guid s_hashMD5Guid; // List of BuildProviders involved in this compilation // The key is either a virtual path, or the BuildProvider itself if // it doesn't give us a virtual path. // The value is the BuildProvider. private Hashtable _buildProviders = new Hashtable(StringComparer.OrdinalIgnoreCase); internal ICollection BuildProviders { get { return _buildProviders.Values; } } // List of physical source files to be compiled private StringSet _sourceFiles = new StringSet(); // CodeCompileUnit to hold various top level things we need to generate private CodeCompileUnit _miscCodeCompileUnit; // List of physical embedded resource files to be compiled private StringSet _embeddedResourceFiles; // The set of assemblies that we will be linked with private AssemblySet _initialReferencedAssemblies; // The additional set of assemblies that we will be linked with, and that are // requested by various BuildProviders. We need to keep them separate to avoid // having BuildProviders see assemblies that were requested by earlier providers, // which would lead to unpredictable behavior (since the order is arbitrary) private AssemblySet _additionalReferencedAssemblies; internal CodeDomProvider _codeProvider; private Hashtable _buildProviderToSourceFileMap; // The type of CodeDom compiler (i.e. language, flags) private CompilerType _compilerType; internal Type CodeDomProviderType { get { return _compilerType.CodeDomProviderType; } } // Used to generate fast Type factories private ObjectFactoryCodeDomTreeGenerator _objectFactoryGenerator; private StringResourceBuilder _stringResourceBuilder; internal StringResourceBuilder StringResourceBuilder { get { if (_stringResourceBuilder == null) _stringResourceBuilder = new StringResourceBuilder(); return _stringResourceBuilder; } } // Used to create temporary source files private TempFileCollection _tempFiles = new TempFileCollection(HttpRuntime.CodegenDirInternal); private int _fileCount; private string _cultureName; internal string CultureName { get { return _cultureName; } set { _cultureName = value; } } private string _outputAssemblyName; private string OutputAssemblyName { get { if (_outputAssemblyName == null) { // If we don't have the assembly name, we should never have a culture Debug.Assert(CultureName == null); // If the assembly name was not specified, use a generated one based on the TempFileCollection. // But prefix it with a fixed token, to make it easier to recognize the assembly (DevDiv 36625) string basePath = _tempFiles.BasePath; string baseFileName = Path.GetFileName(basePath); _outputAssemblyName = BuildManager.WebAssemblyNamePrefix + baseFileName; } return _outputAssemblyName; } } private int _maxBatchSize; private long _maxBatchGeneratedFileSize; private long _totalFileLength; private CaseInsensitiveStringSet _registeredTypeNames; internal bool ContainsTypeNames(ICollection typeNames) { if (_registeredTypeNames != null && typeNames != null) { foreach (String typeName in typeNames) { if (_registeredTypeNames.Contains(typeName)) { return true; } } } return false; } internal void AddTypeNames(ICollection typeNames) { if (typeNames == null) { return; } if (_registeredTypeNames == null) { _registeredTypeNames = new CaseInsensitiveStringSet(); } _registeredTypeNames.AddCollection(typeNames); } internal AssemblyBuilder(CompilationSection compConfig, ICollection referencedAssemblies, CompilerType compilerType, string outputAssemblyName) { _compConfig = compConfig; _outputAssemblyName = outputAssemblyName; // Clone the referenced assemblies _initialReferencedAssemblies = AssemblySet.Create(referencedAssemblies); // We need to clone it to avoid modifying the original (VSWhidbey 338935) _compilerType = compilerType.Clone(); if (BuildManager.PrecompilingWithDebugInfo) { // If the precompile flag indicates force debug, always compile as debug _compilerType.CompilerParameters.IncludeDebugInformation = true; } else if (BuildManager.PrecompilingForDeployment) { // If we're precompiling the app, never compile in debug mode (VSWhidbey 178377) _compilerType.CompilerParameters.IncludeDebugInformation = false; } else if (DeploymentSection.RetailInternal) { // If we're in retail deployment mode, always turn off debug (DevDiv 36396) _compilerType.CompilerParameters.IncludeDebugInformation = false; } else if (_compConfig.AssemblyPostProcessorTypeInternal != null) { // If an IAssemblyPostProcessor is registered always compile as debug _compilerType.CompilerParameters.IncludeDebugInformation = true; } // _tempFiles.KeepFiles = _compilerType.CompilerParameters.IncludeDebugInformation; _codeProvider = CompilationUtil.CreateCodeDomProviderNonPublic( _compilerType.CodeDomProviderType); _maxBatchSize = _compConfig.MaxBatchSize; _maxBatchGeneratedFileSize = _compConfig.MaxBatchGeneratedFileSize * 1024; } // Beginning of public contract ////// Adds an assembly that will be referenced during compilation. /// public void AddAssemblyReference(Assembly a) { if (_additionalReferencedAssemblies == null) _additionalReferencedAssemblies = new AssemblySet(); _additionalReferencedAssemblies.Add(a); } ////// Adds an assembly that will be referenced during compilation. Also adds the /// assembly the the ReferencedAssemblies list in the CodeCompileUnit. /// internal void AddAssemblyReference(Assembly a, CodeCompileUnit ccu) { AddAssemblyReference(a); Util.AddAssemblyToStringCollection(a, ccu.ReferencedAssemblies); } ////// Creates a new source file that will be added to the compilation. See the public overload /// method for detail. /// internal virtual TextWriter CreateCodeFile(BuildProvider buildProvider, out string filename) { string generatedFilePath = GetTempFilePhysicalPath(_codeProvider.FileExtension); filename = generatedFilePath; if (buildProvider != null) { if (_buildProviderToSourceFileMap == null) _buildProviderToSourceFileMap = new Hashtable(); _buildProviderToSourceFileMap[buildProvider] = generatedFilePath; buildProvider.SetContributedCode(); } _sourceFiles.Add(generatedFilePath); Stream temp = new FileStream(generatedFilePath, FileMode.Create, FileAccess.Write, FileShare.Read); return new StreamWriter(temp, Encoding.UTF8); } ////// Creates a new source file that will be added to the compilation. The build provider /// can write source code to this file using the returned TextWriter. /// The build provider should close the TextWriter when it is done writing to it. /// The build provider should pass itself as a parameter to this method. /// public TextWriter CreateCodeFile(BuildProvider buildProvider) { // Ignore the unused filename param. string filename; return CreateCodeFile(buildProvider, out filename); } // Punting this method for the sake of simplifying the API, as the same thing can be // achieved with the other methods (with a bit more work). #if UNUSED ////// Returns the physical path to a source file that will be included in the /// compilation. Note that the file is not actually created. It is up to the /// build provider to do this. /// The source file has the correct extension for the target language. /// The build provider should pass itself as a parameter to this method. /// public string GetCodeFilePhysicalPath(BuildProvider buildProvider) { string generatedFilePath = GetTempFilePhysicalPath(_codeProvider.FileExtension); _sourceFiles.Add(generatedFilePath); return generatedFilePath; } #endif // Indicates whether the assemblyBuilder has reached its capacity limit. internal bool IsBatchFull { get { return (_sourceFiles.Count >= _maxBatchSize) || (_totalFileLength >= _maxBatchGeneratedFileSize); } } ////// Adds a CodeCompileUnit to the compilation. This is typically used as an /// alternative to CreateSourceFile, by providers who are CodeDOM aware. /// The build provider should pass itself as a parameter to this method. /// public void AddCodeCompileUnit(BuildProvider buildProvider, CodeCompileUnit compileUnit) { // Add a checksum pragma to the compile unit if appropriate AddChecksumPragma(buildProvider, compileUnit); // Add all the referenced assemblies to the CodeCompileUnit in case the CodeDom // provider needs them for code generation Util.AddAssembliesToStringCollection(_initialReferencedAssemblies, compileUnit.ReferencedAssemblies); // Merge the _additionalReferencedAssemblies from individul build providers Util.AddAssembliesToStringCollection(_additionalReferencedAssemblies, compileUnit.ReferencedAssemblies); String filename; // Revert impersonation when generating source code in the codegen dir (VSWhidbey 176576) using (new ProcessImpersonationContext()) { TextWriter writer = CreateCodeFile(buildProvider, out filename); try { _codeProvider.GenerateCodeFromCompileUnit(compileUnit, writer, null /*CodeGeneratorOptions*/); } finally { writer.Flush(); writer.Close(); } } if (filename != null) { FileInfo info = new FileInfo(filename); _totalFileLength += info.Length; } } ////// Tell the host about a type that is being generated. This allows the host /// To generate a fast object factory for it. /// public void GenerateTypeFactory(string typeName) { // Create the object factory generator on demand if (_objectFactoryGenerator == null) { _objectFactoryGenerator = new ObjectFactoryCodeDomTreeGenerator(OutputAssemblyName); } // Add a method to fast create this type _objectFactoryGenerator.AddFactoryMethod(typeName); } ////// Creates a new resource that will be added to the compilation. The build provider /// can write to it using the returned Stream. /// The build provider should close the Stream when it is done writing to it. /// The build provider should pass itself as a parameter to this method. /// public Stream CreateEmbeddedResource(BuildProvider buildProvider, string name) { // Make sure it's just a valid simple file name if (!Util.IsValidFileName(name)) { throw new ArgumentException(null, name); } string resourceFile = Path.Combine(_tempFiles.TempDir, name); _tempFiles.AddFile(resourceFile, _tempFiles.KeepFiles); if (_embeddedResourceFiles == null) _embeddedResourceFiles = new StringSet(); _embeddedResourceFiles.Add(resourceFile); return File.OpenWrite(resourceFile); } ////// Returns a CodeDomProvider that the build provider can use to generate a CodeCompileUnit. /// public CodeDomProvider CodeDomProvider { get { return _codeProvider; } } private string _tempFilePhysicalPathPrefix; private string TempFilePhysicalPathPrefix { get { if (_tempFilePhysicalPathPrefix == null) { _tempFilePhysicalPathPrefix = Path.Combine(_tempFiles.TempDir, OutputAssemblyName) + "."; // Append the culture name to avoid naming conflicts if (CultureName != null) { _tempFilePhysicalPathPrefix += CultureName + "_"; } } return _tempFilePhysicalPathPrefix; } } ////// Returns the physical path to a temporary file that the build provider /// can use for intermediate results. Note that the file is not actually /// created. It is up to the build provider to do this. /// The temp file's extension is passed in by the build provider. /// The file is automatically deleted after the compilation, so the /// build provider does not need to explicitly delete it. /// public string GetTempFilePhysicalPath(string extension) { // Do the right thing depending on whether the extension include the starting '.' string tempPath; if (!String.IsNullOrEmpty(extension) && extension[0] == '.') { tempPath = TempFilePhysicalPathPrefix + ((_fileCount++) + extension); } else { tempPath = TempFilePhysicalPathPrefix + ((_fileCount++) + "." + extension); } _tempFiles.AddFile(tempPath, _tempFiles.KeepFiles); InternalSecurityPermissions.PathDiscovery(tempPath).Demand(); return tempPath; } // End of public contract private void AddCompileWithBuildProvider(VirtualPath virtualPath, BuildProvider owningBuildProvider) { BuildProvider buildProvider = BuildManager.CreateBuildProvider(virtualPath, _compConfig, _initialReferencedAssemblies, true /*failIfUnknown*/); // Since it's referenced via compileWith, it doesn't need its own build result buildProvider.SetNoBuildResult(); // If it's a CompileWith provider, remember the main provider SourceFileBuildProvider sourceBuildProvider = buildProvider as SourceFileBuildProvider; if (sourceBuildProvider != null) sourceBuildProvider.OwningBuildProvider = owningBuildProvider; AddBuildProvider(buildProvider); } internal virtual void AddBuildProvider(BuildProvider buildProvider) { // By default, use the build provider itself as the key object hashtableKey = buildProvider; // Keep track of the build provider's virtual path, if any if (buildProvider.VirtualPath != null) { // It has a virtual path, so use that as the key hashtableKey = buildProvider.VirtualPath; // If we already had it, ignore it. This can happen when there is a user control // with a code beside in App_Code (VSWhidbey 481426) if (_buildProviders.ContainsKey(hashtableKey)) return; } _buildProviders[hashtableKey] = buildProvider; // Ask the provider to generate the code // If it throws an Xml exception, extra the relevant info and turn it // into our own ParseException try { buildProvider.GenerateCode(this); } catch (XmlException e) { throw new HttpParseException(e.Message, null /*innerException*/, buildProvider.VirtualPath, null /*sourceCode*/, e.LineNumber); } catch (XmlSchemaException e) { throw new HttpParseException(e.Message, null /*innerException*/, buildProvider.VirtualPath, null /*sourceCode*/, e.LineNumber); } catch (Exception e) { throw new HttpParseException(e.Message, e, buildProvider.VirtualPath, null /*sourceCode*/, 1); } // Handle any 'compileWith' dependencies, i.e. files that must be compiled // within the same assembly as the current file InternalBuildProvider internalBuildProvider = buildProvider as InternalBuildProvider; if (internalBuildProvider != null) { ICollection compileWith = internalBuildProvider.GetCompileWithDependencies(); if (compileWith != null) { foreach (VirtualPath virtualPath in compileWith) { // If we already have it, ignore it if (_buildProviders.ContainsKey(virtualPath.VirtualPathString)) continue; // Add the compileWith dependency to our compilation AddCompileWithBuildProvider(virtualPath, internalBuildProvider); } } } } private void AddAssemblyCultureAttribute() { if (CultureName == null) return; CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(System.Reflection.AssemblyCultureAttribute)), new CodeAttributeArgument[] { new CodeAttributeArgument(new CodePrimitiveExpression(CultureName))}); AddAssemblyAttribute(declaration); } #if UNUSED private void AddComVisibleAttribute() { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(System.Runtime.InteropServices.ComVisibleAttribute)), new CodeAttributeArgument[] { new CodeAttributeArgument(new CodePrimitiveExpression(false))}); AddAssemblyAttribute(declaration); } #endif private void AddAspNetGeneratedCodeAttribute() { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(GeneratedCodeAttribute))); declaration.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression("ASP.NET"))); declaration.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(VersionInfo.SystemWebVersion))); AddAssemblyAttribute(declaration); } private void AddAllowPartiallyTrustedCallersAttribute() { if (BuildManager.CompileWithAllowPartiallyTrustedCallersAttribute) { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(AllowPartiallyTrustedCallersAttribute))); AddAssemblyAttribute(declaration); } } private void AddAssemblyKeyFileAttribute() { if (!String.IsNullOrEmpty(BuildManager.StrongNameKeyFile)) { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(AssemblyKeyFileAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(BuildManager.StrongNameKeyFile))); AddAssemblyAttribute(declaration); } } private void AddAssemblyKeyContainerAttribute() { if (!String.IsNullOrEmpty(BuildManager.StrongNameKeyContainer)) { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(AssemblyKeyNameAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(BuildManager.StrongNameKeyContainer))); AddAssemblyAttribute(declaration); } } private void AddAssemblyDelaySignAttribute() { if (BuildManager.CompileWithDelaySignAttribute) { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(AssemblyDelaySignAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(true))); AddAssemblyAttribute(declaration); } } // Add an assembly level attribute to the assembly private void AddAssemblyAttribute(CodeAttributeDeclaration declaration) { if (_miscCodeCompileUnit == null) _miscCodeCompileUnit = new CodeCompileUnit(); _miscCodeCompileUnit.AssemblyCustomAttributes.Add(declaration); } private void GenerateMiscCodeCompileUnit() { // If there aren't any, return if (_miscCodeCompileUnit == null) return; AddCodeCompileUnit(null /*buildProvider*/, _miscCodeCompileUnit); } // Add a checksum pragma. This is used for improved debugging experience. private void AddChecksumPragma(BuildProvider buildProvider, CodeCompileUnit compileUnit) { // If we can't get a virtual path, do nothing if (buildProvider == null || buildProvider.VirtualPath == null) return; // Only do this if we're compiling in debug mode if (!_compilerType.CompilerParameters.IncludeDebugInformation) return; string physicalPath = HostingEnvironment.MapPathInternal(buildProvider.VirtualPath); // Only do this is the file physically exists, which it would not in the // case of a non-file based VirtualPathProvider. In such case, there is // no point in putting the pragma, since the debugger could not locate // the file anyway. if (!File.Exists(physicalPath)) return; #if !FEATURE_PAL // FEATURE_PAL does not yet support MD5 Crypto // Initialize the MD5 objects on demand if (s_md5HashAlgorithm == null) { s_md5HashAlgorithm = new MD5CryptoServiceProvider(); s_hashMD5Guid = new Guid(0x406ea660, 0x64cf, 0x4c82, 0xb6, 0xf0, 0x42, 0xd4, 0x81, 0x72, 0xa7, 0x99); } CodeChecksumPragma pragma = new CodeChecksumPragma(); if (_compConfig.UrlLinePragmas) { pragma.FileName = ErrorFormatter.MakeHttpLinePragma(buildProvider.VirtualPathObject.VirtualPathString); } else { pragma.FileName = physicalPath; } pragma.ChecksumAlgorithmId = s_hashMD5Guid; // Generate an MD5 hash from the contents of the file using (Stream stream = new FileStream(physicalPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { pragma.ChecksumData = s_md5HashAlgorithm.ComputeHash(stream); } // Add the pragma to the CodeCompileUnit compileUnit.StartDirectives.Add(pragma); #endif } internal CompilerParameters GetCompilerParameters() { CompilerParameters compilParams = _compilerType.CompilerParameters; string dir = _tempFiles.TempDir; // If a culture is set, modify the assembly name and location based on it if (CultureName != null) { dir = Path.Combine(dir, CultureName); Directory.CreateDirectory(dir); compilParams.OutputAssembly = Path.Combine(dir, OutputAssemblyName + ".resources.dll"); } else { compilParams.OutputAssembly = Path.Combine(dir, OutputAssemblyName + ".dll"); } // If such file already exist, try to delete or rename it if (File.Exists(compilParams.OutputAssembly)) Util.RemoveOrRenameFile(compilParams.OutputAssembly); compilParams.TempFiles = _tempFiles; // Create the string resource file (shared by all the pages we're compiling) if (_stringResourceBuilder != null && _stringResourceBuilder.HasStrings) { string resFileName = _tempFiles.AddExtension("res"); _stringResourceBuilder.CreateResourceFile(resFileName); compilParams.Win32Resource = resFileName; } // Add all the embedded resources to the compilParams if (_embeddedResourceFiles != null) { foreach (string aname in _embeddedResourceFiles) compilParams.EmbeddedResources.Add(aname); } // Merge the two sets of assemblies if (_additionalReferencedAssemblies != null) { foreach (Assembly assembly in _additionalReferencedAssemblies) { _initialReferencedAssemblies.Add(assembly); } } // Add all the referenced assemblies to the compilParams Util.AddAssembliesToStringCollection(_initialReferencedAssemblies, compilParams.ReferencedAssemblies); // Make any fix up adjustments to the CompilerParameters to work around some issues FixUpCompilerParameters(_compilerType.CodeDomProviderType, compilParams); return compilParams; } static string s_vbImportsString; private static void AddVBGlobalNamespaceImports(CompilerParameters compilParams) { // Put together the VB import string on demand if (s_vbImportsString == null) { PagesSection pagesConfig = RuntimeConfig.GetAppConfig().Pages; if (pagesConfig.Namespaces == null) { s_vbImportsString = String.Empty; } else { StringBuilder sb = new StringBuilder(); sb.Append("/imports:"); bool nextItemNeedsComma = false; // Auto-import Microsoft.VisualBasic is needed if (pagesConfig.Namespaces.AutoImportVBNamespace) { sb.Append("Microsoft.VisualBasic"); nextItemNeedsComma = true; } // Add all the namespaces from the configsection foreach (NamespaceInfo entry in pagesConfig.Namespaces) { // If there was a previous entry, we need a comma separator if (nextItemNeedsComma) sb.Append(','); sb.Append(entry.Namespace); nextItemNeedsComma = true; } s_vbImportsString = sb.ToString(); } } // Prepend it to the compilerOptions if (s_vbImportsString.Length > 0) { if (compilParams.CompilerOptions == null) compilParams.CompilerOptions = s_vbImportsString; else compilParams.CompilerOptions = s_vbImportsString + " " + compilParams.CompilerOptions; } } // Command line string for My.* support private const string MySupport = @"/define:_MYTYPE=\""Web\"""; private static void AddVBMyFlags(CompilerParameters compilParams) { // Prepend it to the compilerOptions if (compilParams.CompilerOptions == null) compilParams.CompilerOptions = MySupport; else compilParams.CompilerOptions = MySupport + " " + compilParams.CompilerOptions; } internal static void FixUpCompilerParameters(Type codeDomProviderType, CompilerParameters compilParams) { // If C#, remove the warning that complains about variables that start with "__" // Also ignore warning that complains about assemblyKeyName and delaysign // Also ignore warning about assuming assembly versions matching (CS1701, DevDiv 137847, warning about System.Web.Extensions v1.0 matching v3.5) if (codeDomProviderType == typeof(Microsoft.CSharp.CSharpCodeProvider)) { CodeDomUtility.PrependCompilerOption(compilParams, "/nowarn:1659;1699;1701"); } else if (codeDomProviderType == typeof(Microsoft.VisualBasic.VBCodeProvider)) { // If VB, add all the imported namespaces on the command line (DevDiv 21499). // This is VB only because other languages don't support global command line // namespace imports. AddVBGlobalNamespaceImports(compilParams); // Add any command line flags needed to support the My.* feature AddVBMyFlags(compilParams); } ProcessProviderOptions(codeDomProviderType, compilParams); FixTreatWarningsAsErrors(codeDomProviderType, compilParams); // Add CodeAnalysis symbol if required by client. if (BuildManager.PrecompilingWithCodeAnalysisSymbol) { CodeDomUtility.PrependCompilerOption(compilParams, "/define:CODE_ANALYSIS"); } } // DevDiv 114316 // CodeDom sets TreatWarningAsErrors to true whenever warningLevel is non-zero. // To get warnings only, the workaround is to use /warnaserror- in CompilerOptions. // However this does not work in some cases, as TreatWarningAsErrors set to true still emits // /warnaserror+. // So, whenever the user wants /warnaserror[+|-|numberlist], we explicitly set TreatWarningsAsErrors to false, // so that the /warnaserror+ is not emitted, and the user can specify exactly what is desired. internal static void FixTreatWarningsAsErrors(Type codeDomProviderType, CompilerParameters compilParams) { // Only do so for C# and VB. if (codeDomProviderType != typeof(Microsoft.CSharp.CSharpCodeProvider) && codeDomProviderType != typeof(Microsoft.VisualBasic.VBCodeProvider)) return; if (CultureInfo.InvariantCulture.CompareInfo.IndexOf(compilParams.CompilerOptions, "/warnaserror", CompareOptions.IgnoreCase) >= 0) compilParams.TreatWarningsAsErrors = false; } // Check for OptionInfer and WarnAsError. This is the workaround as use of compilerOptions is not allowed in partial trust. // Devdiv 130325 private static void ProcessProviderOptions(Type codeDomProviderType, CompilerParameters compilParams) { IDictionary providerOptions = CompilationUtil.GetProviderOptions(codeDomProviderType); if (providerOptions == null) return; // For C# and VB, check for WarnAsError if (codeDomProviderType == typeof(Microsoft.VisualBasic.VBCodeProvider) || codeDomProviderType == typeof(Microsoft.CSharp.CSharpCodeProvider)) ProcessBooleanProviderOption("WarnAsError", "/warnaserror+", "/warnaserror-", providerOptions, compilParams); // Only process OptionInfer for v3.5 compiler if (codeDomProviderType == null || !CompilationUtil.IsCompilerVersion35(codeDomProviderType)) return; // For VB, check for OptionInfer if (codeDomProviderType == typeof(Microsoft.VisualBasic.VBCodeProvider)) ProcessBooleanProviderOption("OptionInfer", "/optionInfer+", "/optionInfer-", providerOptions, compilParams); } private static void ProcessBooleanProviderOption(string providerOptionName, string trueCompilerOption, string falseCompilerOption, IDictionary providerOptions, CompilerParameters compilParams) { if (providerOptions == null || compilParams == null) return; Debug.Assert(providerOptionName != null, "providerOptionName should not be null"); Debug.Assert(trueCompilerOption != null, "trueCompilerOption should not be null"); Debug.Assert(falseCompilerOption != null, "falseCompilerOption should not be null"); string providerOptionValue = null; if (!providerOptions.TryGetValue(providerOptionName, out providerOptionValue)) return; if (string.IsNullOrEmpty(providerOptionValue)) throw new System.Configuration.ConfigurationException(SR.GetString(SR.Property_NullOrEmpty, CompilationUtil.CodeDomProviderOptionPath + providerOptionName)); bool value; if (Boolean.TryParse(providerOptionValue, out value)) { // If the value is boolean, insert the compiler options if (value) CodeDomUtility.AppendCompilerOption(compilParams, trueCompilerOption); else CodeDomUtility.AppendCompilerOption(compilParams, falseCompilerOption); } else { // If the value is not boolean, throw an exception throw new System.Configuration.ConfigurationException(SR.GetString(SR.Value_must_be_boolean, CompilationUtil.CodeDomProviderOptionPath + providerOptionName)); } } internal CompilerResults Compile() { // First, check if there is something to compile if (_sourceFiles.Count == 0 && _embeddedResourceFiles == null) return null; // if we have some fast object factories to generate, get the CodeCompileUnit if (_objectFactoryGenerator != null) { _miscCodeCompileUnit = _objectFactoryGenerator.CodeCompileUnit; } // Add a culture attribute if needed AddAssemblyCultureAttribute(); // Add a ComVisible(false) attribute (VSWhidbey 436453) // Actually, don't do it to avoid breaking migrated apps (VSWhidbey 446788) //AddComVisibleAttribute(); // Add an AspNetGeneratedCode attribute to help fxcop ignore some violations (VSWhidbey 437581) AddAspNetGeneratedCodeAttribute(); // Add an AllowPartiallyTrustedCallers attribute to make strong-name assemblies. (Devdiv 39696) AddAllowPartiallyTrustedCallersAttribute(); AddAssemblyDelaySignAttribute(); AddAssemblyKeyFileAttribute(); AddAssemblyKeyContainerAttribute(); // Generate a source file for the misc top level items if needed GenerateMiscCodeCompileUnit(); CompilerParameters compilParams = GetCompilerParameters(); string[] files = new string[_sourceFiles.Count]; _sourceFiles.CopyTo(files, 0); // Increment compilation counter PerfCounters.IncrementCounter(AppPerfCounter.COMPILATIONS); // Raise Web Event WebBaseEvent.RaiseSystemEvent(this, WebEventCodes.ApplicationCompilationStart); HttpContext context = HttpContext.Current; if (context != null) { if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_COMPILE_ENTER, context.WorkerRequest); } CompilerResults results = null; try { try { // Revert impersonation when compiling source code in the codegen dir (VSWhidbey 176576) using (new ProcessImpersonationContext()) { results = _codeProvider.CompileAssemblyFromFile(compilParams, files); } } finally { if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure) && context != null) { string fileNames = null; if (_buildProviders.Count < 20) { IDictionaryEnumerator e = _buildProviders.GetEnumerator(); while(e.MoveNext()) { if (fileNames != null) fileNames += ","; fileNames += e.Key; } } else { fileNames = String.Format(CultureInfo.InstalledUICulture, SR.Resources.GetString(SR.Etw_Batch_Compilation, CultureInfo.InstalledUICulture), new object[1] {_buildProviders.Count}); } string status; if (results != null && (results.NativeCompilerReturnValue != 0 || results.Errors.HasErrors)) status = SR.Resources.GetString(SR.Etw_Failure, CultureInfo.InstalledUICulture); else status = SR.Resources.GetString(SR.Etw_Success, CultureInfo.InstalledUICulture); EtwTrace.Trace(EtwTraceType.ETW_TYPE_COMPILE_LEAVE, context.WorkerRequest, fileNames, status); } } } catch { throw; } // Prevent Exception Filter Security Issue (ASURT 122835) // If an IAssemblyPostProcessor is registered, call it Type postProcessorType = _compConfig.AssemblyPostProcessorTypeInternal; if (postProcessorType != null) { using (IAssemblyPostProcessor postProcessor = (IAssemblyPostProcessor) HttpRuntime.FastCreatePublicInstance(postProcessorType)) { postProcessor.PostProcessAssembly(results.PathToAssembly); } } // Raise Web Event WebBaseEvent.RaiseSystemEvent(this, WebEventCodes.ApplicationCompilationEnd); if (results != null) { // Invalidate an invalid assembly to trigger recompilation InvalidateInvalidAssembly(results, compilParams); // Fix up with line pragmas to account for the http case, and for some special conditions FixUpLinePragmas(results); // If there is a CBM callback, inform it of the errors/warnings if (BuildManager.CBMCallback != null) { foreach (CompilerError error in results.Errors) { BuildManager.CBMCallback.ReportCompilerError(error); } } // If there are errors, increment the relevant perf counters and throw if (results.NativeCompilerReturnValue != 0 || results.Errors.HasErrors) { // Increment the compilation error and total error counters PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_COMPILING); PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_TOTAL); throw new HttpCompileException(results, GetErrorSourceFileContents(results)); } } return results; } private void InvalidateInvalidAssembly(CompilerResults results, CompilerParameters compilParams) { // VSWhidbey 610291 // If target assembly gets locked, we invalidate the assembly, so that it does // not get used, and the next compilation will use a new assembly name. // CS0016 is the error code for "Could not write to output file 'file' -- 'reason'" if (results == null || !results.Errors.HasErrors) return; foreach (CompilerError error in results.Errors) { if (error.IsWarning) continue; if (StringUtil.EqualsIgnoreCase(error.ErrorNumber, "CS0016")){ // Also invalidate the base assembly if this is a localized resource assembly if (CultureName != null) { string dir = _tempFiles.TempDir; string baseAssemblyFile = Path.Combine(dir, OutputAssemblyName + ".dll"); DiskBuildResultCache.TryDeleteFile(new FileInfo(baseAssemblyFile)); } // Invalidate the target assembly DiskBuildResultCache.TryDeleteFile(compilParams.OutputAssembly); } } } /* * Fix up all the source files in the errors in case they are HTTP (VS compiler scenario). * Also, fix the error in case the base class was incorrect in the code beside model */ private void FixUpLinePragmas(CompilerResults results) { CompilerError badBaseClassError = null; // Go through the errors backwards so we can delete them as needed for (int i=results.Errors.Count-1; i>=0; i--) { CompilerError error = results.Errors[i]; string physicalPath = ErrorFormatter.ResolveHttpFileName(error.FileName); // Only replace it by the physical path if it actually exists, which may not // be the case when using a VirtualPathProvider if (File.Exists(physicalPath)) { error.FileName = physicalPath; // If it is our special marker line number, remember it and remove it. // We place the marker at two places: 1) before setting AppRelativeVirtualPath in the constructor, // and 2) before the method FrameworkInitialize. // For the generated method FrameworkInitialize, the method comes one line after // the marker, due to an additional line taken by the DebuggerNonUserCodeAttribute. (DevDiv 175681) if (error.Line == TemplateControlCodeDomTreeGenerator.badBaseClassLineMarker || (error.Line == TemplateControlCodeDomTreeGenerator.badBaseClassLineMarker + 1 && error.ErrorText != null && error.ErrorText.IndexOf("FrameworkInitialize", StringComparison.OrdinalIgnoreCase) >= 0)) { badBaseClassError = error; results.Errors.RemoveAt(i); } else if (error.Line > TemplateControlCodeDomTreeGenerator.badBaseClassLineMarker && error.Line < TemplateControlCodeDomTreeGenerator.badBaseClassLineMarker + 50) { // Also, if within range of it, remove it altogether results.Errors.RemoveAt(i); } } } // If we found our special marker error, we're most likely in a situation where // the class in the code beside file doesn't match the 'inherits' in the aspx/ascx, // or is missing the based type (or has the wrong base type). In that case, change // the error message to make the problem explicit to the user (VSWhidbey 376977/468830) if (badBaseClassError != null) { // Read the content of the code beside file string codeFileContent = Util.StringFromFile(badBaseClassError.FileName); // Search for the partial class declaration within the file. We do this by searching for // the string "partial class" in case insensitive way. This is far from fool proof, but // it covers the common VB and C# cases, and the fallback when not found is reasonable. int classOffset = CultureInfo.InvariantCulture.CompareInfo.IndexOf(codeFileContent, "partial class", CompareOptions.IgnoreCase); if (classOffset >= 0) { // We found it, so figure out the line number from it badBaseClassError.Line = Util.LineCount(codeFileContent, 0, classOffset) + 1; } else { // Otherwise, just use 1. It won't point to the right line, but at least the error // message is helpful badBaseClassError.Line = 1; } // Change the error message to make the situation clear to the user badBaseClassError.ErrorText = SR.GetString(SR.Bad_Base_Class_In_Code_File); badBaseClassError.ErrorNumber = "ASPNET"; // Insert the error at the begining of the collection, since we display the first error. results.Errors.Insert(0, badBaseClassError); } } /* * Attempt to find the generated source file that has the error, and return * its contents as a string (for error reproting purposes). * Note that when debug is false, we set tempFiles.KeepFiles to false, and * all the sources will be gone by the time we get here. I filed VSWhidbey 103673, * to get a solution to this from BCL. */ private string GetErrorSourceFileContents(CompilerResults results) { if (!results.Errors.HasErrors) return null; // Get the physical path of the file that has the error. Note that this could be // either the path to a high level file (e.g. aspx) if pragmas are in play, // or the path to a generated file if there are no pragmas string linePragma = results.Errors[0].FileName; // Attempt to locate the correct build provider BuildProvider buildProvider = GetBuildProviderFromLinePragma(linePragma); if (buildProvider != null) { // Return the generated file for this build provider return GetGeneratedSourceFromBuildProvider(buildProvider); } // If we didn't find it, then we're probably in the no pragma case, in // which case linePragma itself is the generated file return Util.StringFromFileIfExists(linePragma); } internal string GetGeneratedSourceFromBuildProvider(BuildProvider buildProvider) { // Return the generated file content for this build provider string generatedFilePath = (string) _buildProviderToSourceFileMap[buildProvider]; return Util.StringFromFileIfExists(generatedFilePath); } internal BuildProvider GetBuildProviderFromLinePragma(string linePragma) { BuildProvider buildProvider = GetBuildProviderFromLinePragmaInternal(linePragma); // If it's a CompileWith provider, return the main provider instead SourceFileBuildProvider sourceBuildProvider = buildProvider as SourceFileBuildProvider; if (sourceBuildProvider != null) buildProvider = sourceBuildProvider.OwningBuildProvider; return buildProvider; } private BuildProvider GetBuildProviderFromLinePragmaInternal(string linePragma) { // If we didn't keep track of any generated files, we can't do much if (_buildProviderToSourceFileMap == null) return null; // Check if it's an http line pragma, from which we can get a VirtualPath string virtualPath = ErrorFormatter.GetVirtualPathFromHttpLinePragma(linePragma); // First, look for the pragma case foreach (BuildProvider buildProvider in BuildProviders) { // If the build provider can't give us a virtual path, skip it if (buildProvider.VirtualPath == null) continue; // If we got a virtual path, use it to locate the correct BuildProvider if (virtualPath != null) { if (StringUtil.EqualsIgnoreCase(virtualPath, buildProvider.VirtualPath)) { return buildProvider; } continue; } // Otherwise, work with the physical path string physicalPath = HostingEnvironment.MapPathInternal(buildProvider.VirtualPath); if (StringUtil.EqualsIgnoreCase(linePragma, physicalPath)) { return buildProvider; } } return null; } } /* * This class is used intead of AssemblyBuilder when handling * ClientBuildManager.GetCodeDirectoryInformation * It is instantiated via CompilerType.CreateAssemblyBuilder. */ internal class CbmCodeGeneratorBuildProviderHost: AssemblyBuilder { private string _generatedFilesDir; internal CbmCodeGeneratorBuildProviderHost(CompilationSection compConfig, ICollection referencedAssemblies, CompilerType compilerType, string generatedFilesDir, string outputAssemblyName) : base(compConfig, referencedAssemblies, compilerType, outputAssemblyName) { // Wipe out any existing directory, and recreate it // This is where we will put generated source files if (Directory.Exists(generatedFilesDir)) { // Delete all the files in the directory foreach (FileData fileData in FileEnumerator.Create(generatedFilesDir)) { // It should only contain files Debug.Assert(!fileData.IsDirectory); if (fileData.IsDirectory) continue; Debug.Trace("CbmCodeGeneratorBuildProviderHost", "Deleting " + fileData.FullName); File.Delete(fileData.FullName); } } // Create it to make sure it exists Directory.CreateDirectory(generatedFilesDir); _generatedFilesDir = generatedFilesDir; } internal override TextWriter CreateCodeFile(BuildProvider buildProvider, out string filename) { // use GetCacheKeyFromVirtualPath to get a file name that looks like // the original file, but is guaranteed unique across different virtual dirs. string generatedCodeFile = BuildManager.GetCacheKeyFromVirtualPath( buildProvider.VirtualPathObject); generatedCodeFile = Path.Combine(_generatedFilesDir, generatedCodeFile); generatedCodeFile = FileUtil.TruncatePathIfNeeded(generatedCodeFile, 10 /*length of extension */); generatedCodeFile = generatedCodeFile + "." + _codeProvider.FileExtension; filename = generatedCodeFile; BuildManager.GenerateFileTable[buildProvider.VirtualPathObject.VirtualPathStringNoTrailingSlash] = generatedCodeFile; Debug.Trace("CbmCodeGeneratorBuildProviderHost", "Generating " + generatedCodeFile); Stream temp = new FileStream(generatedCodeFile, FileMode.Create, FileAccess.Write, FileShare.Read); return new StreamWriter(temp, Encoding.UTF8); } internal override void AddBuildProvider(BuildProvider buildProvider) { // Skip source files, since their code generation is an identity transform if (buildProvider is SourceFileBuildProvider) return; base.AddBuildProvider(buildProvider); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Web.Compilation { using System; using System.Security.Permissions; using System.IO; using System.Collections; using System.Collections.Specialized; using System.Collections.Generic; using System.Reflection; using System.Text; using System.Globalization; using System.Security; using System.Security.Cryptography; using System.Xml; using System.Xml.Schema; using System.CodeDom; using System.CodeDom.Compiler; using System.Web.Hosting; using System.Web.Util; using System.Web.UI; using System.Web.Configuration; using System.Web.Management; /* * This class is used to handle a single compilation using a CodeDom compiler. * It is instantiated via CompilerType.CreateAssemblyBuilder. */ [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] public class AssemblyBuilder { private CompilationSection _compConfig; // Field relating to the checksum calculation private static HashAlgorithm s_md5HashAlgorithm; private static Guid s_hashMD5Guid; // List of BuildProviders involved in this compilation // The key is either a virtual path, or the BuildProvider itself if // it doesn't give us a virtual path. // The value is the BuildProvider. private Hashtable _buildProviders = new Hashtable(StringComparer.OrdinalIgnoreCase); internal ICollection BuildProviders { get { return _buildProviders.Values; } } // List of physical source files to be compiled private StringSet _sourceFiles = new StringSet(); // CodeCompileUnit to hold various top level things we need to generate private CodeCompileUnit _miscCodeCompileUnit; // List of physical embedded resource files to be compiled private StringSet _embeddedResourceFiles; // The set of assemblies that we will be linked with private AssemblySet _initialReferencedAssemblies; // The additional set of assemblies that we will be linked with, and that are // requested by various BuildProviders. We need to keep them separate to avoid // having BuildProviders see assemblies that were requested by earlier providers, // which would lead to unpredictable behavior (since the order is arbitrary) private AssemblySet _additionalReferencedAssemblies; internal CodeDomProvider _codeProvider; private Hashtable _buildProviderToSourceFileMap; // The type of CodeDom compiler (i.e. language, flags) private CompilerType _compilerType; internal Type CodeDomProviderType { get { return _compilerType.CodeDomProviderType; } } // Used to generate fast Type factories private ObjectFactoryCodeDomTreeGenerator _objectFactoryGenerator; private StringResourceBuilder _stringResourceBuilder; internal StringResourceBuilder StringResourceBuilder { get { if (_stringResourceBuilder == null) _stringResourceBuilder = new StringResourceBuilder(); return _stringResourceBuilder; } } // Used to create temporary source files private TempFileCollection _tempFiles = new TempFileCollection(HttpRuntime.CodegenDirInternal); private int _fileCount; private string _cultureName; internal string CultureName { get { return _cultureName; } set { _cultureName = value; } } private string _outputAssemblyName; private string OutputAssemblyName { get { if (_outputAssemblyName == null) { // If we don't have the assembly name, we should never have a culture Debug.Assert(CultureName == null); // If the assembly name was not specified, use a generated one based on the TempFileCollection. // But prefix it with a fixed token, to make it easier to recognize the assembly (DevDiv 36625) string basePath = _tempFiles.BasePath; string baseFileName = Path.GetFileName(basePath); _outputAssemblyName = BuildManager.WebAssemblyNamePrefix + baseFileName; } return _outputAssemblyName; } } private int _maxBatchSize; private long _maxBatchGeneratedFileSize; private long _totalFileLength; private CaseInsensitiveStringSet _registeredTypeNames; internal bool ContainsTypeNames(ICollection typeNames) { if (_registeredTypeNames != null && typeNames != null) { foreach (String typeName in typeNames) { if (_registeredTypeNames.Contains(typeName)) { return true; } } } return false; } internal void AddTypeNames(ICollection typeNames) { if (typeNames == null) { return; } if (_registeredTypeNames == null) { _registeredTypeNames = new CaseInsensitiveStringSet(); } _registeredTypeNames.AddCollection(typeNames); } internal AssemblyBuilder(CompilationSection compConfig, ICollection referencedAssemblies, CompilerType compilerType, string outputAssemblyName) { _compConfig = compConfig; _outputAssemblyName = outputAssemblyName; // Clone the referenced assemblies _initialReferencedAssemblies = AssemblySet.Create(referencedAssemblies); // We need to clone it to avoid modifying the original (VSWhidbey 338935) _compilerType = compilerType.Clone(); if (BuildManager.PrecompilingWithDebugInfo) { // If the precompile flag indicates force debug, always compile as debug _compilerType.CompilerParameters.IncludeDebugInformation = true; } else if (BuildManager.PrecompilingForDeployment) { // If we're precompiling the app, never compile in debug mode (VSWhidbey 178377) _compilerType.CompilerParameters.IncludeDebugInformation = false; } else if (DeploymentSection.RetailInternal) { // If we're in retail deployment mode, always turn off debug (DevDiv 36396) _compilerType.CompilerParameters.IncludeDebugInformation = false; } else if (_compConfig.AssemblyPostProcessorTypeInternal != null) { // If an IAssemblyPostProcessor is registered always compile as debug _compilerType.CompilerParameters.IncludeDebugInformation = true; } // _tempFiles.KeepFiles = _compilerType.CompilerParameters.IncludeDebugInformation; _codeProvider = CompilationUtil.CreateCodeDomProviderNonPublic( _compilerType.CodeDomProviderType); _maxBatchSize = _compConfig.MaxBatchSize; _maxBatchGeneratedFileSize = _compConfig.MaxBatchGeneratedFileSize * 1024; } // Beginning of public contract ////// Adds an assembly that will be referenced during compilation. /// public void AddAssemblyReference(Assembly a) { if (_additionalReferencedAssemblies == null) _additionalReferencedAssemblies = new AssemblySet(); _additionalReferencedAssemblies.Add(a); } ////// Adds an assembly that will be referenced during compilation. Also adds the /// assembly the the ReferencedAssemblies list in the CodeCompileUnit. /// internal void AddAssemblyReference(Assembly a, CodeCompileUnit ccu) { AddAssemblyReference(a); Util.AddAssemblyToStringCollection(a, ccu.ReferencedAssemblies); } ////// Creates a new source file that will be added to the compilation. See the public overload /// method for detail. /// internal virtual TextWriter CreateCodeFile(BuildProvider buildProvider, out string filename) { string generatedFilePath = GetTempFilePhysicalPath(_codeProvider.FileExtension); filename = generatedFilePath; if (buildProvider != null) { if (_buildProviderToSourceFileMap == null) _buildProviderToSourceFileMap = new Hashtable(); _buildProviderToSourceFileMap[buildProvider] = generatedFilePath; buildProvider.SetContributedCode(); } _sourceFiles.Add(generatedFilePath); Stream temp = new FileStream(generatedFilePath, FileMode.Create, FileAccess.Write, FileShare.Read); return new StreamWriter(temp, Encoding.UTF8); } ////// Creates a new source file that will be added to the compilation. The build provider /// can write source code to this file using the returned TextWriter. /// The build provider should close the TextWriter when it is done writing to it. /// The build provider should pass itself as a parameter to this method. /// public TextWriter CreateCodeFile(BuildProvider buildProvider) { // Ignore the unused filename param. string filename; return CreateCodeFile(buildProvider, out filename); } // Punting this method for the sake of simplifying the API, as the same thing can be // achieved with the other methods (with a bit more work). #if UNUSED ////// Returns the physical path to a source file that will be included in the /// compilation. Note that the file is not actually created. It is up to the /// build provider to do this. /// The source file has the correct extension for the target language. /// The build provider should pass itself as a parameter to this method. /// public string GetCodeFilePhysicalPath(BuildProvider buildProvider) { string generatedFilePath = GetTempFilePhysicalPath(_codeProvider.FileExtension); _sourceFiles.Add(generatedFilePath); return generatedFilePath; } #endif // Indicates whether the assemblyBuilder has reached its capacity limit. internal bool IsBatchFull { get { return (_sourceFiles.Count >= _maxBatchSize) || (_totalFileLength >= _maxBatchGeneratedFileSize); } } ////// Adds a CodeCompileUnit to the compilation. This is typically used as an /// alternative to CreateSourceFile, by providers who are CodeDOM aware. /// The build provider should pass itself as a parameter to this method. /// public void AddCodeCompileUnit(BuildProvider buildProvider, CodeCompileUnit compileUnit) { // Add a checksum pragma to the compile unit if appropriate AddChecksumPragma(buildProvider, compileUnit); // Add all the referenced assemblies to the CodeCompileUnit in case the CodeDom // provider needs them for code generation Util.AddAssembliesToStringCollection(_initialReferencedAssemblies, compileUnit.ReferencedAssemblies); // Merge the _additionalReferencedAssemblies from individul build providers Util.AddAssembliesToStringCollection(_additionalReferencedAssemblies, compileUnit.ReferencedAssemblies); String filename; // Revert impersonation when generating source code in the codegen dir (VSWhidbey 176576) using (new ProcessImpersonationContext()) { TextWriter writer = CreateCodeFile(buildProvider, out filename); try { _codeProvider.GenerateCodeFromCompileUnit(compileUnit, writer, null /*CodeGeneratorOptions*/); } finally { writer.Flush(); writer.Close(); } } if (filename != null) { FileInfo info = new FileInfo(filename); _totalFileLength += info.Length; } } ////// Tell the host about a type that is being generated. This allows the host /// To generate a fast object factory for it. /// public void GenerateTypeFactory(string typeName) { // Create the object factory generator on demand if (_objectFactoryGenerator == null) { _objectFactoryGenerator = new ObjectFactoryCodeDomTreeGenerator(OutputAssemblyName); } // Add a method to fast create this type _objectFactoryGenerator.AddFactoryMethod(typeName); } ////// Creates a new resource that will be added to the compilation. The build provider /// can write to it using the returned Stream. /// The build provider should close the Stream when it is done writing to it. /// The build provider should pass itself as a parameter to this method. /// public Stream CreateEmbeddedResource(BuildProvider buildProvider, string name) { // Make sure it's just a valid simple file name if (!Util.IsValidFileName(name)) { throw new ArgumentException(null, name); } string resourceFile = Path.Combine(_tempFiles.TempDir, name); _tempFiles.AddFile(resourceFile, _tempFiles.KeepFiles); if (_embeddedResourceFiles == null) _embeddedResourceFiles = new StringSet(); _embeddedResourceFiles.Add(resourceFile); return File.OpenWrite(resourceFile); } ////// Returns a CodeDomProvider that the build provider can use to generate a CodeCompileUnit. /// public CodeDomProvider CodeDomProvider { get { return _codeProvider; } } private string _tempFilePhysicalPathPrefix; private string TempFilePhysicalPathPrefix { get { if (_tempFilePhysicalPathPrefix == null) { _tempFilePhysicalPathPrefix = Path.Combine(_tempFiles.TempDir, OutputAssemblyName) + "."; // Append the culture name to avoid naming conflicts if (CultureName != null) { _tempFilePhysicalPathPrefix += CultureName + "_"; } } return _tempFilePhysicalPathPrefix; } } ////// Returns the physical path to a temporary file that the build provider /// can use for intermediate results. Note that the file is not actually /// created. It is up to the build provider to do this. /// The temp file's extension is passed in by the build provider. /// The file is automatically deleted after the compilation, so the /// build provider does not need to explicitly delete it. /// public string GetTempFilePhysicalPath(string extension) { // Do the right thing depending on whether the extension include the starting '.' string tempPath; if (!String.IsNullOrEmpty(extension) && extension[0] == '.') { tempPath = TempFilePhysicalPathPrefix + ((_fileCount++) + extension); } else { tempPath = TempFilePhysicalPathPrefix + ((_fileCount++) + "." + extension); } _tempFiles.AddFile(tempPath, _tempFiles.KeepFiles); InternalSecurityPermissions.PathDiscovery(tempPath).Demand(); return tempPath; } // End of public contract private void AddCompileWithBuildProvider(VirtualPath virtualPath, BuildProvider owningBuildProvider) { BuildProvider buildProvider = BuildManager.CreateBuildProvider(virtualPath, _compConfig, _initialReferencedAssemblies, true /*failIfUnknown*/); // Since it's referenced via compileWith, it doesn't need its own build result buildProvider.SetNoBuildResult(); // If it's a CompileWith provider, remember the main provider SourceFileBuildProvider sourceBuildProvider = buildProvider as SourceFileBuildProvider; if (sourceBuildProvider != null) sourceBuildProvider.OwningBuildProvider = owningBuildProvider; AddBuildProvider(buildProvider); } internal virtual void AddBuildProvider(BuildProvider buildProvider) { // By default, use the build provider itself as the key object hashtableKey = buildProvider; // Keep track of the build provider's virtual path, if any if (buildProvider.VirtualPath != null) { // It has a virtual path, so use that as the key hashtableKey = buildProvider.VirtualPath; // If we already had it, ignore it. This can happen when there is a user control // with a code beside in App_Code (VSWhidbey 481426) if (_buildProviders.ContainsKey(hashtableKey)) return; } _buildProviders[hashtableKey] = buildProvider; // Ask the provider to generate the code // If it throws an Xml exception, extra the relevant info and turn it // into our own ParseException try { buildProvider.GenerateCode(this); } catch (XmlException e) { throw new HttpParseException(e.Message, null /*innerException*/, buildProvider.VirtualPath, null /*sourceCode*/, e.LineNumber); } catch (XmlSchemaException e) { throw new HttpParseException(e.Message, null /*innerException*/, buildProvider.VirtualPath, null /*sourceCode*/, e.LineNumber); } catch (Exception e) { throw new HttpParseException(e.Message, e, buildProvider.VirtualPath, null /*sourceCode*/, 1); } // Handle any 'compileWith' dependencies, i.e. files that must be compiled // within the same assembly as the current file InternalBuildProvider internalBuildProvider = buildProvider as InternalBuildProvider; if (internalBuildProvider != null) { ICollection compileWith = internalBuildProvider.GetCompileWithDependencies(); if (compileWith != null) { foreach (VirtualPath virtualPath in compileWith) { // If we already have it, ignore it if (_buildProviders.ContainsKey(virtualPath.VirtualPathString)) continue; // Add the compileWith dependency to our compilation AddCompileWithBuildProvider(virtualPath, internalBuildProvider); } } } } private void AddAssemblyCultureAttribute() { if (CultureName == null) return; CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(System.Reflection.AssemblyCultureAttribute)), new CodeAttributeArgument[] { new CodeAttributeArgument(new CodePrimitiveExpression(CultureName))}); AddAssemblyAttribute(declaration); } #if UNUSED private void AddComVisibleAttribute() { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(System.Runtime.InteropServices.ComVisibleAttribute)), new CodeAttributeArgument[] { new CodeAttributeArgument(new CodePrimitiveExpression(false))}); AddAssemblyAttribute(declaration); } #endif private void AddAspNetGeneratedCodeAttribute() { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(GeneratedCodeAttribute))); declaration.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression("ASP.NET"))); declaration.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(VersionInfo.SystemWebVersion))); AddAssemblyAttribute(declaration); } private void AddAllowPartiallyTrustedCallersAttribute() { if (BuildManager.CompileWithAllowPartiallyTrustedCallersAttribute) { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(AllowPartiallyTrustedCallersAttribute))); AddAssemblyAttribute(declaration); } } private void AddAssemblyKeyFileAttribute() { if (!String.IsNullOrEmpty(BuildManager.StrongNameKeyFile)) { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(AssemblyKeyFileAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(BuildManager.StrongNameKeyFile))); AddAssemblyAttribute(declaration); } } private void AddAssemblyKeyContainerAttribute() { if (!String.IsNullOrEmpty(BuildManager.StrongNameKeyContainer)) { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(AssemblyKeyNameAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(BuildManager.StrongNameKeyContainer))); AddAssemblyAttribute(declaration); } } private void AddAssemblyDelaySignAttribute() { if (BuildManager.CompileWithDelaySignAttribute) { CodeAttributeDeclaration declaration = new CodeAttributeDeclaration( new CodeTypeReference(typeof(AssemblyDelaySignAttribute)), new CodeAttributeArgument(new CodePrimitiveExpression(true))); AddAssemblyAttribute(declaration); } } // Add an assembly level attribute to the assembly private void AddAssemblyAttribute(CodeAttributeDeclaration declaration) { if (_miscCodeCompileUnit == null) _miscCodeCompileUnit = new CodeCompileUnit(); _miscCodeCompileUnit.AssemblyCustomAttributes.Add(declaration); } private void GenerateMiscCodeCompileUnit() { // If there aren't any, return if (_miscCodeCompileUnit == null) return; AddCodeCompileUnit(null /*buildProvider*/, _miscCodeCompileUnit); } // Add a checksum pragma. This is used for improved debugging experience. private void AddChecksumPragma(BuildProvider buildProvider, CodeCompileUnit compileUnit) { // If we can't get a virtual path, do nothing if (buildProvider == null || buildProvider.VirtualPath == null) return; // Only do this if we're compiling in debug mode if (!_compilerType.CompilerParameters.IncludeDebugInformation) return; string physicalPath = HostingEnvironment.MapPathInternal(buildProvider.VirtualPath); // Only do this is the file physically exists, which it would not in the // case of a non-file based VirtualPathProvider. In such case, there is // no point in putting the pragma, since the debugger could not locate // the file anyway. if (!File.Exists(physicalPath)) return; #if !FEATURE_PAL // FEATURE_PAL does not yet support MD5 Crypto // Initialize the MD5 objects on demand if (s_md5HashAlgorithm == null) { s_md5HashAlgorithm = new MD5CryptoServiceProvider(); s_hashMD5Guid = new Guid(0x406ea660, 0x64cf, 0x4c82, 0xb6, 0xf0, 0x42, 0xd4, 0x81, 0x72, 0xa7, 0x99); } CodeChecksumPragma pragma = new CodeChecksumPragma(); if (_compConfig.UrlLinePragmas) { pragma.FileName = ErrorFormatter.MakeHttpLinePragma(buildProvider.VirtualPathObject.VirtualPathString); } else { pragma.FileName = physicalPath; } pragma.ChecksumAlgorithmId = s_hashMD5Guid; // Generate an MD5 hash from the contents of the file using (Stream stream = new FileStream(physicalPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { pragma.ChecksumData = s_md5HashAlgorithm.ComputeHash(stream); } // Add the pragma to the CodeCompileUnit compileUnit.StartDirectives.Add(pragma); #endif } internal CompilerParameters GetCompilerParameters() { CompilerParameters compilParams = _compilerType.CompilerParameters; string dir = _tempFiles.TempDir; // If a culture is set, modify the assembly name and location based on it if (CultureName != null) { dir = Path.Combine(dir, CultureName); Directory.CreateDirectory(dir); compilParams.OutputAssembly = Path.Combine(dir, OutputAssemblyName + ".resources.dll"); } else { compilParams.OutputAssembly = Path.Combine(dir, OutputAssemblyName + ".dll"); } // If such file already exist, try to delete or rename it if (File.Exists(compilParams.OutputAssembly)) Util.RemoveOrRenameFile(compilParams.OutputAssembly); compilParams.TempFiles = _tempFiles; // Create the string resource file (shared by all the pages we're compiling) if (_stringResourceBuilder != null && _stringResourceBuilder.HasStrings) { string resFileName = _tempFiles.AddExtension("res"); _stringResourceBuilder.CreateResourceFile(resFileName); compilParams.Win32Resource = resFileName; } // Add all the embedded resources to the compilParams if (_embeddedResourceFiles != null) { foreach (string aname in _embeddedResourceFiles) compilParams.EmbeddedResources.Add(aname); } // Merge the two sets of assemblies if (_additionalReferencedAssemblies != null) { foreach (Assembly assembly in _additionalReferencedAssemblies) { _initialReferencedAssemblies.Add(assembly); } } // Add all the referenced assemblies to the compilParams Util.AddAssembliesToStringCollection(_initialReferencedAssemblies, compilParams.ReferencedAssemblies); // Make any fix up adjustments to the CompilerParameters to work around some issues FixUpCompilerParameters(_compilerType.CodeDomProviderType, compilParams); return compilParams; } static string s_vbImportsString; private static void AddVBGlobalNamespaceImports(CompilerParameters compilParams) { // Put together the VB import string on demand if (s_vbImportsString == null) { PagesSection pagesConfig = RuntimeConfig.GetAppConfig().Pages; if (pagesConfig.Namespaces == null) { s_vbImportsString = String.Empty; } else { StringBuilder sb = new StringBuilder(); sb.Append("/imports:"); bool nextItemNeedsComma = false; // Auto-import Microsoft.VisualBasic is needed if (pagesConfig.Namespaces.AutoImportVBNamespace) { sb.Append("Microsoft.VisualBasic"); nextItemNeedsComma = true; } // Add all the namespaces from the configsection foreach (NamespaceInfo entry in pagesConfig.Namespaces) { // If there was a previous entry, we need a comma separator if (nextItemNeedsComma) sb.Append(','); sb.Append(entry.Namespace); nextItemNeedsComma = true; } s_vbImportsString = sb.ToString(); } } // Prepend it to the compilerOptions if (s_vbImportsString.Length > 0) { if (compilParams.CompilerOptions == null) compilParams.CompilerOptions = s_vbImportsString; else compilParams.CompilerOptions = s_vbImportsString + " " + compilParams.CompilerOptions; } } // Command line string for My.* support private const string MySupport = @"/define:_MYTYPE=\""Web\"""; private static void AddVBMyFlags(CompilerParameters compilParams) { // Prepend it to the compilerOptions if (compilParams.CompilerOptions == null) compilParams.CompilerOptions = MySupport; else compilParams.CompilerOptions = MySupport + " " + compilParams.CompilerOptions; } internal static void FixUpCompilerParameters(Type codeDomProviderType, CompilerParameters compilParams) { // If C#, remove the warning that complains about variables that start with "__" // Also ignore warning that complains about assemblyKeyName and delaysign // Also ignore warning about assuming assembly versions matching (CS1701, DevDiv 137847, warning about System.Web.Extensions v1.0 matching v3.5) if (codeDomProviderType == typeof(Microsoft.CSharp.CSharpCodeProvider)) { CodeDomUtility.PrependCompilerOption(compilParams, "/nowarn:1659;1699;1701"); } else if (codeDomProviderType == typeof(Microsoft.VisualBasic.VBCodeProvider)) { // If VB, add all the imported namespaces on the command line (DevDiv 21499). // This is VB only because other languages don't support global command line // namespace imports. AddVBGlobalNamespaceImports(compilParams); // Add any command line flags needed to support the My.* feature AddVBMyFlags(compilParams); } ProcessProviderOptions(codeDomProviderType, compilParams); FixTreatWarningsAsErrors(codeDomProviderType, compilParams); // Add CodeAnalysis symbol if required by client. if (BuildManager.PrecompilingWithCodeAnalysisSymbol) { CodeDomUtility.PrependCompilerOption(compilParams, "/define:CODE_ANALYSIS"); } } // DevDiv 114316 // CodeDom sets TreatWarningAsErrors to true whenever warningLevel is non-zero. // To get warnings only, the workaround is to use /warnaserror- in CompilerOptions. // However this does not work in some cases, as TreatWarningAsErrors set to true still emits // /warnaserror+. // So, whenever the user wants /warnaserror[+|-|numberlist], we explicitly set TreatWarningsAsErrors to false, // so that the /warnaserror+ is not emitted, and the user can specify exactly what is desired. internal static void FixTreatWarningsAsErrors(Type codeDomProviderType, CompilerParameters compilParams) { // Only do so for C# and VB. if (codeDomProviderType != typeof(Microsoft.CSharp.CSharpCodeProvider) && codeDomProviderType != typeof(Microsoft.VisualBasic.VBCodeProvider)) return; if (CultureInfo.InvariantCulture.CompareInfo.IndexOf(compilParams.CompilerOptions, "/warnaserror", CompareOptions.IgnoreCase) >= 0) compilParams.TreatWarningsAsErrors = false; } // Check for OptionInfer and WarnAsError. This is the workaround as use of compilerOptions is not allowed in partial trust. // Devdiv 130325 private static void ProcessProviderOptions(Type codeDomProviderType, CompilerParameters compilParams) { IDictionary providerOptions = CompilationUtil.GetProviderOptions(codeDomProviderType); if (providerOptions == null) return; // For C# and VB, check for WarnAsError if (codeDomProviderType == typeof(Microsoft.VisualBasic.VBCodeProvider) || codeDomProviderType == typeof(Microsoft.CSharp.CSharpCodeProvider)) ProcessBooleanProviderOption("WarnAsError", "/warnaserror+", "/warnaserror-", providerOptions, compilParams); // Only process OptionInfer for v3.5 compiler if (codeDomProviderType == null || !CompilationUtil.IsCompilerVersion35(codeDomProviderType)) return; // For VB, check for OptionInfer if (codeDomProviderType == typeof(Microsoft.VisualBasic.VBCodeProvider)) ProcessBooleanProviderOption("OptionInfer", "/optionInfer+", "/optionInfer-", providerOptions, compilParams); } private static void ProcessBooleanProviderOption(string providerOptionName, string trueCompilerOption, string falseCompilerOption, IDictionary providerOptions, CompilerParameters compilParams) { if (providerOptions == null || compilParams == null) return; Debug.Assert(providerOptionName != null, "providerOptionName should not be null"); Debug.Assert(trueCompilerOption != null, "trueCompilerOption should not be null"); Debug.Assert(falseCompilerOption != null, "falseCompilerOption should not be null"); string providerOptionValue = null; if (!providerOptions.TryGetValue(providerOptionName, out providerOptionValue)) return; if (string.IsNullOrEmpty(providerOptionValue)) throw new System.Configuration.ConfigurationException(SR.GetString(SR.Property_NullOrEmpty, CompilationUtil.CodeDomProviderOptionPath + providerOptionName)); bool value; if (Boolean.TryParse(providerOptionValue, out value)) { // If the value is boolean, insert the compiler options if (value) CodeDomUtility.AppendCompilerOption(compilParams, trueCompilerOption); else CodeDomUtility.AppendCompilerOption(compilParams, falseCompilerOption); } else { // If the value is not boolean, throw an exception throw new System.Configuration.ConfigurationException(SR.GetString(SR.Value_must_be_boolean, CompilationUtil.CodeDomProviderOptionPath + providerOptionName)); } } internal CompilerResults Compile() { // First, check if there is something to compile if (_sourceFiles.Count == 0 && _embeddedResourceFiles == null) return null; // if we have some fast object factories to generate, get the CodeCompileUnit if (_objectFactoryGenerator != null) { _miscCodeCompileUnit = _objectFactoryGenerator.CodeCompileUnit; } // Add a culture attribute if needed AddAssemblyCultureAttribute(); // Add a ComVisible(false) attribute (VSWhidbey 436453) // Actually, don't do it to avoid breaking migrated apps (VSWhidbey 446788) //AddComVisibleAttribute(); // Add an AspNetGeneratedCode attribute to help fxcop ignore some violations (VSWhidbey 437581) AddAspNetGeneratedCodeAttribute(); // Add an AllowPartiallyTrustedCallers attribute to make strong-name assemblies. (Devdiv 39696) AddAllowPartiallyTrustedCallersAttribute(); AddAssemblyDelaySignAttribute(); AddAssemblyKeyFileAttribute(); AddAssemblyKeyContainerAttribute(); // Generate a source file for the misc top level items if needed GenerateMiscCodeCompileUnit(); CompilerParameters compilParams = GetCompilerParameters(); string[] files = new string[_sourceFiles.Count]; _sourceFiles.CopyTo(files, 0); // Increment compilation counter PerfCounters.IncrementCounter(AppPerfCounter.COMPILATIONS); // Raise Web Event WebBaseEvent.RaiseSystemEvent(this, WebEventCodes.ApplicationCompilationStart); HttpContext context = HttpContext.Current; if (context != null) { if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_COMPILE_ENTER, context.WorkerRequest); } CompilerResults results = null; try { try { // Revert impersonation when compiling source code in the codegen dir (VSWhidbey 176576) using (new ProcessImpersonationContext()) { results = _codeProvider.CompileAssemblyFromFile(compilParams, files); } } finally { if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure) && context != null) { string fileNames = null; if (_buildProviders.Count < 20) { IDictionaryEnumerator e = _buildProviders.GetEnumerator(); while(e.MoveNext()) { if (fileNames != null) fileNames += ","; fileNames += e.Key; } } else { fileNames = String.Format(CultureInfo.InstalledUICulture, SR.Resources.GetString(SR.Etw_Batch_Compilation, CultureInfo.InstalledUICulture), new object[1] {_buildProviders.Count}); } string status; if (results != null && (results.NativeCompilerReturnValue != 0 || results.Errors.HasErrors)) status = SR.Resources.GetString(SR.Etw_Failure, CultureInfo.InstalledUICulture); else status = SR.Resources.GetString(SR.Etw_Success, CultureInfo.InstalledUICulture); EtwTrace.Trace(EtwTraceType.ETW_TYPE_COMPILE_LEAVE, context.WorkerRequest, fileNames, status); } } } catch { throw; } // Prevent Exception Filter Security Issue (ASURT 122835) // If an IAssemblyPostProcessor is registered, call it Type postProcessorType = _compConfig.AssemblyPostProcessorTypeInternal; if (postProcessorType != null) { using (IAssemblyPostProcessor postProcessor = (IAssemblyPostProcessor) HttpRuntime.FastCreatePublicInstance(postProcessorType)) { postProcessor.PostProcessAssembly(results.PathToAssembly); } } // Raise Web Event WebBaseEvent.RaiseSystemEvent(this, WebEventCodes.ApplicationCompilationEnd); if (results != null) { // Invalidate an invalid assembly to trigger recompilation InvalidateInvalidAssembly(results, compilParams); // Fix up with line pragmas to account for the http case, and for some special conditions FixUpLinePragmas(results); // If there is a CBM callback, inform it of the errors/warnings if (BuildManager.CBMCallback != null) { foreach (CompilerError error in results.Errors) { BuildManager.CBMCallback.ReportCompilerError(error); } } // If there are errors, increment the relevant perf counters and throw if (results.NativeCompilerReturnValue != 0 || results.Errors.HasErrors) { // Increment the compilation error and total error counters PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_COMPILING); PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_TOTAL); throw new HttpCompileException(results, GetErrorSourceFileContents(results)); } } return results; } private void InvalidateInvalidAssembly(CompilerResults results, CompilerParameters compilParams) { // VSWhidbey 610291 // If target assembly gets locked, we invalidate the assembly, so that it does // not get used, and the next compilation will use a new assembly name. // CS0016 is the error code for "Could not write to output file 'file' -- 'reason'" if (results == null || !results.Errors.HasErrors) return; foreach (CompilerError error in results.Errors) { if (error.IsWarning) continue; if (StringUtil.EqualsIgnoreCase(error.ErrorNumber, "CS0016")){ // Also invalidate the base assembly if this is a localized resource assembly if (CultureName != null) { string dir = _tempFiles.TempDir; string baseAssemblyFile = Path.Combine(dir, OutputAssemblyName + ".dll"); DiskBuildResultCache.TryDeleteFile(new FileInfo(baseAssemblyFile)); } // Invalidate the target assembly DiskBuildResultCache.TryDeleteFile(compilParams.OutputAssembly); } } } /* * Fix up all the source files in the errors in case they are HTTP (VS compiler scenario). * Also, fix the error in case the base class was incorrect in the code beside model */ private void FixUpLinePragmas(CompilerResults results) { CompilerError badBaseClassError = null; // Go through the errors backwards so we can delete them as needed for (int i=results.Errors.Count-1; i>=0; i--) { CompilerError error = results.Errors[i]; string physicalPath = ErrorFormatter.ResolveHttpFileName(error.FileName); // Only replace it by the physical path if it actually exists, which may not // be the case when using a VirtualPathProvider if (File.Exists(physicalPath)) { error.FileName = physicalPath; // If it is our special marker line number, remember it and remove it. // We place the marker at two places: 1) before setting AppRelativeVirtualPath in the constructor, // and 2) before the method FrameworkInitialize. // For the generated method FrameworkInitialize, the method comes one line after // the marker, due to an additional line taken by the DebuggerNonUserCodeAttribute. (DevDiv 175681) if (error.Line == TemplateControlCodeDomTreeGenerator.badBaseClassLineMarker || (error.Line == TemplateControlCodeDomTreeGenerator.badBaseClassLineMarker + 1 && error.ErrorText != null && error.ErrorText.IndexOf("FrameworkInitialize", StringComparison.OrdinalIgnoreCase) >= 0)) { badBaseClassError = error; results.Errors.RemoveAt(i); } else if (error.Line > TemplateControlCodeDomTreeGenerator.badBaseClassLineMarker && error.Line < TemplateControlCodeDomTreeGenerator.badBaseClassLineMarker + 50) { // Also, if within range of it, remove it altogether results.Errors.RemoveAt(i); } } } // If we found our special marker error, we're most likely in a situation where // the class in the code beside file doesn't match the 'inherits' in the aspx/ascx, // or is missing the based type (or has the wrong base type). In that case, change // the error message to make the problem explicit to the user (VSWhidbey 376977/468830) if (badBaseClassError != null) { // Read the content of the code beside file string codeFileContent = Util.StringFromFile(badBaseClassError.FileName); // Search for the partial class declaration within the file. We do this by searching for // the string "partial class" in case insensitive way. This is far from fool proof, but // it covers the common VB and C# cases, and the fallback when not found is reasonable. int classOffset = CultureInfo.InvariantCulture.CompareInfo.IndexOf(codeFileContent, "partial class", CompareOptions.IgnoreCase); if (classOffset >= 0) { // We found it, so figure out the line number from it badBaseClassError.Line = Util.LineCount(codeFileContent, 0, classOffset) + 1; } else { // Otherwise, just use 1. It won't point to the right line, but at least the error // message is helpful badBaseClassError.Line = 1; } // Change the error message to make the situation clear to the user badBaseClassError.ErrorText = SR.GetString(SR.Bad_Base_Class_In_Code_File); badBaseClassError.ErrorNumber = "ASPNET"; // Insert the error at the begining of the collection, since we display the first error. results.Errors.Insert(0, badBaseClassError); } } /* * Attempt to find the generated source file that has the error, and return * its contents as a string (for error reproting purposes). * Note that when debug is false, we set tempFiles.KeepFiles to false, and * all the sources will be gone by the time we get here. I filed VSWhidbey 103673, * to get a solution to this from BCL. */ private string GetErrorSourceFileContents(CompilerResults results) { if (!results.Errors.HasErrors) return null; // Get the physical path of the file that has the error. Note that this could be // either the path to a high level file (e.g. aspx) if pragmas are in play, // or the path to a generated file if there are no pragmas string linePragma = results.Errors[0].FileName; // Attempt to locate the correct build provider BuildProvider buildProvider = GetBuildProviderFromLinePragma(linePragma); if (buildProvider != null) { // Return the generated file for this build provider return GetGeneratedSourceFromBuildProvider(buildProvider); } // If we didn't find it, then we're probably in the no pragma case, in // which case linePragma itself is the generated file return Util.StringFromFileIfExists(linePragma); } internal string GetGeneratedSourceFromBuildProvider(BuildProvider buildProvider) { // Return the generated file content for this build provider string generatedFilePath = (string) _buildProviderToSourceFileMap[buildProvider]; return Util.StringFromFileIfExists(generatedFilePath); } internal BuildProvider GetBuildProviderFromLinePragma(string linePragma) { BuildProvider buildProvider = GetBuildProviderFromLinePragmaInternal(linePragma); // If it's a CompileWith provider, return the main provider instead SourceFileBuildProvider sourceBuildProvider = buildProvider as SourceFileBuildProvider; if (sourceBuildProvider != null) buildProvider = sourceBuildProvider.OwningBuildProvider; return buildProvider; } private BuildProvider GetBuildProviderFromLinePragmaInternal(string linePragma) { // If we didn't keep track of any generated files, we can't do much if (_buildProviderToSourceFileMap == null) return null; // Check if it's an http line pragma, from which we can get a VirtualPath string virtualPath = ErrorFormatter.GetVirtualPathFromHttpLinePragma(linePragma); // First, look for the pragma case foreach (BuildProvider buildProvider in BuildProviders) { // If the build provider can't give us a virtual path, skip it if (buildProvider.VirtualPath == null) continue; // If we got a virtual path, use it to locate the correct BuildProvider if (virtualPath != null) { if (StringUtil.EqualsIgnoreCase(virtualPath, buildProvider.VirtualPath)) { return buildProvider; } continue; } // Otherwise, work with the physical path string physicalPath = HostingEnvironment.MapPathInternal(buildProvider.VirtualPath); if (StringUtil.EqualsIgnoreCase(linePragma, physicalPath)) { return buildProvider; } } return null; } } /* * This class is used intead of AssemblyBuilder when handling * ClientBuildManager.GetCodeDirectoryInformation * It is instantiated via CompilerType.CreateAssemblyBuilder. */ internal class CbmCodeGeneratorBuildProviderHost: AssemblyBuilder { private string _generatedFilesDir; internal CbmCodeGeneratorBuildProviderHost(CompilationSection compConfig, ICollection referencedAssemblies, CompilerType compilerType, string generatedFilesDir, string outputAssemblyName) : base(compConfig, referencedAssemblies, compilerType, outputAssemblyName) { // Wipe out any existing directory, and recreate it // This is where we will put generated source files if (Directory.Exists(generatedFilesDir)) { // Delete all the files in the directory foreach (FileData fileData in FileEnumerator.Create(generatedFilesDir)) { // It should only contain files Debug.Assert(!fileData.IsDirectory); if (fileData.IsDirectory) continue; Debug.Trace("CbmCodeGeneratorBuildProviderHost", "Deleting " + fileData.FullName); File.Delete(fileData.FullName); } } // Create it to make sure it exists Directory.CreateDirectory(generatedFilesDir); _generatedFilesDir = generatedFilesDir; } internal override TextWriter CreateCodeFile(BuildProvider buildProvider, out string filename) { // use GetCacheKeyFromVirtualPath to get a file name that looks like // the original file, but is guaranteed unique across different virtual dirs. string generatedCodeFile = BuildManager.GetCacheKeyFromVirtualPath( buildProvider.VirtualPathObject); generatedCodeFile = Path.Combine(_generatedFilesDir, generatedCodeFile); generatedCodeFile = FileUtil.TruncatePathIfNeeded(generatedCodeFile, 10 /*length of extension */); generatedCodeFile = generatedCodeFile + "." + _codeProvider.FileExtension; filename = generatedCodeFile; BuildManager.GenerateFileTable[buildProvider.VirtualPathObject.VirtualPathStringNoTrailingSlash] = generatedCodeFile; Debug.Trace("CbmCodeGeneratorBuildProviderHost", "Generating " + generatedCodeFile); Stream temp = new FileStream(generatedCodeFile, FileMode.Create, FileAccess.Write, FileShare.Read); return new StreamWriter(temp, Encoding.UTF8); } internal override void AddBuildProvider(BuildProvider buildProvider) { // Skip source files, since their code generation is an identity transform if (buildProvider is SourceFileBuildProvider) return; base.AddBuildProvider(buildProvider); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Rect3D.cs
- NullableBoolConverter.cs
- coordinatorscratchpad.cs
- StrongNamePublicKeyBlob.cs
- UserControl.cs
- LazyTextWriterCreator.cs
- Size3DValueSerializer.cs
- NewExpression.cs
- login.cs
- CallbackHandler.cs
- ISCIIEncoding.cs
- WizardPanel.cs
- DocumentAutomationPeer.cs
- M3DUtil.cs
- ScriptingWebServicesSectionGroup.cs
- QueryCursorEventArgs.cs
- GenericWebPart.cs
- FontFaceLayoutInfo.cs
- DataPagerCommandEventArgs.cs
- DataSourceControlBuilder.cs
- InstanceDescriptor.cs
- GenericEnumerator.cs
- CodeRemoveEventStatement.cs
- ApplicationServiceManager.cs
- ZipPackage.cs
- DiscoveryMessageProperty.cs
- AnnotationComponentManager.cs
- SHA256Managed.cs
- DynamicAttribute.cs
- CredentialCache.cs
- XmlSubtreeReader.cs
- GrammarBuilderRuleRef.cs
- SqlStatistics.cs
- CommandEventArgs.cs
- MessagePartSpecification.cs
- DSASignatureFormatter.cs
- DateBoldEvent.cs
- TableParagraph.cs
- ValueOfAction.cs
- WizardPanel.cs
- NullableConverter.cs
- IpcPort.cs
- ConfigXmlAttribute.cs
- IgnoreDeviceFilterElement.cs
- LoginUtil.cs
- AllMembershipCondition.cs
- SspiWrapper.cs
- XsltFunctions.cs
- XPathException.cs
- RightsManagementEncryptionTransform.cs
- RangeValuePattern.cs
- WindowProviderWrapper.cs
- XNodeValidator.cs
- ArgIterator.cs
- XmlAggregates.cs
- VariableQuery.cs
- SelectionChangedEventArgs.cs
- GlyphsSerializer.cs
- WebPartRestoreVerb.cs
- Cursor.cs
- ObjectStateManager.cs
- NameValuePermission.cs
- MediaPlayer.cs
- WebAdminConfigurationHelper.cs
- Int16Animation.cs
- DesignerTransaction.cs
- CSharpCodeProvider.cs
- GAC.cs
- WeakReferenceEnumerator.cs
- MultilineStringConverter.cs
- EpmSyndicationContentDeSerializer.cs
- ConstraintStruct.cs
- OperationParameterInfo.cs
- NullRuntimeConfig.cs
- BuilderInfo.cs
- Rect.cs
- DataGridViewAutoSizeColumnModeEventArgs.cs
- Deflater.cs
- TriggerBase.cs
- complextypematerializer.cs
- WorkflowApplicationUnloadedException.cs
- ReadContentAsBinaryHelper.cs
- BitmapFrameEncode.cs
- StringInfo.cs
- DataBinding.cs
- TiffBitmapEncoder.cs
- InputScope.cs
- Crc32Helper.cs
- Schema.cs
- ActivityTrace.cs
- ZipIOZip64EndOfCentralDirectoryLocatorBlock.cs
- SqlCacheDependency.cs
- HtmlUtf8RawTextWriter.cs
- SaveFileDialog.cs
- DebugView.cs
- BooleanKeyFrameCollection.cs
- UserPreferenceChangedEventArgs.cs
- WebPartConnectionsCancelEventArgs.cs
- DocumentSequenceHighlightLayer.cs
- SdlChannelSink.cs