|
//------------------------------------------------------------------------------
// <copyright file="PageCodeDomTreeGenerator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.Compilation {
using System;
using System.CodeDom;
using System.Reflection;
using System.Web.Configuration;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.Util;
using Debug = System.Web.Util.Debug;
internal class PageCodeDomTreeGenerator : TemplateControlCodeDomTreeGenerator {
private PageParser _pageParser;
PageParser Parser { get { return _pageParser; } }
private const string fileDependenciesName = "__fileDependencies";
private const string dependenciesLocalName = "dependencies";
private const string outputCacheSettingsLocalName = "outputCacheSettings";
private const string _previousPagePropertyName = "PreviousPage";
private const string _masterPropertyName = "Master";
private const string _styleSheetThemePropertyName = "StyleSheetTheme";
private const string outputCacheSettingsFieldName = "__outputCacheSettings";
internal const int DebugScriptTimeout = 30000000;
internal PageCodeDomTreeGenerator(PageParser pageParser) : base(pageParser) {
_pageParser = pageParser;
}
/*
* Generate the list of implemented interfaces
*/
protected override void GenerateInterfaces() {
base.GenerateInterfaces();
if (Parser.FRequiresSessionState) {
_intermediateClass.BaseTypes.Add(new CodeTypeReference(typeof(IRequiresSessionState)));
}
if (Parser.FReadOnlySessionState) {
_intermediateClass.BaseTypes.Add(new CodeTypeReference(typeof(IReadOnlySessionState)));
}
// Skip if we're only generating the intermediate class
if (!_designerMode && _sourceDataClass != null && (Parser.AspCompatMode || Parser.AsyncMode)) {
_sourceDataClass.BaseTypes.Add(new CodeTypeReference(typeof(IHttpAsyncHandler)));
}
}
/*
* Build first-time intialization statements
*/
protected override void BuildInitStatements(CodeStatementCollection trueStatements, CodeStatementCollection topLevelStatements) {
base.BuildInitStatements(trueStatements, topLevelStatements);
//
CodeMemberField fileDependencies = new CodeMemberField(typeof(object), fileDependenciesName);
fileDependencies.Attributes |= MemberAttributes.Static;
_sourceDataClass.Members.Add(fileDependencies);
// Note: it may look like this local variable declaration is redundant. However it is necessary
// to make this init code re-entrant safe. This way, even if two threads enter the contructor
// at the same time, they will not add multiple dependencies.
// e.g. string[] dependencies;
CodeVariableDeclarationStatement dependencies = new CodeVariableDeclarationStatement();
dependencies.Type = new CodeTypeReference(typeof(string[]));
dependencies.Name = dependenciesLocalName;
// Note: it is important to add all local variables at the top level for CodeDom Subset compliance.
topLevelStatements.Insert(0, dependencies);
Debug.Assert(Parser.SourceDependencies != null);
StringSet virtualDependencies = new StringSet();
virtualDependencies.AddCollection(Parser.SourceDependencies);
// e.g. dependencies = new string[{{virtualDependencies.Count}}];;
CodeAssignStatement assignDependencies = new CodeAssignStatement();
assignDependencies.Left =
new CodeVariableReferenceExpression(dependenciesLocalName);
assignDependencies.Right =
new CodeArrayCreateExpression(typeof(String), virtualDependencies.Count);
trueStatements.Add(assignDependencies);
int i = 0;
foreach (string virtualDependency in virtualDependencies) {
// e.g. dependencies[i] = "~/sub/foo.aspx";
CodeAssignStatement addFileDep = new CodeAssignStatement();
addFileDep.Left =
new CodeArrayIndexerExpression(
new CodeVariableReferenceExpression(dependenciesLocalName),
new CodeExpression[] {new CodePrimitiveExpression(i++)});
string src = UrlPath.MakeVirtualPathAppRelative(virtualDependency);
addFileDep.Right = new CodePrimitiveExpression(src);
trueStatements.Add(addFileDep);
}
// e.g. __fileDependencies = this.GetWrappedFileDependencies(dependencies);
CodeAssignStatement initFile = new CodeAssignStatement();
initFile.Left = new CodeFieldReferenceExpression(_classTypeExpr, fileDependenciesName);
CodeMethodInvokeExpression createWrap = new CodeMethodInvokeExpression();
createWrap.Method.TargetObject = new CodeThisReferenceExpression();
createWrap.Method.MethodName = "GetWrappedFileDependencies";
createWrap.Parameters.Add(new CodeVariableReferenceExpression(dependenciesLocalName));
initFile.Right = createWrap;
#if DBG
AppendDebugComment(trueStatements);
#endif
trueStatements.Add(initFile);
}
/*
* Build the default constructor
*/
protected override void BuildDefaultConstructor() {
base.BuildDefaultConstructor();
if (CompilParams.IncludeDebugInformation) {
// If in debug mode, set the timeout to some huge value (ASURT 49427)
// Server.ScriptTimeout = 30000000;
CodeAssignStatement setScriptTimeout = new CodeAssignStatement();
setScriptTimeout.Left = new CodePropertyReferenceExpression(
new CodePropertyReferenceExpression(
new CodeThisReferenceExpression(), "Server"),
"ScriptTimeout");
setScriptTimeout.Right = new CodePrimitiveExpression(DebugScriptTimeout);
InitMethod.Statements.Add(setScriptTimeout);
}
if (Parser.TransactionMode != 0 /*TransactionOption.Disabled*/) {
InitMethod.Statements.Add(new CodeAssignStatement(
new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "TransactionMode"),
new CodePrimitiveExpression(Parser.TransactionMode)));
}
if (Parser.AspCompatMode) {
InitMethod.Statements.Add(new CodeAssignStatement(
new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "AspCompatMode"),
new CodePrimitiveExpression(Parser.AspCompatMode)));
}
if (Parser.AsyncMode) {
InitMethod.Statements.Add(new CodeAssignStatement(
new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "AsyncMode"),
new CodePrimitiveExpression(Parser.AsyncMode)));
}
if (Parser.OutputCacheParameters != null) {
OutputCacheParameters cacheSettings = Parser.OutputCacheParameters;
if ((cacheSettings.CacheProfile != null && cacheSettings.CacheProfile.Length != 0) ||
cacheSettings.Duration != 0 ||
cacheSettings.Location == OutputCacheLocation.None) {
// Add the following code snippet as a static on the class:
//
// private static OutputCacheParameters __outputCacheSettings = null;
//
CodeMemberField outputCacheSettingsField = new CodeMemberField(typeof(OutputCacheParameters), outputCacheSettingsFieldName);
outputCacheSettingsField.Attributes |= MemberAttributes.Static;
outputCacheSettingsField.InitExpression = new CodePrimitiveExpression(null);
_sourceDataClass.Members.Add(outputCacheSettingsField);
// Then, add the following code to the default constructor:
//
// if (__outputCacheSettings == null)
// __outputCacheSettings = new OutputCacheParameters(.....)
//
// This is the "if (__outputCacheSettings == null)" part
CodeConditionStatement outputCacheSettingsCondition = new CodeConditionStatement();
outputCacheSettingsCondition.Condition = new CodeBinaryOperatorExpression(
new CodeFieldReferenceExpression(
_classTypeExpr,
outputCacheSettingsFieldName),
CodeBinaryOperatorType.IdentityEquality,
new CodePrimitiveExpression(null));
// This is the "__outputCacheSettings = new OutputCacheParameters()" part
// e.g. declare local variable: OutputCacheParameters outputCacheSettings;
CodeVariableDeclarationStatement outputCacheSettingsDeclaration = new CodeVariableDeclarationStatement();
outputCacheSettingsDeclaration.Type = new CodeTypeReference(typeof(OutputCacheParameters));
outputCacheSettingsDeclaration.Name = outputCacheSettingsLocalName;
outputCacheSettingsCondition.TrueStatements.Insert(0, outputCacheSettingsDeclaration);
// e.g. outputCacheSettings = new outputCacheParameters;
CodeObjectCreateExpression cacheSettingsObject = new CodeObjectCreateExpression();
cacheSettingsObject.CreateType = new CodeTypeReference(typeof(OutputCacheParameters));
CodeVariableReferenceExpression outputCacheSettings =
new CodeVariableReferenceExpression(outputCacheSettingsLocalName);
CodeAssignStatement setOutputCacheObject =
new CodeAssignStatement(outputCacheSettings, cacheSettingsObject);
// Add the statement to the "true" clause
outputCacheSettingsCondition.TrueStatements.Add(setOutputCacheObject);
if (cacheSettings.IsParameterSet(OutputCacheParameter.CacheProfile)) {
CodeAssignStatement setPropertyStatement = new CodeAssignStatement(
new CodePropertyReferenceExpression(outputCacheSettings, "CacheProfile"),
new CodePrimitiveExpression(cacheSettings.CacheProfile));
outputCacheSettingsCondition.TrueStatements.Add(setPropertyStatement);
}
if (cacheSettings.IsParameterSet(OutputCacheParameter.Duration)) {
CodeAssignStatement setPropertyStatement = new CodeAssignStatement(
new CodePropertyReferenceExpression(outputCacheSettings, "Duration"),
new CodePrimitiveExpression(cacheSettings.Duration));
outputCacheSettingsCondition.TrueStatements.Add(setPropertyStatement);
}
if (cacheSettings.IsParameterSet(OutputCacheParameter.Enabled)) {
CodeAssignStatement setPropertyStatement = new CodeAssignStatement(
new CodePropertyReferenceExpression(outputCacheSettings, "Enabled"),
new CodePrimitiveExpression(cacheSettings.Enabled));
outputCacheSettingsCondition.TrueStatements.Add(setPropertyStatement);
}
if (cacheSettings.IsParameterSet(OutputCacheParameter.Location)) {
CodeAssignStatement setPropertyStatement = new CodeAssignStatement(
new CodePropertyReferenceExpression(outputCacheSettings, "Location"),
new CodeFieldReferenceExpression(
new CodeTypeReferenceExpression(typeof(OutputCacheLocation)),
cacheSettings.Location.ToString()));
outputCacheSettingsCondition.TrueStatements.Add(setPropertyStatement);
}
if (cacheSettings.IsParameterSet(OutputCacheParameter.NoStore)) {
CodeAssignStatement setPropertyStatement = new CodeAssignStatement(
new CodePropertyReferenceExpression(outputCacheSettings, "NoStore"),
new CodePrimitiveExpression(cacheSettings.NoStore));
outputCacheSettingsCondition.TrueStatements.Add(setPropertyStatement);
}
if (cacheSettings.IsParameterSet(OutputCacheParameter.SqlDependency)) {
CodeAssignStatement setPropertyStatement = new CodeAssignStatement(
new CodePropertyReferenceExpression(outputCacheSettings, "SqlDependency"),
new CodePrimitiveExpression(cacheSettings.SqlDependency));
outputCacheSettingsCondition.TrueStatements.Add(setPropertyStatement);
}
if (cacheSettings.IsParameterSet(OutputCacheParameter.VaryByControl)) {
CodeAssignStatement setPropertyStatement = new CodeAssignStatement(
new CodePropertyReferenceExpression(outputCacheSettings, "VaryByControl"),
new CodePrimitiveExpression(cacheSettings.VaryByControl));
outputCacheSettingsCondition.TrueStatements.Add(setPropertyStatement);
}
if (cacheSettings.IsParameterSet(OutputCacheParameter.VaryByCustom)) {
CodeAssignStatement setPropertyStatement = new CodeAssignStatement(
new CodePropertyReferenceExpression(outputCacheSettings, "VaryByCustom"),
new CodePrimitiveExpression(cacheSettings.VaryByCustom));
outputCacheSettingsCondition.TrueStatements.Add(setPropertyStatement);
}
if (cacheSettings.IsParameterSet(OutputCacheParameter.VaryByContentEncoding)) {
CodeAssignStatement setPropertyStatement = new CodeAssignStatement(
new CodePropertyReferenceExpression(outputCacheSettings, "VaryByContentEncoding"),
new CodePrimitiveExpression(cacheSettings.VaryByContentEncoding));
outputCacheSettingsCondition.TrueStatements.Add(setPropertyStatement);
}
if (cacheSettings.IsParameterSet(OutputCacheParameter.VaryByHeader)) {
CodeAssignStatement setPropertyStatement = new CodeAssignStatement(
new CodePropertyReferenceExpression(outputCacheSettings, "VaryByHeader"),
new CodePrimitiveExpression(cacheSettings.VaryByHeader));
outputCacheSettingsCondition.TrueStatements.Add(setPropertyStatement);
}
if (cacheSettings.IsParameterSet(OutputCacheParameter.VaryByParam)) {
CodeAssignStatement setPropertyStatement = new CodeAssignStatement(
new CodePropertyReferenceExpression(outputCacheSettings, "VaryByParam"),
new CodePrimitiveExpression(cacheSettings.VaryByParam));
outputCacheSettingsCondition.TrueStatements.Add(setPropertyStatement);
}
// e.g. __outputCacheSettings = outputCacheSettings;
CodeFieldReferenceExpression staticOutputCacheSettings =
new CodeFieldReferenceExpression(_classTypeExpr, outputCacheSettingsFieldName);
CodeAssignStatement assignOutputCacheSettings =
new CodeAssignStatement(staticOutputCacheSettings, outputCacheSettings);
// Add the statement to the "true" clause
outputCacheSettingsCondition.TrueStatements.Add(assignOutputCacheSettings);
InitMethod.Statements.Add(outputCacheSettingsCondition);
}
}
}
/*
* Build various properties, fields, methods
*/
protected override void BuildMiscClassMembers() {
base.BuildMiscClassMembers();
// The following method should not be built in designer mode, and should only be built
// when we're generating the full class (as opposed to the partial stub)
if (!_designerMode && _sourceDataClass != null) {
BuildGetTypeHashCodeMethod();
if (Parser.AspCompatMode)
BuildAspCompatMethods();
if (Parser.AsyncMode)
BuildAsyncPageMethods();
BuildProcessRequestOverride();
}
if (Parser.PreviousPageType != null)
BuildStronglyTypedProperty(_previousPagePropertyName, Parser.PreviousPageType);
if (Parser.MasterPageType != null)
BuildStronglyTypedProperty(_masterPropertyName, Parser.MasterPageType);
}
/*
* Build the data tree for the GetTypeHashCode method
*/
private void BuildGetTypeHashCodeMethod() {
CodeMemberMethod method = new CodeMemberMethod();
AddDebuggerNonUserCodeAttribute(method);
method.Name = "GetTypeHashCode";
method.ReturnType = new CodeTypeReference(typeof(int));
method.Attributes &= ~MemberAttributes.AccessMask;
method.Attributes &= ~MemberAttributes.ScopeMask;
method.Attributes |= MemberAttributes.Override | MemberAttributes.Public;
_sourceDataClass.Members.Add(method);
#if DBG
AppendDebugComment(method.Statements);
#endif
method.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(Parser.TypeHashCode)));
}
internal override CodeExpression BuildPagePropertyReferenceExpression() {
return new CodeThisReferenceExpression();
}
/*
* Build the contents of the FrameworkInitialize method
*/
protected override void BuildFrameworkInitializeMethodContents(CodeMemberMethod method) {
// Generate code to apply stylesheet before calling base.FrameworkInitialize();
if (Parser.StyleSheetTheme != null) {
CodeExpression rightExpr = new CodePrimitiveExpression(Parser.StyleSheetTheme);
CodeExpression leftExpr = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), _styleSheetThemePropertyName);
CodeAssignStatement setStatment = new CodeAssignStatement(leftExpr, rightExpr);
method.Statements.Add(setStatment);
}
base.BuildFrameworkInitializeMethodContents(method);
CodeMethodInvokeExpression addDeps = new CodeMethodInvokeExpression();
addDeps.Method.TargetObject = new CodeThisReferenceExpression();
addDeps.Method.MethodName = "AddWrappedFileDependencies";
addDeps.Parameters.Add(new CodeFieldReferenceExpression(_classTypeExpr, fileDependenciesName));
method.Statements.Add(addDeps);
if (Parser.OutputCacheParameters != null) {
OutputCacheParameters cacheSettings = Parser.OutputCacheParameters;
if ((cacheSettings.CacheProfile != null && cacheSettings.CacheProfile.Length != 0) ||
cacheSettings.Duration != 0 ||
cacheSettings.Location == OutputCacheLocation.None) {
CodeMethodInvokeExpression call = new CodeMethodInvokeExpression();
call.Method.TargetObject = new CodeThisReferenceExpression();
call.Method.MethodName = "InitOutputCache";
call.Parameters.Add(new CodeFieldReferenceExpression(
_classTypeExpr,
outputCacheSettingsFieldName));
method.Statements.Add(call);
}
}
if (Parser.TraceEnabled != TraceEnable.Default) {
method.Statements.Add(new CodeAssignStatement(
new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "TraceEnabled"),
new CodePrimitiveExpression(Parser.TraceEnabled == TraceEnable.Enable)));
}
if (Parser.TraceMode != TraceMode.Default) {
method.Statements.Add(new CodeAssignStatement(
new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "TraceModeValue"),
new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(TraceMode)), Parser.TraceMode.ToString())));
}
if (Parser.ValidateRequest) {
// e.g. Request.ValidateInput();
CodeMethodInvokeExpression invokeExpr = new CodeMethodInvokeExpression();
invokeExpr.Method.TargetObject = new CodePropertyReferenceExpression(
new CodeThisReferenceExpression(), "Request");
invokeExpr.Method.MethodName = "ValidateInput";
method.Statements.Add(new CodeExpressionStatement(invokeExpr));
}
else if (MultiTargetingUtil.TargetFrameworkVersion >= VersionUtil.Framework45) {
// Only emit the ValidateRequestMode setter if the target framework is 4.5 or higher.
// On frameworks 4.0 and earlier that property did not exist.
CodePropertyReferenceExpression left = new CodePropertyReferenceExpression(
new CodeThisReferenceExpression(), "ValidateRequestMode");
CodeFieldReferenceExpression right = new CodeFieldReferenceExpression(
new CodeTypeReferenceExpression(typeof(ValidateRequestMode)), "Disabled");
CodeAssignStatement statement = new CodeAssignStatement(left, right);
method.Statements.Add(statement);
}
}
/*
* Build the data tree for the AspCompat implementation for IHttpAsyncHandler:
*/
private void BuildAspCompatMethods() {
CodeMemberMethod method;
CodeMethodInvokeExpression call;
// public IAsyncResult BeginProcessRequest(HttpContext context, Async'back cb, Object extraData) {
// IAsyncResult ar;
// ar = this.AspCompatBeginProcessRequest(context, cb, extraData);
// return ar;
// }
method = new CodeMemberMethod();
AddDebuggerNonUserCodeAttribute(method);
method.Name = "BeginProcessRequest";
method.Attributes &= ~MemberAttributes.AccessMask;
method.Attributes &= ~MemberAttributes.ScopeMask;
method.Attributes |= MemberAttributes.Public;
method.ImplementationTypes.Add(new CodeTypeReference(typeof(IHttpAsyncHandler)));
method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(HttpContext), "context"));
method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(AsyncCallback), "cb"));
method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(Object), "data"));
method.ReturnType = new CodeTypeReference(typeof(IAsyncResult));
CodeMethodInvokeExpression invokeExpr = new CodeMethodInvokeExpression();
invokeExpr.Method.TargetObject = new CodeThisReferenceExpression();
invokeExpr.Method.MethodName = "AspCompatBeginProcessRequest";
invokeExpr.Parameters.Add(new CodeArgumentReferenceExpression("context"));
invokeExpr.Parameters.Add(new CodeArgumentReferenceExpression("cb"));
invokeExpr.Parameters.Add(new CodeArgumentReferenceExpression("data"));
method.Statements.Add(new CodeMethodReturnStatement(invokeExpr));
_sourceDataClass.Members.Add(method);
// public void EndProcessRequest(IAsyncResult ar) {
// this.AspCompatEndProcessRequest(ar);
// }
method = new CodeMemberMethod();
AddDebuggerNonUserCodeAttribute(method);
method.Name = "EndProcessRequest";
method.Attributes &= ~MemberAttributes.AccessMask;
method.Attributes &= ~MemberAttributes.ScopeMask;
method.Attributes |= MemberAttributes.Public;
method.ImplementationTypes.Add(typeof(IHttpAsyncHandler));
method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IAsyncResult), "ar"));
call = new CodeMethodInvokeExpression();
call.Method.TargetObject = new CodeThisReferenceExpression();
call.Method.MethodName = "AspCompatEndProcessRequest";
call.Parameters.Add(new CodeArgumentReferenceExpression("ar"));
method.Statements.Add(call);
_sourceDataClass.Members.Add(method);
}
/*
* Build the data tree for the Async page implementation for IHttpAsyncHandler:
*/
private void BuildAsyncPageMethods() {
CodeMemberMethod method;
CodeMethodInvokeExpression call;
// public IAsyncResult BeginProcessRequest(HttpContext context, Async'back cb, Object extraData) {
// IAsyncResult ar;
// ar = this.AsyncPageBeginProcessRequest(context, cb, extraData);
// return ar;
// }
method = new CodeMemberMethod();
AddDebuggerNonUserCodeAttribute(method);
method.Name = "BeginProcessRequest";
method.Attributes &= ~MemberAttributes.AccessMask;
method.Attributes &= ~MemberAttributes.ScopeMask;
method.Attributes |= MemberAttributes.Public;
method.ImplementationTypes.Add(new CodeTypeReference(typeof(IHttpAsyncHandler)));
method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(HttpContext), "context"));
method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(AsyncCallback), "cb"));
method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(Object), "data"));
method.ReturnType = new CodeTypeReference(typeof(IAsyncResult));
CodeMethodInvokeExpression invokeExpr = new CodeMethodInvokeExpression();
invokeExpr.Method.TargetObject = new CodeThisReferenceExpression();
invokeExpr.Method.MethodName = "AsyncPageBeginProcessRequest";
invokeExpr.Parameters.Add(new CodeArgumentReferenceExpression("context"));
invokeExpr.Parameters.Add(new CodeArgumentReferenceExpression("cb"));
invokeExpr.Parameters.Add(new CodeArgumentReferenceExpression("data"));
method.Statements.Add(new CodeMethodReturnStatement(invokeExpr));
_sourceDataClass.Members.Add(method);
// public void EndProcessRequest(IAsyncResult ar) {
// this.AsyncPageEndProcessRequest(ar);
// }
method = new CodeMemberMethod();
AddDebuggerNonUserCodeAttribute(method);
method.Name = "EndProcessRequest";
method.Attributes &= ~MemberAttributes.AccessMask;
method.Attributes &= ~MemberAttributes.ScopeMask;
method.Attributes |= MemberAttributes.Public;
method.ImplementationTypes.Add(typeof(IHttpAsyncHandler));
method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IAsyncResult), "ar"));
call = new CodeMethodInvokeExpression();
call.Method.TargetObject = new CodeThisReferenceExpression();
call.Method.MethodName = "AsyncPageEndProcessRequest";
call.Parameters.Add(new CodeArgumentReferenceExpression("ar"));
method.Statements.Add(call);
_sourceDataClass.Members.Add(method);
}
/*
* Build a ProcessRequest override which just calls the base. This is used to make sure
* there is user code on the stack when requests are executed (VSWhidbey 499386)
*/
private void BuildProcessRequestOverride() {
// public override void ProcessRequest(HttpContext context) {
// base.ProcessRequest(context);
// }
CodeMemberMethod method = new CodeMemberMethod();
AddDebuggerNonUserCodeAttribute(method);
method.Name = "ProcessRequest";
method.Attributes &= ~MemberAttributes.AccessMask;
method.Attributes &= ~MemberAttributes.ScopeMask;
// If the base type is non-default (i.e. not Page) we have to be careful overriding
// ProcessRequest, because if the base has its own IHttpHandler.ProcessRequest implementation
// and it's not overridable, we would fail to compile. So when we detect this situation,
// we instead generate it as a new IHttpHandler.ProcessRequest implementation instead of an
// override. In theory, we could *always* do this, but it's safer to limit it to this
// constrained scenario (VSWhidbey 517240)
MethodInfo methodInfo = null;
if (Parser.BaseType != typeof(Page)) {
methodInfo = Parser.BaseType.GetMethod("ProcessRequest",
BindingFlags.Public | BindingFlags.Instance,
null, new Type[] { typeof(HttpContext) }, null);
Debug.Assert(methodInfo != null);
}
_sourceDataClass.BaseTypes.Add(new CodeTypeReference(typeof(IHttpHandler)));
if (methodInfo != null && methodInfo.DeclaringType != typeof(Page)) {
method.Attributes |= MemberAttributes.New | MemberAttributes.Public;
}
else {
method.Attributes |= MemberAttributes.Override | MemberAttributes.Public;
}
method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(HttpContext), "context"));
CodeMethodInvokeExpression invokeExpr = new CodeMethodInvokeExpression();
invokeExpr.Method.TargetObject = new CodeBaseReferenceExpression();
invokeExpr.Method.MethodName = "ProcessRequest";
invokeExpr.Parameters.Add(new CodeArgumentReferenceExpression("context"));
method.Statements.Add(invokeExpr);
_sourceDataClass.Members.Add(method);
}
}
}
|