2 // System.Web.Compilation.PageCompiler
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.
32 using System.Collections;
33 using System.Collections.Generic;
35 using System.Reflection;
37 using System.Web.Configuration;
39 using System.Web.SessionState;
40 using System.Web.Util;
41 using System.Web.Profile;
43 namespace System.Web.Compilation
45 class PageCompiler : TemplateControlCompiler
47 PageParser pageParser;
48 static CodeTypeReference intRef = new CodeTypeReference (typeof (int));
50 public PageCompiler (PageParser pageParser)
53 this.pageParser = pageParser;
56 protected override void CreateStaticFields ()
58 base.CreateStaticFields ();
60 CodeMemberField fld = new CodeMemberField (typeof (object), "__fileDependencies");
61 fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
62 fld.InitExpression = new CodePrimitiveExpression (null);
63 mainClass.Members.Add (fld);
65 if (pageParser.OutputCache) {
66 fld = new CodeMemberField (typeof (OutputCacheParameters), "__outputCacheSettings");
67 fld.Attributes = MemberAttributes.Private | MemberAttributes.Static;
68 fld.InitExpression = new CodePrimitiveExpression (null);
69 mainClass.Members.Add (fld);
73 protected override void CreateConstructor (CodeStatementCollection localVars,
74 CodeStatementCollection trueStmt)
76 if (!String.IsNullOrEmpty (pageParser.MasterPageFile))
77 // This is here just to trigger master page build, so that its type
78 // is available when compiling the page itself.
79 BuildManager.GetCompiledType (pageParser.MasterPageFile);
81 if (pageParser.ClientTarget != null) {
83 prop = new CodePropertyReferenceExpression (thisRef, "ClientTarget");
84 CodeExpression ct = new CodePrimitiveExpression (pageParser.ClientTarget);
85 if (localVars == null)
86 localVars = new CodeStatementCollection ();
87 localVars.Add (new CodeAssignStatement (prop, ct));
90 ArrayList deps = pageParser.Dependencies;
91 int depsCount = deps != null ? deps.Count : 0;
94 if (localVars == null)
95 localVars = new CodeStatementCollection ();
97 trueStmt = new CodeStatementCollection ();
99 CodeAssignStatement assign;
101 new CodeVariableDeclarationStatement (
106 CodeVariableReferenceExpression dependencies = new CodeVariableReferenceExpression ("dependencies");
108 new CodeAssignStatement (dependencies, new CodeArrayCreateExpression (typeof (string), depsCount))
111 CodeArrayIndexerExpression arrayIndex;
114 for (int i = 0; i < depsCount; i++) {
116 arrayIndex = new CodeArrayIndexerExpression (dependencies, new CodeExpression[] {new CodePrimitiveExpression (i)});
117 assign = new CodeAssignStatement (arrayIndex, new CodePrimitiveExpression (o));
118 trueStmt.Add (assign);
121 CodeMethodInvokeExpression getDepsCall = new CodeMethodInvokeExpression (
123 "GetWrappedFileDependencies",
124 new CodeExpression[] {dependencies}
126 assign = new CodeAssignStatement (GetMainClassFieldReferenceExpression ("__fileDependencies"), getDepsCall);
128 trueStmt.Add (assign);
131 base.CreateConstructor (localVars, trueStmt);
134 protected override void AddInterfaces ()
136 base.AddInterfaces ();
137 CodeTypeReference cref;
139 if (pageParser.EnableSessionState) {
140 cref = new CodeTypeReference (typeof (IRequiresSessionState));
141 if (partialClass != null)
142 partialClass.BaseTypes.Add (cref);
144 mainClass.BaseTypes.Add (cref);
147 if (pageParser.ReadOnlySessionState) {
148 cref = new CodeTypeReference (typeof (IReadOnlySessionState));
149 if (partialClass != null)
150 partialClass.BaseTypes.Add (cref);
152 mainClass.BaseTypes.Add (cref);
155 if (pageParser.Async)
156 mainClass.BaseTypes.Add (new CodeTypeReference (typeof (System.Web.IHttpAsyncHandler)));
158 mainClass.BaseTypes.Add (new CodeTypeReference (typeof (System.Web.IHttpHandler)));
161 void CreateGetTypeHashCode ()
163 CodeMemberMethod method = new CodeMemberMethod ();
164 method.ReturnType = intRef;
165 method.Name = "GetTypeHashCode";
166 method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
167 Random rnd = new Random (pageParser.InputFile.GetHashCode ());
168 method.Statements.Add (new CodeMethodReturnStatement (new CodePrimitiveExpression (rnd.Next ())));
169 mainClass.Members.Add (method);
172 static CodeExpression GetExpressionForValueAndType (object value, Type valueType)
174 // Put short circuit types here
175 if (valueType == typeof (TimeSpan)) {
176 CodeMethodReferenceExpression mref = new CodeMethodReferenceExpression (
177 new CodeTypeReferenceExpression (typeof (TimeSpan)),
180 return new CodeMethodInvokeExpression (
182 new CodeExpression[] { new CodePrimitiveExpression (((TimeSpan) value).ToString ()) }
186 throw new HttpException (String.Format ("Unable to create assign expression for type '{0}'.", valueType));
189 static CodeAssignStatement CreatePropertyAssign (CodeExpression expr, string name, object value)
192 if (value == null || value is string)
193 rhs = new CodePrimitiveExpression (value);
195 Type vt = value.GetType ();
198 rhs = new CodePrimitiveExpression (value);
200 rhs = GetExpressionForValueAndType (value, vt);
203 return new CodeAssignStatement (new CodePropertyReferenceExpression (expr, name), rhs);
206 static CodeAssignStatement CreatePropertyAssign (string name, object value)
208 return CreatePropertyAssign (thisRef, name, value);
211 void AddStatementsFromDirective (CodeMemberMethod method)
213 string responseEncoding = pageParser.ResponseEncoding;
214 if (responseEncoding != null)
215 method.Statements.Add (CreatePropertyAssign ("ResponseEncoding", responseEncoding));
217 int codepage = pageParser.CodePage;
219 method.Statements.Add (CreatePropertyAssign ("CodePage", codepage));
221 string contentType = pageParser.ContentType;
222 if (contentType != null)
223 method.Statements.Add (CreatePropertyAssign ("ContentType", contentType));
225 int lcid = pageParser.LCID;
227 method.Statements.Add (CreatePropertyAssign ("LCID", lcid));
229 string culture = pageParser.Culture;
231 method.Statements.Add (CreatePropertyAssign ("Culture", culture));
233 culture = pageParser.UICulture;
235 method.Statements.Add (CreatePropertyAssign ("UICulture", culture));
237 string errorPage = pageParser.ErrorPage;
238 if (errorPage != null)
239 method.Statements.Add (CreatePropertyAssign ("ErrorPage", errorPage));
241 if (pageParser.HaveTrace) {
242 CodeAssignStatement stmt = new CodeAssignStatement ();
243 stmt.Left = new CodePropertyReferenceExpression (thisRef, "TraceEnabled");
244 stmt.Right = new CodePrimitiveExpression (pageParser.Trace);
245 method.Statements.Add (stmt);
248 if (pageParser.TraceMode != TraceMode.Default) {
249 CodeAssignStatement stmt = new CodeAssignStatement ();
250 CodeTypeReferenceExpression tm = new CodeTypeReferenceExpression ("System.Web.TraceMode");
251 stmt.Left = new CodePropertyReferenceExpression (thisRef, "TraceModeValue");
252 stmt.Right = new CodeFieldReferenceExpression (tm, pageParser.TraceMode.ToString ());
253 method.Statements.Add (stmt);
256 if (pageParser.NotBuffer) {
257 CodeAssignStatement stmt = new CodeAssignStatement ();
258 stmt.Left = new CodePropertyReferenceExpression (thisRef, "Buffer");
259 stmt.Right = new CodePrimitiveExpression (false);
260 method.Statements.Add (stmt);
263 if (!pageParser.EnableEventValidation) {
264 CodeAssignStatement stmt = new CodeAssignStatement ();
265 CodePropertyReferenceExpression prop;
266 prop = new CodePropertyReferenceExpression (thisRef, "EnableEventValidation");
268 stmt.Right = new CodePrimitiveExpression (pageParser.EnableEventValidation);
269 method.Statements.Add (stmt);
272 if (pageParser.MaintainScrollPositionOnPostBack) {
273 CodeAssignStatement stmt = new CodeAssignStatement ();
274 CodePropertyReferenceExpression prop;
275 prop = new CodePropertyReferenceExpression (thisRef, "MaintainScrollPositionOnPostBack");
277 stmt.Right = new CodePrimitiveExpression (pageParser.MaintainScrollPositionOnPostBack);
278 method.Statements.Add (stmt);
282 protected override void AddStatementsToConstructor (CodeConstructor ctor)
284 base.AddStatementsToConstructor (ctor);
285 if (pageParser.OutputCache)
286 OutputCacheParamsBlock (ctor);
289 protected override void AddStatementsToInitMethod (CodeMemberMethod method)
291 AddStatementsFromDirective (method);
292 ILocation directiveLocation = pageParser.DirectiveLocation;
294 CodeArgumentReferenceExpression ctrlVar = new CodeArgumentReferenceExpression("__ctrl");
295 if (pageParser.Title != null)
296 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "Title", pageParser.Title), directiveLocation));
298 if (pageParser.MasterPageFile != null)
299 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "MasterPageFile", pageParser.MasterPageFile), directiveLocation));
301 if (pageParser.Theme != null)
302 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "Theme", pageParser.Theme), directiveLocation));
304 if (pageParser.StyleSheetTheme != null)
305 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "StyleSheetTheme", pageParser.StyleSheetTheme), directiveLocation));
307 if (pageParser.Async != false)
308 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "AsyncMode", pageParser.Async), directiveLocation));
310 if (pageParser.AsyncTimeout != -1)
311 method.Statements.Add (AddLinePragma (CreatePropertyAssign (ctrlVar, "AsyncTimeout",
312 TimeSpan.FromSeconds (pageParser.AsyncTimeout)), directiveLocation));
314 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression (thisRef, "InitializeCulture");
315 method.Statements.Add (AddLinePragma (new CodeExpressionStatement (expr), directiveLocation));
318 protected override void PrependStatementsToFrameworkInitialize (CodeMemberMethod method)
320 base.PrependStatementsToFrameworkInitialize (method);
321 if (pageParser.StyleSheetTheme != null)
322 method.Statements.Add (CreatePropertyAssign ("StyleSheetTheme", pageParser.StyleSheetTheme));
325 protected override void AppendStatementsToFrameworkInitialize (CodeMemberMethod method)
327 base.AppendStatementsToFrameworkInitialize (method);
329 ArrayList deps = pageParser.Dependencies;
330 int depsCount = deps != null ? deps.Count : 0;
333 CodeFieldReferenceExpression fileDependencies = GetMainClassFieldReferenceExpression ("__fileDependencies");
335 method.Statements.Add (
336 new CodeMethodInvokeExpression (
338 "AddWrappedFileDependencies",
339 new CodeExpression[] {fileDependencies})
344 if (pageParser.OutputCache) {
345 CodeMethodReferenceExpression init = new CodeMethodReferenceExpression (thisRef, "InitOutputCache");
346 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression (init, GetMainClassFieldReferenceExpression ("__outputCacheSettings"));
347 method.Statements.Add (invoke);
350 if (pageParser.ValidateRequest) {
351 CodeMethodInvokeExpression expr = new CodeMethodInvokeExpression ();
352 CodePropertyReferenceExpression prop;
353 prop = new CodePropertyReferenceExpression (thisRef, "Request");
354 expr.Method = new CodeMethodReferenceExpression (prop, "ValidateInput");
355 method.Statements.Add (expr);
359 CodeAssignStatement AssignOutputCacheParameter (CodeVariableReferenceExpression variable, string propName, object value)
361 var ret = new CodeAssignStatement ();
363 ret.Left = new CodeFieldReferenceExpression (variable, propName);
365 if (value is OutputCacheLocation)
366 ret.Right = new CodeFieldReferenceExpression (
367 new CodeTypeReferenceExpression (new CodeTypeReference (typeof (OutputCacheLocation), CodeTypeReferenceOptions.GlobalReference)),
371 ret.Right = new CodePrimitiveExpression (value);
375 void OutputCacheParamsBlock (CodeMemberMethod method)
377 var statements = new List <CodeStatement> ();
378 var localSettingsDecl = new CodeVariableDeclarationStatement (typeof (OutputCacheParameters), "outputCacheSettings");
379 var localSettings = new CodeVariableReferenceExpression ("outputCacheSettings");
381 statements.Add (localSettingsDecl);
383 new CodeAssignStatement (
385 new CodeObjectCreateExpression (typeof (OutputCacheParameters), new CodeExpression[] {})
389 TemplateParser.OutputCacheParsedParams parsed = pageParser.OutputCacheParsedParameters;
390 if ((parsed & TemplateParser.OutputCacheParsedParams.CacheProfile) != 0)
391 statements.Add (AssignOutputCacheParameter (localSettings, "CacheProfile", pageParser.OutputCacheCacheProfile));
392 statements.Add (AssignOutputCacheParameter (localSettings, "Duration", pageParser.OutputCacheDuration));
393 if ((parsed & TemplateParser.OutputCacheParsedParams.Location) != 0)
394 statements.Add (AssignOutputCacheParameter (localSettings, "Location", pageParser.OutputCacheLocation));
395 if ((parsed & TemplateParser.OutputCacheParsedParams.NoStore) != 0)
396 statements.Add (AssignOutputCacheParameter (localSettings, "NoStore", pageParser.OutputCacheNoStore));
397 if ((parsed & TemplateParser.OutputCacheParsedParams.SqlDependency) != 0)
398 statements.Add (AssignOutputCacheParameter (localSettings, "SqlDependency", pageParser.OutputCacheSqlDependency));
399 if ((parsed & TemplateParser.OutputCacheParsedParams.VaryByContentEncodings) != 0)
400 statements.Add (AssignOutputCacheParameter (localSettings, "VaryByContentEncoding", pageParser.OutputCacheVaryByContentEncodings));
401 if ((parsed & TemplateParser.OutputCacheParsedParams.VaryByControl) != 0)
402 statements.Add (AssignOutputCacheParameter (localSettings, "VaryByControl", pageParser.OutputCacheVaryByControls));
403 if ((parsed & TemplateParser.OutputCacheParsedParams.VaryByCustom) != 0)
404 statements.Add (AssignOutputCacheParameter (localSettings, "VaryByCustom", pageParser.OutputCacheVaryByCustom));
405 if ((parsed & TemplateParser.OutputCacheParsedParams.VaryByHeader) != 0)
406 statements.Add (AssignOutputCacheParameter (localSettings, "VaryByHeader", pageParser.OutputCacheVaryByHeader));
407 statements.Add (AssignOutputCacheParameter (localSettings, "VaryByParam", pageParser.OutputCacheVaryByParam));
409 CodeFieldReferenceExpression outputCacheSettings = GetMainClassFieldReferenceExpression ("__outputCacheSettings");
410 statements.Add (new CodeAssignStatement (outputCacheSettings, localSettings));
412 var cond = new CodeConditionStatement (
413 new CodeBinaryOperatorExpression (
415 CodeBinaryOperatorType.IdentityEquality,
416 new CodePrimitiveExpression (null)
418 statements.ToArray ()
421 method.Statements.Add (cond);
424 void CreateStronglyTypedProperty (Type type, string name)
429 CodeMemberProperty mprop = new CodeMemberProperty ();
431 mprop.Type = new CodeTypeReference (type);
432 mprop.Attributes = MemberAttributes.Public | MemberAttributes.New;
433 CodeExpression prop = new CodePropertyReferenceExpression (new CodeBaseReferenceExpression (), name);
434 prop = new CodeCastExpression (type, prop);
435 mprop.GetStatements.Add (new CodeMethodReturnStatement (prop));
436 if (partialClass != null)
437 partialClass.Members.Add (mprop);
439 mainClass.Members.Add (mprop);
441 AddReferencedAssembly (type.Assembly);
444 protected internal override void CreateMethods ()
446 base.CreateMethods ();
448 CreateProfileProperty ();
449 CreateStronglyTypedProperty (pageParser.MasterType, "Master");
450 CreateStronglyTypedProperty (pageParser.PreviousPageType, "PreviousPage");
451 CreateGetTypeHashCode ();
453 if (pageParser.Async)
454 CreateAsyncMethods ();
457 void CreateAsyncMethods ()
459 CodeMemberMethod method = new CodeMemberMethod ();
460 CodeParameterDeclarationExpression arg;
461 CodeMethodInvokeExpression invoke;
463 // public virtual System.IAsyncResult BeginProcessRequest(System.Web.HttpContext context, System.AsyncCallback cb, object data);
464 method.ReturnType = new CodeTypeReference (typeof (IAsyncResult));
465 method.Name = "BeginProcessRequest";
466 method.Attributes = MemberAttributes.Public;
468 arg = new CodeParameterDeclarationExpression ();
469 arg.Type = new CodeTypeReference (typeof (HttpContext));
470 arg.Name = "context";
471 method.Parameters.Add (arg);
473 arg = new CodeParameterDeclarationExpression ();
474 arg.Type = new CodeTypeReference (typeof (AsyncCallback));
476 method.Parameters.Add (arg);
478 arg = new CodeParameterDeclarationExpression ();
479 arg.Type = new CodeTypeReference (typeof (object));
481 method.Parameters.Add (arg);
483 invoke = new CodeMethodInvokeExpression (thisRef, "AsyncPageBeginProcessRequest");
484 invoke.Parameters.Add (new CodeArgumentReferenceExpression ("context"));
485 invoke.Parameters.Add (new CodeArgumentReferenceExpression ("cb"));
486 invoke.Parameters.Add (new CodeArgumentReferenceExpression ("data"));
488 method.Statements.Add (new CodeMethodReturnStatement (invoke));
489 mainClass.Members.Add (method);
491 // public virtual void EndProcessRequest(System.IAsyncResult ar);
492 method = new CodeMemberMethod ();
493 method.ReturnType = new CodeTypeReference (typeof (void));
494 method.Name = "EndProcessRequest";
495 method.Attributes = MemberAttributes.Public;
497 arg = new CodeParameterDeclarationExpression ();
498 arg.Type = new CodeTypeReference (typeof (IAsyncResult));
500 method.Parameters.Add (arg);
502 invoke = new CodeMethodInvokeExpression (thisRef, "AsyncPageEndProcessRequest");
503 invoke.Parameters.Add (new CodeArgumentReferenceExpression ("ar"));
505 method.Statements.Add (invoke);
506 mainClass.Members.Add (method);
508 // public override void ProcessRequest(System.Web.HttpContext context);
509 method = new CodeMemberMethod ();
510 method.ReturnType = new CodeTypeReference (typeof (void));
511 method.Name = "ProcessRequest";
512 method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
514 arg = new CodeParameterDeclarationExpression ();
515 arg.Type = new CodeTypeReference (typeof (HttpContext));
516 arg.Name = "context";
517 method.Parameters.Add (arg);
519 invoke = new CodeMethodInvokeExpression (new CodeBaseReferenceExpression (), "ProcessRequest");
520 invoke.Parameters.Add (new CodeArgumentReferenceExpression ("context"));
522 method.Statements.Add (invoke);
523 mainClass.Members.Add (method);
526 public static Type CompilePageType (PageParser pageParser)
528 PageCompiler compiler = new PageCompiler (pageParser);
529 return compiler.GetCompiledType ();