2 // System.Web.Compilation.AspComponentFoundry
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2002,2003 Ximian, Inc (http://www.ximian.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
33 using System.Reflection;
36 using System.Collections.Generic;
38 using System.Web.Configuration;
42 namespace System.Web.Compilation
44 internal class AspComponentFoundry
48 Dictionary <string, AspComponent> components;
54 Dictionary <string, AspComponent> Components {
56 if (components == null)
57 components = new Dictionary <string, AspComponent> (StringComparer.OrdinalIgnoreCase);
62 Hashtable Components {
64 if (components == null)
65 components = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant, CaseInsensitiveComparer.DefaultInvariant);
71 public AspComponentFoundry ()
74 foundries = new Hashtable (StringComparer.InvariantCultureIgnoreCase);
76 foundries = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant,
77 CaseInsensitiveComparer.DefaultInvariant);
80 Assembly sw = typeof (AspComponentFoundry).Assembly;
81 RegisterFoundry ("asp", sw, "System.Web.UI.WebControls");
82 RegisterFoundry ("", "object", typeof (System.Web.UI.ObjectTag));
85 RegisterConfigControls ();
89 public AspComponent GetComponent (string tagName)
91 if (tagName == null || tagName.Length == 0)
94 if (components != null) {
97 if (components.TryGetValue (tagName, out ret))
100 if (components.Contains (tagName))
101 return components [tagName] as AspComponent;
105 string foundryName, tag;
106 int colon = tagName.IndexOf (':');
109 throw new Exception ("Empty TagPrefix is not valid.");
110 if (colon + 1 == tagName.Length)
112 foundryName = tagName.Substring (0, colon);
113 tag = tagName.Substring (colon + 1);
115 foundryName = String.Empty;
119 object o = foundries [foundryName];
123 Foundry foundry = o as Foundry;
125 return CreateComponent (foundry, tagName, foundryName, tag);
127 ArrayList af = o as ArrayList;
131 AspComponent component = null;
133 foreach (Foundry f in af) {
135 component = CreateComponent (f, tagName, foundryName, tag);
136 if (component != null)
138 } catch (Exception ex) {
149 AspComponent CreateComponent (Foundry foundry, string tagName, string prefix, string tag)
154 type = foundry.GetType (tag, out source, out ns);
158 AspComponent ret = new AspComponent (type, ns, prefix, source, foundry.FromConfig);
160 Dictionary <string, AspComponent> components = Components;
162 Hashtable components = Components;
164 components.Add (tagName, ret);
168 public void RegisterFoundry (string foundryName, Assembly assembly, string nameSpace)
170 RegisterFoundry (foundryName, assembly, nameSpace, false);
173 public void RegisterFoundry (string foundryName,
178 AssemblyFoundry foundry = new AssemblyFoundry (assembly, nameSpace);
179 foundry.FromConfig = fromConfig;
180 InternalRegister (foundryName, foundry, fromConfig);
183 public void RegisterFoundry (string foundryName, string tagName, Type type)
185 RegisterFoundry (foundryName, tagName, type, false);
188 public void RegisterFoundry (string foundryName,
193 TagNameFoundry foundry = new TagNameFoundry (tagName, type);
194 foundry.FromConfig = fromConfig;
195 InternalRegister (foundryName, foundry, fromConfig);
199 public void RegisterFoundry (string foundryName, string tagName, string source)
201 RegisterFoundry (foundryName, tagName, source, false);
204 public void RegisterFoundry (string foundryName,
209 TagNameFoundry foundry = new TagNameFoundry (tagName, source);
210 foundry.FromConfig = fromConfig;
211 InternalRegister (foundryName, foundry, fromConfig);
214 public void RegisterAssemblyFoundry (string foundryName,
219 AssemblyFoundry foundry = new AssemblyFoundry (assemblyName, nameSpace);
220 foundry.FromConfig = fromConfig;
221 InternalRegister (foundryName, foundry, fromConfig);
224 void RegisterConfigControls ()
226 PagesSection pages = WebConfigurationManager.GetSection ("system.web/pages") as PagesSection;
230 TagPrefixCollection controls = pages.Controls;
231 if (controls == null || controls.Count == 0)
234 IList appCode = BuildManager.CodeAssemblies;
235 bool haveCodeAssemblies = appCode != null && appCode.Count > 0;
237 foreach (TagPrefixInfo tpi in controls) {
238 if (!String.IsNullOrEmpty (tpi.TagName))
239 RegisterFoundry (tpi.TagPrefix, tpi.TagName, tpi.Source, true);
240 else if (String.IsNullOrEmpty (tpi.Assembly)) {
241 if (haveCodeAssemblies) {
242 foreach (object o in appCode) {
246 RegisterFoundry (tpi.TagPrefix, asm, tpi.Namespace, true);
249 } else if (!String.IsNullOrEmpty (tpi.Namespace))
250 RegisterAssemblyFoundry (tpi.TagPrefix,
258 void InternalRegister (string foundryName, Foundry foundry, bool fromConfig)
260 object f = foundries [foundryName];
261 Foundry newFoundry = null;
263 if (f is CompoundFoundry) {
264 ((CompoundFoundry) f).Add (foundry);
266 } else if (f == null || f is ArrayList || (f is AssemblyFoundry && foundry is AssemblyFoundry)) {
267 newFoundry = foundry;
268 } else if (f != null) {
269 CompoundFoundry compound = new CompoundFoundry (foundryName);
270 compound.Add ((Foundry) f);
271 compound.Add (foundry);
272 newFoundry = foundry;
273 newFoundry.FromConfig = fromConfig;
276 if (newFoundry == null)
280 foundries [foundryName] = newFoundry;
284 ArrayList af = f as ArrayList;
286 af = new ArrayList (2);
288 foundries [foundryName] = af;
291 if (newFoundry is AssemblyFoundry) {
293 for (int i = 0; i < af.Count; i++) {
295 if (o is AssemblyFoundry) {
296 af.Insert (i, newFoundry);
302 af.Insert (0, newFoundry);
305 public bool LookupFoundry (string foundryName)
307 return foundries.Contains (foundryName);
310 abstract class Foundry
314 public bool FromConfig {
315 get { return _fromConfig; }
316 set { _fromConfig = value; }
319 public abstract Type GetType (string componentName, out string source, out string ns);
323 class TagNameFoundry : Foundry
331 public bool FromWebConfig {
332 get { return source != null; }
335 public TagNameFoundry (string tagName, string source)
337 this.tagName = tagName;
338 this.source = source;
342 public TagNameFoundry (string tagName, Type type)
344 this.tagName = tagName;
348 public override Type GetType (string componentName, out string source, out string ns)
352 if (0 != String.Compare (componentName, tagName, true))
356 source = this.source;
367 HttpContext context = HttpContext.Current;
371 if (VirtualPathUtility.IsAppRelative (source)) {
373 realpath = context.Request.MapPath (source);
375 vpath = VirtualPathUtility.ToAppRelative (source);
379 if ((type = CachingCompiler.GetTypeFromCache (realpath)) != null)
382 ArrayList other_deps = new ArrayList ();
383 type = BuildManager.GetCompiledType (vpath);
385 AspGenerator.AddTypeToCache (other_deps, realpath, type);
386 BuildManager.AddToReferencedAssemblies (type.Assembly);
394 public string TagName {
395 get { return tagName; }
399 class AssemblyFoundry : Foundry
405 Dictionary <string, Assembly> assemblyCache;
408 public AssemblyFoundry (Assembly assembly, string nameSpace)
410 this.assembly = assembly;
411 this.nameSpace = nameSpace;
413 if (assembly != null)
414 this.assemblyName = assembly.FullName;
416 this.assemblyName = null;
421 public AssemblyFoundry (string assemblyName, string nameSpace)
423 this.assembly = null;
424 this.nameSpace = nameSpace;
425 this.assemblyName = assemblyName;
429 public override Type GetType (string componentName, out string source, out string ns)
435 if (assembly == null && assemblyName != null)
436 assembly = GetAssemblyByName (assemblyName, true);
438 string typeName = String.Concat (nameSpace, ".", componentName);
439 if (assembly != null)
440 return assembly.GetType (typeName, true, true);
443 IList tla = BuildManager.TopLevelAssemblies;
444 if (tla != null && tla.Count > 0) {
446 foreach (Assembly asm in tla) {
449 ret = asm.GetType (typeName, false, true);
459 Assembly GetAssemblyByName (string name, bool throwOnMissing)
461 if (assemblyCache == null)
462 assemblyCache = new Dictionary <string, Assembly> ();
464 if (assemblyCache.ContainsKey (name))
465 return assemblyCache [name];
467 Assembly assembly = null;
468 Exception error = null;
469 if (name.IndexOf (',') != -1) {
471 assembly = Assembly.Load (name);
472 } catch (Exception e) { error = e; }
475 if (assembly == null) {
477 assembly = Assembly.LoadWithPartialName (name);
478 } catch (Exception e) { error = e; }
481 if (assembly == null)
483 throw new HttpException ("Assembly " + name + " not found", error);
487 assemblyCache.Add (name, assembly);
493 class CompoundFoundry : Foundry
495 AssemblyFoundry assemblyFoundry;
499 public CompoundFoundry (string tagPrefix)
501 this.tagPrefix = tagPrefix;
503 tagnames = new Hashtable (StringComparer.InvariantCultureIgnoreCase);
505 tagnames = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant,
506 CaseInsensitiveComparer.DefaultInvariant);
510 public void Add (Foundry foundry)
512 if (foundry is AssemblyFoundry) {
513 assemblyFoundry = (AssemblyFoundry) foundry;
517 TagNameFoundry tn = (TagNameFoundry) foundry;
518 string tagName = tn.TagName;
519 if (tagnames.Contains (tagName)) {
521 if (tn.FromWebConfig)
524 string msg = String.Format ("{0}:{1} already registered.", tagPrefix, tagName);
525 throw new ApplicationException (msg);
527 tagnames.Add (tagName, foundry);
530 public override Type GetType (string componentName, out string source, out string ns)
535 Foundry foundry = tagnames [componentName] as Foundry;
537 return foundry.GetType (componentName, out source, out ns);
539 if (assemblyFoundry != null) {
541 type = assemblyFoundry.GetType (componentName, out source, out ns);
546 string msg = String.Format ("Type {0} not registered for prefix {1}", componentName, tagPrefix);
547 throw new ApplicationException (msg);