PageCompiler.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. //
  2. // System.Web.Compilation.PageCompiler
  3. //
  4. // Authors:
  5. // Gonzalo Paniagua Javier ([email protected])
  6. //
  7. // (C) 2002,2003 Ximian, Inc (http://www.ximian.com)
  8. //
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.CodeDom;
  31. using System.Collections;
  32. using System.Collections.Generic;
  33. using System.IO;
  34. using System.Reflection;
  35. using System.Text;
  36. using System.Web.Configuration;
  37. using System.Web.UI;
  38. using System.Web.SessionState;
  39. using System.Web.Util;
  40. using System.Web.Profile;
  41. namespace System.Web.Compilation
  42. {
  43. class PageCompiler : TemplateControlCompiler
  44. {
  45. PageParser pageParser;
  46. static CodeTypeReference intRef = new CodeTypeReference (typeof (int));
  47. public PageCompiler (PageParser pageParser)
  48. : base (pageParser)
  49. {
  50. this.pageParser = pageParser;
  51. }
  52. protected override void CreateStaticFields ()
  53. {
  54. base.CreateStaticFields ();
  55. CodeMemberField fld = new CodeMemberField (typeof (object), "__fileDependencies");
  56. fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
  57. fld.InitExpression = new CodePrimitiveExpression (null);
  58. mainClass.Members.Add (fld);
  59. if (pageParser.OutputCache) {
  60. fld = new CodeMemberField (typeof (OutputCacheParameters), "__outputCacheSettings");
  61. fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
  62. fld.InitExpression = new CodePrimitiveExpression (null);
  63. mainClass.Members.Add (fld);
  64. }
  65. }
  66. protected override void CreateConstructor (CodeStatementCollection localVars,
  67. CodeStatementCollection trueStmt)
  68. {
  69. if (!String.IsNullOrEmpty (pageParser.MasterPageFile))
  70. // This is here just to trigger master page build, so that its type
  71. // is available when compiling the page itself.
  72. BuildManager.GetCompiledType (pageParser.MasterPageFile);
  73. if (pageParser.ClientTarget != null) {
  74. CodeExpression prop;
  75. prop = new CodePropertyReferenceExpression (thisRef, "ClientTarget");
  76. CodeExpression ct = new CodePrimitiveExpression (pageParser.ClientTarget);
  77. if (localVars == null)
  78. localVars = new CodeStatementCollection ();
  79. localVars.Add (new CodeAssignStatement (prop, ct));
  80. }
  81. ArrayList deps = pageParser.Dependencies;
  82. int depsCount = deps != null ? deps.Count : 0;
  83. if (depsCount > 0) {
  84. if (localVars == null)
  85. localVars = new CodeStatementCollection ();
  86. if (trueStmt == null)
  87. trueStmt = new CodeStatementCollection ();
  88. CodeAssignStatement assign;
  89. localVars.Add (
  90. new CodeVariableDeclarationStatement (
  91. typeof (string[]),
  92. "dependencies")
  93. );
  94. CodeVariableReferenceExpression dependencies = new CodeVariableReferenceExpression ("dependencies");
  95. trueStmt.Add (
  96. new CodeAssignStatement (dependencies, new CodeArrayCreateExpression (typeof (string), depsCount))
  97. );
  98. CodeArrayIndexerExpression arrayIndex;
  99. object o;
  100. for (int i = 0; i < depsCount; i++) {
  101. o = deps [i];
  102. arrayIndex = new CodeArrayIndexerExpression (dependencies, new CodeExpression[] {new CodePrimitiveExpression (i)});
  103. assign = new CodeAssignStatement (arrayIndex, new CodePrimitiveExpression (o));
  104. trueStmt.Add (assign);
  105. }
  106. CodeMethodInvokeExpression getDepsCall = new CodeMethodInvokeExpression (
  107. thisRef,
  108. "GetWrappedFileDependencies",
  109. new CodeExpression[] {dependencies}
  110. );
  111. assign = new CodeAssignStatement (GetMainClassFieldReferenceExpression ("__fileDependencies"), getDepsCall);
  112. trueStmt.Add (assign);
  113. }
  114. base.CreateConstructor (localVars, trueStmt);
  115. }
  116. protected override void AddInterfaces ()
  117. {
  118. base.AddInterfaces ();
  119. CodeTypeReference cref;
  120. if (pageParser.EnableSessionState) {
  121. cref = new CodeTypeReference (typeof (IRequiresSessionState));
  122. if (partialClass != null)
  123. partialClass.BaseTypes.Add (cref);
  124. else
  125. mainClass.BaseTypes.Add (cref);
  126. }
  127. if (pageParser.ReadOnlySessionState) {
  128. cref = new CodeTypeReference (typeof (IReadOnlySessionState));
  129. if (partialClass != null)
  130. partialClass.BaseTypes.Add (cref);
  131. else
  132. mainClass.BaseTypes.Add (cref);
  133. }
  134. if (pageParser.Async)
  135. mainClass.BaseTypes.Add (new CodeTypeReference (typeof (System.Web.IHttpAsyncHandler)));
  136. mainClass.BaseTypes.Add (new CodeTypeReference (typeof (System.Web.IHttpHandler)));
  137. }
  138. void CreateGetTypeHashCode ()
  139. {
  140. CodeMemberMethod method = new CodeMemberMethod ();
  141. method.ReturnType = intRef;
  142. method.Name = "GetTypeHashCode";
  143. method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
  144. Random rnd = new Random (pageParser.InputFile.GetHashCode ());
  145. method.Statements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (rnd.Next ())));
  146. mainClass.Members.Add (method);
  147. }
  148. static CodeAssignStatement CreatePropertyAssign (CodeExpression expr, string name, object value)
  149. {
  150. CodePropertyReferenceExpression prop;
  151. prop = new CodePropertyReferenceExpression (expr, name);
  152. CodePrimitiveExpression prim;
  153. prim = new CodePrimitiveExpression (value);
  154. return new CodeAssignStatement (prop, prim);
  155. }
  156. static CodeAssignStatement CreatePropertyAssign (string name, object value)
  157. {
  158. return CreatePropertyAssign (thisRef, name, value);
  159. }
  160. void AddStatementsFromDirective (CodeMemberMethod method)
  161. {
  162. string responseEncoding = pageParser.ResponseEncoding;
  163. if (responseEncoding != null)
  164. method.Statements.Add (CreatePropertyAssign ("ResponseEncoding", responseEncoding));
  165. int codepage = pageParser.CodePage;
  166. if (codepage != -1)
  167. method.Statements.Add (CreatePropertyAssign ("CodePage", codepage));
  168. string contentType = pageParser.ContentType;
  169. if (contentType != null)
  170. method.Statements.Add (CreatePropertyAssign ("ContentType", contentType));
  171. int lcid = pageParser.LCID;
  172. if (lcid != -1)
  173. method.Statements.Add (CreatePropertyAssign ("LCID", lcid));
  174. string culture = pageParser.Culture;
  175. if (culture != null)
  176. method.Statements.Add (CreatePropertyAssign ("Culture", culture));
  177. culture = pageParser.UICulture;
  178. if (culture != null)
  179. method.Statements.Add (CreatePropertyAssign ("UICulture", culture));
  180. string errorPage = pageParser.ErrorPage;
  181. if (errorPage != null)
  182. method.Statements.Add (CreatePropertyAssign ("ErrorPage", errorPage));
  183. if (pageParser.HaveTrace) {
  184. CodeAssignStatement stmt = new CodeAssignStatement ();
  185. stmt.Left = new CodePropertyReferenceExpression (thisRef, "TraceEnabled");
  186. stmt.Right = new CodePrimitiveExpression (pageParser.Trace);
  187. method.Statements.Add (stmt);
  188. }
  189. if (pageParser.TraceMode != TraceMode.Default) {
  190. CodeAssignStatement stmt = new CodeAssignStatement ();
  191. CodeTypeReferenceExpression tm = new CodeTypeReferenceExpression ("System.Web.TraceMode");
  192. stmt.Left = new CodePropertyReferenceExpression (thisRef, "TraceModeValue");
  193. stmt.Right = new CodeFieldReferenceExpression (tm, pageParser.TraceMode.ToString ());
  194. method.Statements.Add (stmt);
  195. }
  196. if (pageParser.NotBuffer) {
  197. CodeAssignStatement stmt = new CodeAssignStatement ();
  198. stmt.Left = new CodePropertyReferenceExpression (thisRef, "Buffer");
  199. stmt.Right = new CodePrimitiveExpression (false);
  200. method.Statements.Add (stmt);
  201. }
  202. if (!pageParser.EnableEventValidation) {
  203. CodeAssignStatement stmt = new CodeAssignStatement ();
  204. CodePropertyReferenceExpression prop;
  205. prop = new CodePropertyReferenceExpression (thisRef, "EnableEventValidation");
  206. stmt.Left = prop;
  207. stmt.Right = new CodePrimitiveExpression (pageParser.EnableEventValidation);
  208. method.Statements.Add (stmt);
  209. }
  210. if (pageParser.MaintainScrollPositionOnPostBack) {
  211. CodeAssignStatement stmt = new CodeAssignStatement ();
  212. CodePropertyReferenceExpression prop;
  213. prop = new CodePropertyReferenceExpression (thisRef, "MaintainScrollPositionOnPostBack");
  214. stmt.Left = prop;
  215. stmt.Right = new CodePrimitiveExpression (pageParser.MaintainScrollPositionOnPostBack);
  216. method.Statements.Add (stmt);
  217. }
  218. }
  219. protected override void AddStatementsToConstructor (CodeConstructor ctor)
  220. {
  221. base.AddStatementsToConstructor (ctor);
  222. if (pageParser.OutputCache)
  223. OutputCacheParamsBlock (ctor);
  224. }
  225. protected override void AddStatementsToInitMethod (CodeMemberMethod method)
  226. {
  227. AddStatementsFromDirective (method);
  228. ILocation directiveLocation = pageParser.DirectiveLocation;
  229. CodeArgumentReferenceExpression ctrlVar = new CodeArgumentReferenceExpression("__ctrl");
  230. if (pageParser.Title != null)
  231. method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "Title", pageParser.Title), directiveLocation));
  232. if (pageParser.MasterPageFile != null)
  233. method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "MasterPageFile", pageParser.MasterPageFile), directiveLocation));
  234. if (pageParser.Theme != null)
  235. method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "Theme", pageParser.Theme), directiveLocation));
  236. if (pageParser.StyleSheetTheme != null)
  237. method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "StyleSheetTheme", pageParser.StyleSheetTheme), directiveLocation));
  238. if (pageParser.Async != false)
  239. method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "AsyncMode", pageParser.Async), directiveLocation));
  240. if (pageParser.AsyncTimeout != -1)
  241. method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "AsyncTimeout",
  242. TimeSpan.FromSeconds (pageParser.AsyncTimeout)), directiveLocation));
  243. CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (thisRef, "InitializeCulture");
  244. method.Statements.Add (AddLinePragma (new CodeExpressionStatement (expr), directiveLocation));
  245. }
  246. protected override void PrependStatementsToFrameworkInitialize (CodeMemberMethod method)
  247. {
  248. base.PrependStatementsToFrameworkInitialize (method);
  249. if (pageParser.StyleSheetTheme != null)
  250. method.Statements.Add (CreatePropertyAssign ("StyleSheetTheme", pageParser.StyleSheetTheme));
  251. }
  252. protected override void AppendStatementsToFrameworkInitialize (CodeMemberMethod method)
  253. {
  254. base.AppendStatementsToFrameworkInitialize (method);
  255. ArrayList deps = pageParser.Dependencies;
  256. int depsCount = deps != null ? deps.Count : 0;
  257. if (depsCount > 0) {
  258. CodeFieldReferenceExpression fileDependencies = GetMainClassFieldReferenceExpression ("__fileDependencies");
  259. method.Statements.Add (
  260. new CodeMethodInvokeExpression (
  261. thisRef,
  262. "AddWrappedFileDependencies",
  263. new CodeExpression[] {fileDependencies})
  264. );
  265. }
  266. if (pageParser.OutputCache) {
  267. CodeMethodReferenceExpression init = new CodeMethodReferenceExpression (thisRef, "InitOutputCache");
  268. CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (init, GetMainClassFieldReferenceExpression ("__outputCacheSettings"));
  269. method.Statements.Add (invoke);
  270. }
  271. if (pageParser.ValidateRequest) {
  272. CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression ();
  273. CodePropertyReferenceExpression prop;
  274. prop = new CodePropertyReferenceExpression (thisRef, "Request");
  275. expr.Method = new CodeMethodReferenceExpression (prop, "ValidateInput");
  276. method.Statements.Add (expr);
  277. }
  278. }
  279. CodeAssignStatement AssignOutputCacheParameter (CodeVariableReferenceExpression variable, string propName, object value)
  280. {
  281. var ret = new CodeAssignStatement ();
  282. ret.Left = new CodeFieldReferenceExpression (variable, propName);
  283. if (value is OutputCacheLocation)
  284. ret.Right = new CodeFieldReferenceExpression (
  285. new CodeTypeReferenceExpression (new CodeTypeReference (typeof (OutputCacheLocation), CodeTypeReferenceOptions.GlobalReference)),
  286. value.ToString ()
  287. );
  288. else
  289. ret.Right = new CodePrimitiveExpression (value);
  290. return ret;
  291. }
  292. void OutputCacheParamsBlock (CodeMemberMethod method)
  293. {
  294. var statements = new List <CodeStatement> ();
  295. var localSettingsDecl = new CodeVariableDeclarationStatement (typeof (OutputCacheParameters), "outputCacheSettings");
  296. var localSettings = new CodeVariableReferenceExpression ("outputCacheSettings");
  297. statements.Add (localSettingsDecl);
  298. statements.Add (
  299. new CodeAssignStatement (
  300. localSettings,
  301. new CodeObjectCreateExpression (typeof (OutputCacheParameters), new CodeExpression[] {})
  302. )
  303. );
  304. TemplateParser.OutputCacheParsedParams parsed = pageParser.OutputCacheParsedParameters;
  305. if ((parsed & TemplateParser.OutputCacheParsedParams.CacheProfile) != 0)
  306. statements.Add (AssignOutputCacheParameter (localSettings, "CacheProfile", pageParser.OutputCacheCacheProfile));
  307. statements.Add (AssignOutputCacheParameter (localSettings, "Duration", pageParser.OutputCacheDuration));
  308. if ((parsed & TemplateParser.OutputCacheParsedParams.Location) != 0)
  309. statements.Add (AssignOutputCacheParameter (localSettings, "Location", pageParser.OutputCacheLocation));
  310. if ((parsed & TemplateParser.OutputCacheParsedParams.NoStore) != 0)
  311. statements.Add (AssignOutputCacheParameter (localSettings, "NoStore", pageParser.OutputCacheNoStore));
  312. if ((parsed & TemplateParser.OutputCacheParsedParams.SqlDependency) != 0)
  313. statements.Add (AssignOutputCacheParameter (localSettings, "SqlDependency", pageParser.OutputCacheSqlDependency));
  314. if ((parsed & TemplateParser.OutputCacheParsedParams.VaryByContentEncodings) != 0)
  315. statements.Add (AssignOutputCacheParameter (localSettings, "VaryByContentEncoding", pageParser.OutputCacheVaryByContentEncodings));
  316. if ((parsed & TemplateParser.OutputCacheParsedParams.VaryByControl) != 0)
  317. statements.Add (AssignOutputCacheParameter (localSettings, "VaryByControl", pageParser.OutputCacheVaryByControls));
  318. if ((parsed & TemplateParser.OutputCacheParsedParams.VaryByCustom) != 0)
  319. statements.Add (AssignOutputCacheParameter (localSettings, "VaryByCustom", pageParser.OutputCacheVaryByCustom));
  320. if ((parsed & TemplateParser.OutputCacheParsedParams.VaryByHeader) != 0)
  321. statements.Add (AssignOutputCacheParameter (localSettings, "VaryByHeader", pageParser.OutputCacheVaryByHeader));
  322. statements.Add (AssignOutputCacheParameter (localSettings, "VaryByParam", pageParser.OutputCacheVaryByParam));
  323. CodeFieldReferenceExpression outputCacheSettings = GetMainClassFieldReferenceExpression ("__outputCacheSettings");
  324. statements.Add (new CodeAssignStatement (outputCacheSettings, localSettings));
  325. var cond = new CodeConditionStatement (
  326. new CodeBinaryOperatorExpression (
  327. outputCacheSettings,
  328. CodeBinaryOperatorType.IdentityEquality,
  329. new CodePrimitiveExpression (null)
  330. ),
  331. statements.ToArray ()
  332. );
  333. method.Statements.Add (cond);
  334. }
  335. void CreateStronglyTypedProperty (Type type, string name)
  336. {
  337. if (type == null)
  338. return;
  339. CodeMemberProperty mprop = new CodeMemberProperty ();
  340. mprop.Name = name;
  341. mprop.Type = new CodeTypeReference (type);
  342. mprop.Attributes = MemberAttributes.Public | MemberAttributes.New;
  343. CodeExpression prop = new CodePropertyReferenceExpression (new CodeBaseReferenceExpression (), name);
  344. prop = new CodeCastExpression (type, prop);
  345. mprop.GetStatements.Add (new CodeMethodReturnStatement (prop));
  346. if (partialClass != null)
  347. partialClass.Members.Add (mprop);
  348. else
  349. mainClass.Members.Add (mprop);
  350. AddReferencedAssembly (type.Assembly);
  351. }
  352. protected internal override void CreateMethods ()
  353. {
  354. base.CreateMethods ();
  355. CreateProfileProperty ();
  356. CreateStronglyTypedProperty (pageParser.MasterType, "Master");
  357. CreateStronglyTypedProperty (pageParser.PreviousPageType, "PreviousPage");
  358. CreateGetTypeHashCode ();
  359. if (pageParser.Async)
  360. CreateAsyncMethods ();
  361. }
  362. void CreateAsyncMethods ()
  363. {
  364. CodeMemberMethod method = new CodeMemberMethod ();
  365. CodeParameterDeclarationExpression arg;
  366. CodeMethodInvokeExpression invoke;
  367. // public virtual System.IAsyncResult BeginProcessRequest(System.Web.HttpContext context, System.AsyncCallback cb, object data);
  368. method.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
  369. method.Name = "BeginProcessRequest";
  370. method.Attributes = MemberAttributes.Public;
  371. arg = new CodeParameterDeclarationExpression ();
  372. arg.Type = new CodeTypeReference (typeof (HttpContext));
  373. arg.Name = "context";
  374. method.Parameters.Add (arg);
  375. arg = new CodeParameterDeclarationExpression ();
  376. arg.Type = new CodeTypeReference (typeof (AsyncCallback));
  377. arg.Name = "cb";
  378. method.Parameters.Add (arg);
  379. arg = new CodeParameterDeclarationExpression ();
  380. arg.Type = new CodeTypeReference (typeof (object));
  381. arg.Name = "data";
  382. method.Parameters.Add (arg);
  383. invoke = new CodeMethodInvokeExpression (thisRef, "AsyncPageBeginProcessRequest");
  384. invoke.Parameters.Add (new CodeArgumentReferenceExpression ("context"));
  385. invoke.Parameters.Add (new CodeArgumentReferenceExpression ("cb"));
  386. invoke.Parameters.Add (new CodeArgumentReferenceExpression ("data"));
  387. method.Statements.Add (new CodeMethodReturnStatement (invoke));
  388. mainClass.Members.Add (method);
  389. // public virtual void EndProcessRequest(System.IAsyncResult ar);
  390. method = new CodeMemberMethod ();
  391. method.ReturnType = new CodeTypeReference (typeof (void));
  392. method.Name = "EndProcessRequest";
  393. method.Attributes = MemberAttributes.Public;
  394. arg = new CodeParameterDeclarationExpression ();
  395. arg.Type = new CodeTypeReference (typeof (IAsyncResult));
  396. arg.Name = "ar";
  397. method.Parameters.Add (arg);
  398. invoke = new CodeMethodInvokeExpression (thisRef, "AsyncPageEndProcessRequest");
  399. invoke.Parameters.Add (new CodeArgumentReferenceExpression ("ar"));
  400. method.Statements.Add (invoke);
  401. mainClass.Members.Add (method);
  402. // public override void ProcessRequest(System.Web.HttpContext context);
  403. method = new CodeMemberMethod ();
  404. method.ReturnType = new CodeTypeReference (typeof (void));
  405. method.Name = "ProcessRequest";
  406. method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
  407. arg = new CodeParameterDeclarationExpression ();
  408. arg.Type = new CodeTypeReference (typeof (HttpContext));
  409. arg.Name = "context";
  410. method.Parameters.Add (arg);
  411. invoke = new CodeMethodInvokeExpression (new CodeBaseReferenceExpression (), "ProcessRequest");
  412. invoke.Parameters.Add (new CodeArgumentReferenceExpression ("context"));
  413. method.Statements.Add (invoke);
  414. mainClass.Members.Add (method);
  415. }
  416. public static Type CompilePageType (PageParser pageParser)
  417. {
  418. PageCompiler compiler = new PageCompiler (pageParser);
  419. return compiler.GetCompiledType ();
  420. }
  421. }
  422. }