1 using System; 2 using System.Collections.Concurrent; 3 using System.Configuration; 4 using System.Web; 5 using System.Web.Compilation; 6 using System.Web.Configuration; 7 using System.Web.Hosting; 8 using Microsoft.Build.Utilities; 9 10 // Helper class to use 2.0 root config as necessary. Each helper method will 11 // go through RuntimeConfig (the original code path), except in the 12 // case of building and targeting 2.0/3.5. 13 internal class MTConfigUtil { 14 15 private static readonly ConcurrentDictionary<Tuple<Type, VirtualPath>, ConfigurationSection> s_sections = 16 new ConcurrentDictionary<Tuple<Type, VirtualPath>, ConfigurationSection>(); 17 18 private static readonly ConcurrentDictionary<VirtualPath, Configuration> s_configurations = 19 new ConcurrentDictionary<VirtualPath, Configuration>(); 20 21 private static string s_machineConfigPath; 22 private static VirtualPath s_appVirtualPath; 23 24 // We only need to use the root config of 2.0 if we are building (and 25 // not during runtime) and targeting 2.0 or 3.5. 26 static private bool? s_useMTConfig; 27 static private bool UseMTConfig { 28 get { 29 if (s_useMTConfig == null) { 30 s_useMTConfig = BuildManagerHost.InClientBuildManager && 31 (MultiTargetingUtil.IsTargetFramework20 || MultiTargetingUtil.IsTargetFramework35); 32 } 33 return s_useMTConfig.Value; 34 } 35 } 36 37 // Counterpart for RuntimeConfig.GetAppConfig().Profile; GetProfileAppConfig()38 static internal ProfileSection GetProfileAppConfig() { 39 if (!UseMTConfig) { 40 return RuntimeConfig.GetAppConfig().Profile; 41 } 42 return GetAppConfig<ProfileSection>(); 43 } 44 45 // Counterpart for RuntimeConfig.GetAppConfig().Pages; GetPagesAppConfig()46 static internal PagesSection GetPagesAppConfig() { 47 if (!UseMTConfig) { 48 return RuntimeConfig.GetAppConfig().Pages; 49 } 50 return GetAppConfig<PagesSection>(); 51 } 52 53 // Counterpart for RuntimeConfig.GetConfig().Pages; GetPagesConfig()54 static internal PagesSection GetPagesConfig() { 55 if (!UseMTConfig) { 56 return RuntimeConfig.GetConfig().Pages; 57 } 58 return GetConfig<PagesSection>(); 59 } 60 61 // Counterpart for RuntimeConfig.GetConfig(string).Pages GetPagesConfig(string vpath)62 static internal PagesSection GetPagesConfig(string vpath) { 63 if (!UseMTConfig) { 64 return RuntimeConfig.GetConfig(vpath).Pages; 65 } 66 return GetConfig<PagesSection>(vpath); 67 } 68 69 // Counterpart for RuntimeConfig.GetConfig(VirtualPath).Pages GetPagesConfig(VirtualPath vpath)70 static internal PagesSection GetPagesConfig(VirtualPath vpath) { 71 if (!UseMTConfig) { 72 return RuntimeConfig.GetConfig(vpath).Pages; 73 } 74 return GetConfig<PagesSection>(vpath); 75 } 76 77 // Counterpart for RuntimeConfig.GetConfig(HttpContext).Pages GetPagesConfig(HttpContext context)78 static internal PagesSection GetPagesConfig(HttpContext context) { 79 if (!UseMTConfig) { 80 return RuntimeConfig.GetConfig(context).Pages; 81 } 82 return GetConfig<PagesSection>(context); 83 } 84 85 // Counterpart for RuntimeConfig.GetConfig().Compilation GetCompilationConfig()86 static internal CompilationSection GetCompilationConfig() { 87 if (!UseMTConfig) { 88 return RuntimeConfig.GetConfig().Compilation; 89 } 90 return GetConfig<CompilationSection>(); 91 } 92 93 // Counterpart for RuntimeConfig.GetAppConfig().Compilation GetCompilationAppConfig()94 static internal CompilationSection GetCompilationAppConfig() { 95 if (!UseMTConfig) { 96 return RuntimeConfig.GetAppConfig().Compilation; 97 } 98 return GetAppConfig<CompilationSection>(); 99 } 100 101 // Counterpart for RuntimeConfig.GetConfig(string).Compilation GetCompilationConfig(string vpath)102 static internal CompilationSection GetCompilationConfig(string vpath) { 103 if (!UseMTConfig) { 104 return RuntimeConfig.GetConfig(vpath).Compilation; 105 } 106 return GetConfig<CompilationSection>(vpath); 107 } 108 109 // Counterpart for RuntimeConfig.GetConfig(VirtualPath).Compilation GetCompilationConfig(VirtualPath vpath)110 static internal CompilationSection GetCompilationConfig(VirtualPath vpath) { 111 if (!UseMTConfig) { 112 return RuntimeConfig.GetConfig(vpath).Compilation; 113 } 114 return GetConfig<CompilationSection>(vpath); 115 } 116 117 // Counterpart for RuntimeConfig.GetConfig(HttpContext).Compilation GetCompilationConfig(HttpContext context)118 static internal CompilationSection GetCompilationConfig(HttpContext context) { 119 if (!UseMTConfig) { 120 return RuntimeConfig.GetConfig(context).Compilation; 121 } 122 return GetConfig<CompilationSection>(context); 123 } 124 125 // Counterpart to RuntimeConfig.GetConfig() 126 static private S GetConfig<S>() where S : ConfigurationSection { 127 HttpContext context = HttpContext.Current; 128 if (context != null) { 129 return GetConfig<S>(context); 130 } 131 else { 132 return GetAppConfig<S>(); 133 } 134 } 135 136 // Counterpart to RuntimeConfig.GetAppConfig() 137 static private S GetAppConfig<S>() where S : ConfigurationSection { 138 return GetConfig<S>((VirtualPath) null); 139 } 140 141 // Counterpart to RuntimeConfig.GetConfig(HttpContext) 142 static private S GetConfig<S>(HttpContext context) where S : ConfigurationSection { 143 return GetConfig<S>(context.ConfigurationPath); 144 } 145 146 // Counterpart to RuntimeConfig.GetConfig(string) 147 static private S GetConfig<S>(string vpath) where S : ConfigurationSection{ 148 return GetConfig<S>(VirtualPath.CreateNonRelativeAllowNull(vpath)); 149 } 150 151 // Counterpart to RuntimeConfig.GetConfig(VirtualPath) 152 static private S GetConfig<S>(VirtualPath vpath) where S : ConfigurationSection { 153 Tuple<Type, VirtualPath> key = new Tuple<Type, VirtualPath>(typeof(S), vpath); 154 ConfigurationSection result; 155 if (!s_sections.TryGetValue(key, out result)) { 156 result = GetConfigHelper<S>(vpath); 157 s_sections.TryAdd(key, result); 158 } 159 return result as S; 160 } 161 162 // Actual method performing to work to retrieve the required ConfigurationSection. 163 static private S GetConfigHelper<S>(VirtualPath vpath) where S : ConfigurationSection{ 164 string physicalPath = null; 165 if (vpath == null || !vpath.IsWithinAppRoot) { 166 // If virtual path is null or outside the application root, we use the application level config. 167 vpath = HostingEnvironment.ApplicationVirtualPathObject; 168 physicalPath = HostingEnvironment.ApplicationPhysicalPath; 169 } 170 else { 171 // If it is not a directory, use the directory as the vpath 172 if (!vpath.DirectoryExists()) { 173 vpath = vpath.Parent; 174 } 175 physicalPath = HostingEnvironment.MapPath(vpath); 176 } 177 178 Configuration config = GetConfiguration(vpath, physicalPath); 179 180 // Retrieve the specified section 181 if (typeof(S) == typeof(CompilationSection)) { 182 return config.GetSection("system.web/compilation") as S; 183 } 184 else if (typeof(S) == typeof(PagesSection)) { 185 return config.GetSection("system.web/pages") as S; 186 } 187 else if (typeof(S) == typeof(ProfileSection)) { 188 return config.GetSection("system.web/profile") as S; 189 } 190 191 throw new InvalidOperationException(SR.GetString(SR.Config_section_not_supported, typeof(S).FullName)); 192 } 193 194 static private string MachineConfigPath { 195 get { 196 if (s_machineConfigPath == null) { 197 s_machineConfigPath = ToolLocationHelper.GetPathToDotNetFrameworkFile(@"config\machine.config", TargetDotNetFrameworkVersion.Version20); 198 if (string.IsNullOrEmpty(s_machineConfigPath)) { 199 string message = SR.GetString(SR.Downlevel_requires_35); 200 throw new InvalidOperationException(message); 201 } 202 } 203 return s_machineConfigPath; 204 } 205 } 206 GetConfiguration(VirtualPath vpath, string physicalPath)207 static private Configuration GetConfiguration(VirtualPath vpath, string physicalPath) { 208 Configuration result; 209 if (!s_configurations.TryGetValue(vpath, out result)) { 210 result = GetConfigurationHelper(vpath, physicalPath); 211 s_configurations.TryAdd(vpath, result); 212 } 213 return result; 214 } 215 GetConfigurationHelper(VirtualPath vpath, string physicalPath)216 static private Configuration GetConfigurationHelper(VirtualPath vpath, string physicalPath) { 217 // Set up the configuration file map 218 string machineConfigPath = MachineConfigPath; 219 WebConfigurationFileMap fileMap = new WebConfigurationFileMap(machineConfigPath); 220 221 // Set up file maps for the current directory and parent directories up to application root 222 VirtualPath currentVPath = vpath; 223 while (currentVPath != null && currentVPath.IsWithinAppRoot) { 224 string vpathString = currentVPath.VirtualPathStringNoTrailingSlash; 225 if (physicalPath == null) { 226 physicalPath = HostingEnvironment.MapPath(currentVPath); 227 } 228 fileMap.VirtualDirectories.Add(vpathString, new VirtualDirectoryMapping(physicalPath, IsAppRoot(currentVPath))); 229 currentVPath = currentVPath.Parent; 230 physicalPath = null; 231 } 232 233 Configuration config = WebConfigurationManager.OpenMappedWebConfiguration(fileMap, vpath.VirtualPathStringNoTrailingSlash, HostingEnvironment.SiteName); 234 return config; 235 } 236 IsAppRoot(VirtualPath path)237 static private bool IsAppRoot(VirtualPath path) { 238 if (s_appVirtualPath == null) { 239 s_appVirtualPath = VirtualPath.Create(HttpRuntime.AppDomainAppVirtualPathObject.VirtualPathStringNoTrailingSlash); 240 } 241 242 var vpath = VirtualPath.Create(path.VirtualPathStringNoTrailingSlash); 243 return s_appVirtualPath.Equals(vpath); 244 } 245 246 } 247