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