1 //------------------------------------------------------------------------------
2 // <copyright file="ObjectFactoryCodeDomTreeGenerator.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 // This code is used to optimize the instantiation of generated types.
8 
9 
10 namespace System.Web.Compilation {
11 
12 using System;
13 using System.Collections;
14 using System.Reflection;
15 using System.Security.Permissions;
16 using System.Globalization;
17 using System.CodeDom;
18 using System.CodeDom.Compiler;
19 using System.Web.Util;
20 using Util = System.Web.UI.Util;
21 
22 
InstantiateObject()23 internal delegate object InstantiateObject();
24 
25 internal class ObjectFactoryCodeDomTreeGenerator {
26 
27     private CodeCompileUnit _codeCompileUnit;
28     private CodeTypeDeclaration _factoryClass;
29 
30     private const string factoryClassNameBase = "FastObjectFactory_";
31     private const string factoryFullClassNameBase = BaseCodeDomTreeGenerator.internalAspNamespace +
32         "." + factoryClassNameBase;
33 
ObjectFactoryCodeDomTreeGenerator(string outputAssemblyName)34     internal ObjectFactoryCodeDomTreeGenerator(string outputAssemblyName) {
35 
36         _codeCompileUnit = new CodeCompileUnit();
37 
38         CodeNamespace sourceDataNamespace = new CodeNamespace(
39             BaseCodeDomTreeGenerator.internalAspNamespace);
40         _codeCompileUnit.Namespaces.Add(sourceDataNamespace);
41 
42         // Make the class name vary based on the assembly (VSWhidbey 363214)
43         string factoryClassName = factoryClassNameBase +
44             Util.MakeValidTypeNameFromString(outputAssemblyName).ToLower(CultureInfo.InvariantCulture);
45 
46         // Create a single class, in which a method will be added for each
47         // type that needs to be fast created in this assembly
48         _factoryClass = new CodeTypeDeclaration(factoryClassName);
49 
50         // Make the class internal (VSWhidbey 363214)
51         _factoryClass.TypeAttributes &= ~TypeAttributes.Public;
52 
53         // We generate a dummy line pragma, just so it will end with a '#line hidden'
54         // and prevent the following generated code from ever being treated as user
55         // code.  We need to use this hack because CodeDOM doesn't allow simply generating
56         // a '#line hidden'. (VSWhidbey 199384)
57         CodeSnippetTypeMember dummySnippet = new CodeSnippetTypeMember(String.Empty);
58 #if !PLATFORM_UNIX /// Unix file system
59         // CORIOLISTODO: Unix file system
60         dummySnippet.LinePragma = new CodeLinePragma(@"c:\\dummy.txt", 1);
61 #else // !PLATFORM_UNIX
62         dummySnippet.LinePragma = new CodeLinePragma(@"/dummy.txt", 1);
63 #endif // !PLATFORM_UNIX
64         _factoryClass.Members.Add(dummySnippet);
65 
66         // Add a private default ctor to make the class non-instantiatable (VSWhidbey 340829)
67         CodeConstructor ctor = new CodeConstructor();
68         ctor.Attributes |= MemberAttributes.Private;
69         _factoryClass.Members.Add(ctor);
70 
71         sourceDataNamespace.Types.Add(_factoryClass);
72     }
73 
AddFactoryMethod(string typeToCreate)74     internal void AddFactoryMethod(string typeToCreate) {
75 
76         // Generate a simple factory method for this type.  e.g.
77         // static object Create_Acme_Foo() {
78         //     return new ASP.foo_aspx();
79         // }
80 
81         CodeMemberMethod method = new CodeMemberMethod();
82         method.Name = GetCreateMethodNameForType(typeToCreate);
83         method.ReturnType = new CodeTypeReference(typeof(object));
84         method.Attributes = MemberAttributes.Static;
85 
86         CodeMethodReturnStatement cmrs = new CodeMethodReturnStatement(
87             new CodeObjectCreateExpression(typeToCreate));
88         method.Statements.Add(cmrs);
89 
90         _factoryClass.Members.Add(method);
91     }
92 
GetCreateMethodNameForType(string typeToCreate)93     private static string GetCreateMethodNameForType(string typeToCreate) {
94         return "Create_" + Util.MakeValidTypeNameFromString(typeToCreate);
95     }
96 
97     internal CodeCompileUnit CodeCompileUnit {
98         get { return _codeCompileUnit; }
99     }
100 
101     // Get the factory delegate for this type
102     // Could be called with user code on the stack, so need to assert here
103     // e.g. This can happen during a Server.Transfer, or a LoadControl.
104     [ReflectionPermission(SecurityAction.Assert, Flags = ReflectionPermissionFlag.MemberAccess)]
GetFastObjectCreationDelegate(Type t)105     internal static InstantiateObject GetFastObjectCreationDelegate(Type t) {
106         // Look for the factory class in the same assembly
107         Assembly a = t.Assembly;
108 
109         string shortAssemblyName = Util.GetAssemblyShortName(t.Assembly);
110         shortAssemblyName = shortAssemblyName.ToLower(CultureInfo.InvariantCulture);
111         Type factoryType = a.GetType(factoryFullClassNameBase + Util.MakeValidTypeNameFromString(shortAssemblyName));
112         if (factoryType == null)
113             return null;
114 
115         string methodName = GetCreateMethodNameForType(t.FullName);
116 
117         try {
118             return (InstantiateObject) Delegate.CreateDelegate(
119                 typeof(InstantiateObject), factoryType, methodName);
120         }
121         catch {
122             return null;
123         }
124     }
125 }
126 
127 }
128 
129