1 //------------------------------------------------------------------------------ 2 // <copyright file="CompilationConfiguration.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 /* 8 * Code related to the <assemblies> config section 9 * 10 * Copyright (c) 1999 Microsoft Corporation 11 */ 12 namespace System.Web.Compilation { 13 14 using System; 15 using System.Web; 16 using System.Configuration; 17 using System.Web.UI; 18 using System.Web.Configuration; 19 using System.Web.Hosting; 20 using System.Web.Util; 21 using System.Globalization; 22 using System.Collections; 23 using System.Collections.Generic; 24 using System.CodeDom.Compiler; 25 using System.Linq; 26 using System.Security; 27 using System.Security.Permissions; 28 using System.Reflection; 29 using System.Runtime.ExceptionServices; 30 using System.Threading; 31 using System.Threading.Tasks; 32 33 internal static class CompilationUtil { 34 35 internal const string CodeDomProviderOptionPath = "system.codedom/compilers/compiler/ProviderOption/"; 36 private const string CompilerDirectoryPath = "CompilerDirectoryPath"; 37 private static int _maxConcurrentCompilations; 38 IsDebuggingEnabled(HttpContext context)39 internal static bool IsDebuggingEnabled(HttpContext context) { 40 CompilationSection compConfig = MTConfigUtil.GetCompilationConfig(context); 41 return compConfig.Debug; 42 } 43 IsBatchingEnabled(string configPath)44 internal static bool IsBatchingEnabled(string configPath) { 45 CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath); 46 return config.Batch; 47 } 48 GetRecompilationsBeforeAppRestarts()49 internal static int GetRecompilationsBeforeAppRestarts() { 50 CompilationSection config = MTConfigUtil.GetCompilationAppConfig(); 51 return config.NumRecompilesBeforeAppRestart; 52 } 53 GetCodeDefaultLanguageCompilerInfo()54 internal static CompilerType GetCodeDefaultLanguageCompilerInfo() { 55 return new CompilerType(typeof(Microsoft.VisualBasic.VBCodeProvider), null); 56 } 57 GetDefaultLanguageCompilerInfo(CompilationSection compConfig, VirtualPath configPath)58 internal static CompilerType GetDefaultLanguageCompilerInfo(CompilationSection compConfig, VirtualPath configPath) { 59 if (compConfig == null) { 60 // Get the <compilation> config object 61 compConfig = MTConfigUtil.GetCompilationConfig(configPath); 62 } 63 64 // If no default language was specified in config, use VB 65 if (compConfig.DefaultLanguage == null) { 66 return GetCodeDefaultLanguageCompilerInfo(); 67 } 68 else { 69 return compConfig.GetCompilerInfoFromLanguage(compConfig.DefaultLanguage); 70 } 71 } 72 73 /* 74 * Return a CompilerType that a file name's extension maps to. 75 */ GetCompilerInfoFromVirtualPath(VirtualPath virtualPath)76 internal static CompilerType GetCompilerInfoFromVirtualPath(VirtualPath virtualPath) { 77 78 // Get the extension of the source file to compile 79 string extension = virtualPath.Extension; 80 81 // Make sure there is an extension 82 if (extension.Length == 0) { 83 throw new HttpException( 84 SR.GetString(SR.Empty_extension, virtualPath)); 85 } 86 87 return GetCompilerInfoFromExtension(virtualPath, extension); 88 } 89 90 /* 91 * Return a CompilerType that a extension maps to. 92 */ GetCompilerInfoFromExtension(VirtualPath configPath, string extension)93 private static CompilerType GetCompilerInfoFromExtension(VirtualPath configPath, string extension) { 94 // Get the <compilation> config object 95 CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath); 96 97 return config.GetCompilerInfoFromExtension(extension, true /*throwOnFail*/); 98 } 99 100 /* 101 * Return a CompilerType that a language maps to. 102 */ GetCompilerInfoFromLanguage(VirtualPath configPath, string language)103 internal static CompilerType GetCompilerInfoFromLanguage(VirtualPath configPath, string language) { 104 // Get the <compilation> config object 105 CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath); 106 107 return config.GetCompilerInfoFromLanguage(language); 108 } 109 GetCSharpCompilerInfo( CompilationSection compConfig, VirtualPath configPath)110 internal static CompilerType GetCSharpCompilerInfo( 111 CompilationSection compConfig, VirtualPath configPath) { 112 113 if (compConfig == null) { 114 // Get the <compilation> config object 115 compConfig = MTConfigUtil.GetCompilationConfig(configPath); 116 } 117 118 if (compConfig.DefaultLanguage == null) 119 return new CompilerType(typeof(Microsoft.CSharp.CSharpCodeProvider), null); 120 121 return compConfig.GetCompilerInfoFromLanguage("c#"); 122 } 123 GetCodeSubDirectories()124 internal static CodeSubDirectoriesCollection GetCodeSubDirectories() { 125 // Get the <compilation> config object 126 CompilationSection config = MTConfigUtil.GetCompilationAppConfig(); 127 128 CodeSubDirectoriesCollection codeSubDirectories = config.CodeSubDirectories; 129 130 // Make sure the config data is valid 131 if (codeSubDirectories != null) { 132 codeSubDirectories.EnsureRuntimeValidation(); 133 } 134 135 return codeSubDirectories; 136 } 137 GetRecompilationHash(CompilationSection ps)138 internal static long GetRecompilationHash(CompilationSection ps) { 139 HashCodeCombiner recompilationHash = new HashCodeCombiner(); 140 AssemblyCollection assemblies; 141 BuildProviderCollection builders; 142 FolderLevelBuildProviderCollection buildProviders; 143 CodeSubDirectoriesCollection codeSubDirs; 144 145 // Combine items from Compilation section 146 recompilationHash.AddObject(ps.Debug); 147 recompilationHash.AddObject(ps.TargetFramework); 148 recompilationHash.AddObject(ps.Strict); 149 recompilationHash.AddObject(ps.Explicit); 150 recompilationHash.AddObject(ps.Batch); 151 recompilationHash.AddObject(ps.OptimizeCompilations); 152 recompilationHash.AddObject(ps.BatchTimeout); 153 recompilationHash.AddObject(ps.MaxBatchGeneratedFileSize); 154 recompilationHash.AddObject(ps.MaxBatchSize); 155 recompilationHash.AddObject(ps.NumRecompilesBeforeAppRestart); 156 recompilationHash.AddObject(ps.DefaultLanguage); 157 recompilationHash.AddObject(ps.UrlLinePragmas); 158 recompilationHash.AddObject(ps.DisableObsoleteWarnings); 159 if (ps.AssemblyPostProcessorTypeInternal != null) { 160 recompilationHash.AddObject(ps.AssemblyPostProcessorTypeInternal.FullName); 161 } 162 if (!String.IsNullOrWhiteSpace(ps.ControlBuilderInterceptorType)) { 163 recompilationHash.AddObject(ps.ControlBuilderInterceptorType); 164 } 165 166 // Combine items from Compilers collection 167 foreach (Compiler compiler in ps.Compilers) { 168 recompilationHash.AddObject(compiler.Language); 169 recompilationHash.AddObject(compiler.Extension); 170 recompilationHash.AddObject(compiler.Type); 171 recompilationHash.AddObject(compiler.WarningLevel); 172 recompilationHash.AddObject(compiler.CompilerOptions); 173 } 174 175 // Combine items from <expressionBuilders> section 176 foreach (System.Web.Configuration.ExpressionBuilder eb in ps.ExpressionBuilders) { 177 recompilationHash.AddObject(eb.ExpressionPrefix); 178 recompilationHash.AddObject(eb.Type); 179 } 180 181 // Combine items from the Assembly collection 182 assemblies = ps.Assemblies; 183 184 if (assemblies.Count == 0) { 185 recompilationHash.AddObject("__clearassemblies"); 186 } 187 else { 188 foreach (AssemblyInfo ai in assemblies) { 189 recompilationHash.AddObject(ai.Assembly); 190 } 191 } 192 193 // Combine items from the Builders Collection 194 builders = ps.BuildProviders; 195 196 if (builders.Count == 0) { 197 recompilationHash.AddObject("__clearbuildproviders"); 198 } 199 else { 200 foreach (System.Web.Configuration.BuildProvider bp in builders) { 201 recompilationHash.AddObject(bp.Type); 202 recompilationHash.AddObject(bp.Extension); 203 } 204 } 205 206 // Combine items from the FolderLevelBuildProviderCollection 207 buildProviders = ps.FolderLevelBuildProviders; 208 209 if (buildProviders.Count == 0) { 210 recompilationHash.AddObject("__clearfolderlevelbuildproviders"); 211 } 212 else { 213 foreach (System.Web.Configuration.FolderLevelBuildProvider bp in buildProviders) { 214 recompilationHash.AddObject(bp.Type); 215 recompilationHash.AddObject(bp.Name); 216 } 217 } 218 219 codeSubDirs = ps.CodeSubDirectories; 220 if (codeSubDirs.Count == 0) { 221 recompilationHash.AddObject("__clearcodesubdirs"); 222 } 223 else { 224 foreach (CodeSubDirectory csd in codeSubDirs) { 225 recompilationHash.AddObject(csd.DirectoryName); 226 } 227 } 228 229 // Make sure the <system.CodeDom> section is hashed properly. 230 CompilerInfo[] compilerInfoArray = CodeDomProvider.GetAllCompilerInfo(); 231 if (compilerInfoArray != null) { 232 CompilerInfo cppCodeProvider = CodeDomProvider.GetCompilerInfo("cpp"); 233 foreach (CompilerInfo info in compilerInfoArray) { 234 // Skip cpp code provider (Dev11 193323). 235 if (info == cppCodeProvider) { 236 continue; 237 } 238 239 // Ignore it if the type is not valid. 240 if (!info.IsCodeDomProviderTypeValid) { 241 continue; 242 } 243 244 CompilerParameters parameters = info.CreateDefaultCompilerParameters(); 245 string option = parameters.CompilerOptions; 246 if (!String.IsNullOrEmpty(option)) { 247 Type type = info.CodeDomProviderType; 248 if (type != null) { 249 recompilationHash.AddObject(type.FullName); 250 } 251 // compilerOptions need to be hashed. 252 recompilationHash.AddObject(option); 253 } 254 255 // DevDiv 62998 256 // The tag providerOption needs to be added to the hash, 257 // as the user could switch between v2 and v3.5. 258 if (info.CodeDomProviderType == null) 259 continue; 260 261 // Add a hash for each providerOption added, specific for each codeDomProvider, so that 262 // if some codedom setting has changed, we know we have to recompile. 263 IDictionary<string, string> providerOptions = GetProviderOptions(info); 264 if (providerOptions != null && providerOptions.Count > 0) { 265 string codeDomProviderType = info.CodeDomProviderType.FullName; 266 foreach (string key in providerOptions.Keys) { 267 string value = providerOptions[key]; 268 recompilationHash.AddObject(codeDomProviderType + ":" + key + "=" + value); 269 } 270 } 271 } 272 } 273 274 return recompilationHash.CombinedHash; 275 } 276 277 278 /* 279 * Return a file provider Type that an extension maps to. 280 */ GetBuildProviderTypeFromExtension(VirtualPath configPath, string extension, BuildProviderAppliesTo neededFor, bool failIfUnknown)281 internal static Type GetBuildProviderTypeFromExtension(VirtualPath configPath, string extension, 282 BuildProviderAppliesTo neededFor, bool failIfUnknown) { 283 284 // Get the <compilation> config object 285 CompilationSection config = MTConfigUtil.GetCompilationConfig(configPath); 286 287 return GetBuildProviderTypeFromExtension(config, extension, neededFor, failIfUnknown); 288 } 289 GetBuildProviderTypeFromExtension(CompilationSection config, string extension, BuildProviderAppliesTo neededFor, bool failIfUnknown)290 internal static Type GetBuildProviderTypeFromExtension(CompilationSection config, string extension, 291 BuildProviderAppliesTo neededFor, bool failIfUnknown) { 292 293 BuildProviderInfo providerInfo = BuildProvider.GetBuildProviderInfo(config, extension); 294 295 Type buildProviderType = null; 296 // Never return an IgnoreFileBuildProvider/ForceCopyBuildProvider, since it's just a marker 297 if (providerInfo != null && 298 providerInfo.Type != typeof(IgnoreFileBuildProvider) && 299 providerInfo.Type != typeof(ForceCopyBuildProvider)) { 300 buildProviderType = providerInfo.Type; 301 } 302 303 // In updatable precomp mode, only aspx/ascx/master web files need processing. Ignore the rest. 304 if (neededFor == BuildProviderAppliesTo.Web && 305 BuildManager.PrecompilingForUpdatableDeployment && 306 !typeof(BaseTemplateBuildProvider).IsAssignableFrom(buildProviderType)) { 307 buildProviderType = null; 308 } 309 310 if (buildProviderType != null) { 311 // Only return it if it applies to what it's needed for 312 if ((neededFor & providerInfo.AppliesTo) != 0) 313 return buildProviderType; 314 } 315 // If the extension is registered as a compiler extension, use 316 // a SourceFileBuildProvider to handle it (not supported in Resources directory) 317 else if (neededFor != BuildProviderAppliesTo.Resources && 318 config.GetCompilerInfoFromExtension(extension, false /*throwOnFail*/) != null) { 319 return typeof(SourceFileBuildProvider); 320 } 321 322 if (failIfUnknown) { 323 throw new HttpException( SR.GetString(SR.Unknown_buildprovider_extension, extension, neededFor.ToString())); 324 } 325 326 return null; 327 } 328 329 // Returns the list of buildProvider types associated to the specified appliesTo GetFolderLevelBuildProviderTypes(CompilationSection config, FolderLevelBuildProviderAppliesTo appliesTo)330 internal static List<Type> GetFolderLevelBuildProviderTypes(CompilationSection config, 331 FolderLevelBuildProviderAppliesTo appliesTo) { 332 FolderLevelBuildProviderCollection buildProviders = config.FolderLevelBuildProviders; 333 return buildProviders.GetBuildProviderTypes(appliesTo); 334 } 335 336 // In partial trust, do not allow the CompilerDirectoryPath provider option in codedom settings (Dev10 bug 462348) CheckCompilerDirectoryPathAllowed(IDictionary<string, string> providerOptions)337 internal static void CheckCompilerDirectoryPathAllowed(IDictionary<string, string> providerOptions) { 338 if (providerOptions == null) { 339 return; 340 } 341 if (!providerOptions.ContainsKey(CompilerDirectoryPath)) { 342 return; 343 } 344 345 if (!HttpRuntime.HasUnmanagedPermission()) { 346 string errorString = SR.GetString(SR.Insufficient_trust_for_attribute, CompilerDirectoryPath); 347 throw new HttpException(errorString); 348 } 349 } 350 CheckCompilerOptionsAllowed(string compilerOptions, bool config, string file, int line)351 internal static void CheckCompilerOptionsAllowed(string compilerOptions, bool config, string file, int line) { 352 353 // If it's empty, we never block it 354 if (String.IsNullOrEmpty(compilerOptions)) 355 return; 356 357 // Only allow the use of compilerOptions when we have UnmanagedCode access (ASURT 73678) 358 if (!HttpRuntime.HasUnmanagedPermission()) { 359 string errorString = SR.GetString(SR.Insufficient_trust_for_attribute, "compilerOptions"); 360 361 if (config) 362 throw new ConfigurationErrorsException(errorString, file, line); 363 else 364 throw new HttpException(errorString); 365 } 366 } 367 368 // This is used to determine what files need to be copied, and what stub files 369 // need to be created during deployment precompilation. 370 // Note: createStub only applies if the method returns false. NeedToCopyFile(VirtualPath virtualPath, bool updatable, out bool createStub)371 internal static bool NeedToCopyFile(VirtualPath virtualPath, bool updatable, out bool createStub) { 372 373 createStub = false; 374 375 // Get the <compilation> config object 376 CompilationSection config = MTConfigUtil.GetCompilationConfig(virtualPath); 377 378 string extension = virtualPath.Extension; 379 380 BuildProviderInfo providerInfo = BuildProvider.GetBuildProviderInfo(config, extension); 381 382 if (providerInfo != null) { 383 // We only care about 'web' providers. Everything else we treat as static 384 if ((BuildProviderAppliesTo.Web & providerInfo.AppliesTo) == 0) 385 return true; 386 387 // If the provider is a ForceCopyBuildProvider, treat as static 388 if (providerInfo.Type == typeof(ForceCopyBuildProvider)) 389 return true; 390 391 // During updatable precomp, everything needs to be copied over. However, 392 // aspx files that use code beside will later be overwritten by modified 393 // versions (see TemplateParser.CreateModifiedMainDirectiveFileIfNeeded) 394 if (providerInfo.Type != typeof(IgnoreFileBuildProvider) && 395 BuildManager.PrecompilingForUpdatableDeployment) { 396 return true; 397 } 398 399 // There is a real provider, so don't copy the file. We also need to determine whether 400 // a stub file needs to be created. 401 402 createStub = true; 403 404 // Skip the stub file for some non-requestable types 405 if (providerInfo.Type == typeof(UserControlBuildProvider) || 406 providerInfo.Type == typeof(MasterPageBuildProvider) || 407 providerInfo.Type == typeof(IgnoreFileBuildProvider)) { 408 createStub = false; 409 } 410 411 return false; 412 } 413 414 // If the extension is registered as a compiler extension, don't copy 415 if (config.GetCompilerInfoFromExtension(extension, false /*throwOnFail*/) != null) { 416 return false; 417 } 418 419 // Skip the copying for asax and skin files, which are not static even though they 420 // don't have a registered BuildProvider (but don't skip .skin files during 421 // updatable precomp). 422 // 423 if (StringUtil.EqualsIgnoreCase(extension, ".asax")) 424 return false; 425 if (!updatable && StringUtil.EqualsIgnoreCase(extension, ThemeDirectoryCompiler.skinExtension)) 426 return false; 427 428 // 429 // If there is no BuildProvider registered, it's a static file, and should be copied 430 // 431 432 return true; 433 } 434 LoadTypeWithChecks(string typeName, Type requiredBaseType, Type requiredBaseType2, ConfigurationElement elem, string propertyName)435 internal static Type LoadTypeWithChecks(string typeName, Type requiredBaseType, Type requiredBaseType2, ConfigurationElement elem, string propertyName) { 436 Type t = ConfigUtil.GetType(typeName, propertyName, elem); 437 438 if (requiredBaseType2 == null) { 439 ConfigUtil.CheckAssignableType(requiredBaseType, t, elem, propertyName); 440 } 441 else { 442 ConfigUtil.CheckAssignableType(requiredBaseType, requiredBaseType2, t, elem, propertyName); 443 } 444 445 return t; 446 } 447 448 // Devdiv Bug 57600 449 // We need to use the constructor with ProviderOptions to get the v3.5/v4.0 compiler that was possibly set in config. 450 // We first check if there is any providerOptions and invoke the constructor if so. 451 // Otherwise, we fall back to the default constructor. CreateCodeDomProvider(Type codeDomProviderType)452 internal static CodeDomProvider CreateCodeDomProvider(Type codeDomProviderType) { 453 CodeDomProvider codeDomProvider = CreateCodeDomProviderWithPropertyOptions(codeDomProviderType); 454 if (codeDomProvider != null) { 455 return codeDomProvider; 456 } 457 return (CodeDomProvider)Activator.CreateInstance(codeDomProviderType); 458 } 459 CreateCodeDomProviderNonPublic(Type codeDomProviderType)460 internal static CodeDomProvider CreateCodeDomProviderNonPublic(Type codeDomProviderType) { 461 CodeDomProvider codeDomProvider = CreateCodeDomProviderWithPropertyOptions(codeDomProviderType); 462 if (codeDomProvider != null) { 463 return codeDomProvider; 464 } 465 return (CodeDomProvider)HttpRuntime.CreateNonPublicInstance(codeDomProviderType); 466 } 467 468 [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)] CreateCodeDomProviderWithPropertyOptions(Type codeDomProviderType)469 private static CodeDomProvider CreateCodeDomProviderWithPropertyOptions(Type codeDomProviderType) { 470 // The following resembles the code in System.CodeDom.CompilerInfo.CreateProvider 471 472 // Make a copy to avoid modifying the original. 473 var originalProviderOptions = GetProviderOptions(codeDomProviderType); 474 IDictionary<string, string> providerOptions = null; 475 if (originalProviderOptions != null) { 476 providerOptions = new Dictionary<string, string>(originalProviderOptions); 477 } else { 478 providerOptions = new Dictionary<string, string>(); 479 } 480 481 // Block CompilerDirectoryPath if we are in partial trust 482 CheckCompilerDirectoryPathAllowed(providerOptions); 483 484 // Check whether the user supplied the compilerDirectoryPath or was it added by us 485 bool addedCompilerDirectoryPath = false; 486 487 if (MultiTargetingUtil.IsTargetFramework20) { 488 // If the target framework is v2.0, there won't be any codedom settings, so we need 489 // to explicitly set the compiler to be the v2.0 compiler using compilerVersion=v2.0. 490 providerOptions["CompilerVersion"] = "v2.0"; 491 } 492 else if (MultiTargetingUtil.IsTargetFramework35) { 493 // We need to explicitly set to v3.5, as it is possible for the 494 // user to only have specified it for one compiler but not 495 // the other. 496 // Dev10 bug 809212 497 providerOptions["CompilerVersion"] = "v3.5"; 498 } 499 else { 500 // If we are targeting 4.0 but the compiler version is less than 4.0, set it to 4.0. 501 // This can happen if a user tries to run a 2.0/3.5 web site in a 4.0 application pool without 502 // upgrading it, and the codedom section still has 3.5 as the compilerVersion, 503 // so we have to set the compilerVersion to 4.0 explicitly. 504 string version = GetCompilerVersion(codeDomProviderType); 505 Version v = GetVersionFromVString(version); 506 if (v != null && v < MultiTargetingUtil.Version40) { 507 providerOptions["CompilerVersion"] = "v4.0"; 508 } 509 } 510 511 if (providerOptions != null && providerOptions.Count > 0) { 512 Debug.Assert(codeDomProviderType != null, "codeDomProviderType should not be null"); 513 // Check whether the codedom provider supports a constructor that takes in providerOptions. 514 // Currently only VB and C# support providerOptions for sure, while others such as JScript might not. 515 ConstructorInfo ci = codeDomProviderType.GetConstructor(new Type[] { typeof(IDictionary<string, string>) }); 516 CodeDomProvider provider = null; 517 if (ci != null) { 518 // First, obtain the language for the given codedom provider type. 519 CodeDomProvider defaultProvider = (CodeDomProvider)Activator.CreateInstance(codeDomProviderType); 520 string extension = defaultProvider.FileExtension; 521 var language = CodeDomProvider.GetLanguageFromExtension(extension); 522 // Then, use the new createProvider API to create an instance. 523 provider = CodeDomProvider.CreateProvider(language, providerOptions); 524 } 525 // Restore the provider options if we previously manually added the compilerDirectoryPath. 526 // Otherwise, we might incorrectly invalidate the compilerDirectoryPath in medium trust (Dev10 bug 550299). 527 if (addedCompilerDirectoryPath) { 528 providerOptions.Remove(CompilerDirectoryPath); 529 } 530 return provider; 531 } 532 533 return null; 534 } 535 536 [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)] GetProviderOptions(Type codeDomProviderType)537 internal static IDictionary<string, string> GetProviderOptions(Type codeDomProviderType) { 538 // Using reflection to get the property for the time being. 539 // This could simply return CompilerInfo.PropertyOptions if it goes public in future. 540 CodeDomProvider provider = (CodeDomProvider)Activator.CreateInstance(codeDomProviderType); 541 string extension = provider.FileExtension; 542 if (CodeDomProvider.IsDefinedExtension(extension)) { 543 CompilerInfo ci = CodeDomProvider.GetCompilerInfo(CodeDomProvider.GetLanguageFromExtension(extension)); 544 return GetProviderOptions(ci); 545 } 546 return null; 547 } 548 549 [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)] GetProviderOptions(CompilerInfo ci)550 private static IDictionary<string, string> GetProviderOptions(CompilerInfo ci) { 551 Debug.Assert(ci != null, "CompilerInfo ci should not be null"); 552 PropertyInfo pi = ci.GetType().GetProperty("ProviderOptions", 553 BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance); 554 if (pi != null) 555 return (IDictionary<string, string>)pi.GetValue(ci, null); 556 return null; 557 } 558 559 /// <summary> 560 /// Returns the compilerVersion providerOption specified for the codedom provider type. 561 /// Returns null if the providerOption is not found. 562 /// </summary> GetCompilerVersion(Type codeDomProviderType)563 internal static string GetCompilerVersion(Type codeDomProviderType) { 564 return GetProviderOption(codeDomProviderType, "CompilerVersion"); 565 } 566 567 /// <summary> 568 /// Returns the value of the providerOption specified for the codedom provider type. 569 /// Returns null if the providerOption is not found. 570 /// </summary> GetProviderOption(Type codeDomProviderType, string providerOption)571 internal static string GetProviderOption(Type codeDomProviderType, string providerOption) { 572 IDictionary<string, string> providerOptions = CompilationUtil.GetProviderOptions(codeDomProviderType); 573 if (providerOptions != null) { 574 string version; 575 if (providerOptions.TryGetValue(providerOption, out version)) { 576 return version; 577 } 578 } 579 return null; 580 } 581 582 /// <summary> 583 /// Returns true if the string matches "v3.5" exactly. 584 /// </summary> IsCompilerVersion35(string compilerVersion)585 internal static bool IsCompilerVersion35(string compilerVersion) { 586 if (compilerVersion == "v3.5") { 587 return true; 588 } 589 return false; 590 } 591 592 /// <summary> 593 /// This returns true only if the codedom CompilverVersion provider option is exactly v3.5. 594 /// </summary> IsCompilerVersion35(Type codeDomProviderType)595 internal static bool IsCompilerVersion35(Type codeDomProviderType) { 596 string compilerVersion = GetCompilerVersion(codeDomProviderType); 597 bool result = IsCompilerVersion35(compilerVersion); 598 return result; 599 } 600 601 /// <summary> 602 /// Returns true if the codedom CompilerVersion provider option is at least v3.5. 603 /// </summary> 604 /// <param name="codeDomProviderType"></param> 605 /// <returns></returns> IsCompilerVersion35OrAbove(Type codeDomProviderType)606 internal static bool IsCompilerVersion35OrAbove(Type codeDomProviderType) { 607 string compilerVersion = GetCompilerVersion(codeDomProviderType); 608 if (IsCompilerVersion35(compilerVersion)) { 609 return true; 610 } 611 // The compilerVersion provider option is known to exist only for v3.5. 612 // If it does not exist, then we need to rely on the target framework version to 613 // determine whether we need to use the 2.0 or 4.0 compiler. 614 if (MultiTargetingUtil.IsTargetFramework20) { 615 return false; 616 } 617 618 // If it isn't 2.0 or 3.5, assume it is 4.0 and above. 619 return true; 620 } 621 622 /// <summary> 623 /// Returns true if the codedom provider has warnAsError set to true 624 /// </summary> WarnAsError(Type codeDomProviderType)625 internal static bool WarnAsError(Type codeDomProviderType) { 626 string value = GetProviderOption(codeDomProviderType, "WarnAsError"); 627 bool result; 628 if (value != null && bool.TryParse(value, out result)) { 629 return result; 630 } 631 632 // Assume false if the value wasn't set 633 return false; 634 } 635 636 // Returns the version when given string of form "v4.0" GetVersionFromVString(string version)637 internal static Version GetVersionFromVString(string version) { 638 if (string.IsNullOrEmpty(version)) { 639 return null; 640 } 641 Debug.Assert(version.Length > 1, "Version has invalid length"); 642 return new Version(version.Substring(1)); 643 } 644 645 // Returns maximum number of concurrent compilations 646 internal static int MaxConcurrentCompilations { 647 get { 648 if (_maxConcurrentCompilations == 0) { 649 int maxConcurrentCompilations; 650 651 if (AppSettings.MaxConcurrentCompilations.HasValue && AppSettings.MaxConcurrentCompilations.Value >= 0) { 652 maxConcurrentCompilations = AppSettings.MaxConcurrentCompilations.Value; 653 } 654 else { 655 CompilationSection config = MTConfigUtil.GetCompilationAppConfig(); 656 maxConcurrentCompilations = config.MaxConcurrentCompilations; 657 } 658 659 if (maxConcurrentCompilations <= 0) { 660 maxConcurrentCompilations = Environment.ProcessorCount; 661 } 662 663 Interlocked.CompareExchange(ref _maxConcurrentCompilations, maxConcurrentCompilations, 0); 664 } 665 666 return _maxConcurrentCompilations; 667 } 668 } 669 } 670 } 671