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()23internal 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