PageParser.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / xsp / System / Web / UI / PageParser.cs / 4 / PageParser.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 * Implements the ASP.NET template parser 
 *
 * Copyright (c) 1998 Microsoft Corporation 
 */

namespace System.Web.UI {
using System.Runtime.Serialization.Formatters; 
using System.Text;
using System.Runtime.InteropServices; 
using System.Runtime.Serialization; 
using System;
using System.IO; 
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;
using System.Globalization; 
using System.CodeDom.Compiler;
using System.ComponentModel; 
using System.Web.Hosting; 
using System.Web.Caching;
using System.Web.Util; 
using System.Web.Compilation;
using System.Web.Configuration;
using System.Web.Management;
using System.EnterpriseServices; 
using HttpException = System.Web.HttpException;
using System.Text.RegularExpressions; 
using System.Security.Permissions; 

/* 
 * Parser for .aspx files
 */

///  
/// 
///    [To be supplied.] 
///  
[AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
public sealed class PageParser : TemplateControlParser { 

    private int _transactionMode = 0 /*TransactionOption.Disabled*/;
    internal int TransactionMode { get { return _transactionMode; } }
 
    private TraceMode _traceMode = System.Web.TraceMode.Default;
    internal TraceMode TraceMode { get { return _traceMode; } } 
 
    private TraceEnable _traceEnabled = TraceEnable.Default;
    internal TraceEnable TraceEnabled { get { return _traceEnabled; } } 

    private int _codePage;
    private string _responseEncoding;
    private int _lcid; 
    private string _culture;
    private int _mainDirectiveLineNumber = 1; 
    private bool _mainDirectiveMasterPageSet; 

    private OutputCacheLocation _outputCacheLocation; 

    internal bool FRequiresSessionState { get { return flags[requiresSessionState]; } }
    internal bool FReadOnlySessionState { get { return flags[readOnlySessionState]; } }
 
    private string _errorPage;
 
    private string _styleSheetTheme; 
    internal String StyleSheetTheme { get { return _styleSheetTheme; } }
 
    internal bool AspCompatMode { get { return flags[aspCompatMode]; } }

    internal bool AsyncMode { get { return flags[asyncMode]; } }
 
    internal bool ValidateRequest { get { return flags[validateRequest]; } }
 
    private Type _previousPageType; 
    internal Type PreviousPageType { get { return _previousPageType; } }
 
    private Type _masterPageType;
    internal Type MasterPageType { get { return _masterPageType; } }

    private string _configMasterPageFile; 

 
    public PageParser() { 
        flags[buffer] = Page.BufferDefault;
        flags[requiresSessionState] = true; 
        flags[validateRequest] = true;
    }

    /* 
     * Compile an .aspx file into a Page object
     */ 
 
    /// 
    ///    [To be supplied.] 
    /// 

    private static object s_lock = new object();
 

    // Only allowed in full trust (ASURT 123086) 
    [SecurityPermission(SecurityAction.Demand, Unrestricted=true)] 
    public static IHttpHandler GetCompiledPageInstance(string virtualPath,
        string inputFile, HttpContext context) { 

        // Canonicalize the path to avoid failure caused by the CheckSuspiciousPhysicalPath
        // security check, which was not meant to apply to this scenario (plus this API requires
        // full trust).  VSWhidbey 541640. 
        if (!String.IsNullOrEmpty(inputFile)) {
            inputFile = Path.GetFullPath(inputFile); 
        } 
        if (inputFile != null) {
            // This call temporarily replaces _theHostingEnvironment._virtualPathProvider, and it can get 
            // corrupted if two threads do it at once.  Use a lock to prevent this (VSWhidbey 598332)
            lock (s_lock) {
                return GetCompiledPageInstance(VirtualPath.Create(virtualPath), inputFile, context);
            } 
        }
        else { 
            return GetCompiledPageInstance(VirtualPath.Create(virtualPath), inputFile, context); 
        }
    } 

    private static IHttpHandler GetCompiledPageInstance(VirtualPath virtualPath,
        string inputFile, HttpContext context) {
 
        // This is a hacky API that only exists to support web service's
        // DefaultWsdlHelpGenerator.aspx, which doesn't live under the app root. 
        // To make this work, we add an explicit mapping from the virtual path 
        // to the stream of the passed in file
 
        // Make it relative to the current request if necessary
        if (context != null)
            virtualPath = context.Request.FilePathObject.Combine(virtualPath);
 
        object virtualPathToFileMappingState = null;
        try { 
            try { 
                // If there is a physical path, we need to connect the virtual path to it, so that
                // the build system will use the right input file for the virtual path. 
                if (inputFile != null) {
                    virtualPathToFileMappingState = HostingEnvironment.AddVirtualPathToFileMapping(
                        virtualPath, inputFile);
                } 

                BuildResultCompiledType result = (BuildResultCompiledType)BuildManager.GetVPathBuildResult( 
                    context, virtualPath, false /*noBuild*/, true /*allowCrossApp*/, true /*allowBuildInPrecompile*/); 
                return (IHttpHandler)HttpRuntime.CreatePublicInstance(result.ResultType);
            } 
            finally {
                if (virtualPathToFileMappingState != null)
                    HostingEnvironment.ClearVirtualPathToFileMapping(virtualPathToFileMappingState);
            } 
        }
        catch { 
            throw; 
        }
    } 

    internal override Type DefaultBaseType { get { return typeof(System.Web.UI.Page); } }

    internal override Type DefaultFileLevelBuilderType { 
        get {
            return typeof(FileLevelPageControlBuilder); 
        } 
    }
 
    internal override RootBuilder CreateDefaultFileLevelBuilder() {

        return new FileLevelPageControlBuilder();
    } 

    private void EnsureMasterPageFileFromConfigApplied() { 
        // Skip if it's already applied. 
        if (_mainDirectiveMasterPageSet) {
            return; 
        }

        // If the masterPageFile is defined in the config
        if (_configMasterPageFile != null) { 

            // Readjust the lineNumber to the location of maindirective 
            int prevLineNumber = _lineNumber; 
            _lineNumber = _mainDirectiveLineNumber;
            try { 
                if (_configMasterPageFile.Length > 0) {
                    Type type = GetReferencedType(_configMasterPageFile);

                    // Make sure it has the correct base type 
                    if (!typeof(MasterPage).IsAssignableFrom(type)) {
                        ProcessError(SR.GetString(SR.Invalid_master_base, _configMasterPageFile)); 
                    } 
                }
 
                if (((FileLevelPageControlBuilder)RootBuilder).ContentBuilderEntries != null) {
                    RootBuilder.SetControlType(BaseType);
                    RootBuilder.PreprocessAttribute(String.Empty /*filter*/, "MasterPageFile", _configMasterPageFile, true /*mainDirectiveMode*/);
                } 
            }
            finally { 
                _lineNumber = prevLineNumber; 
            }
        } 

        _mainDirectiveMasterPageSet = true;
    }
 
    internal override void HandlePostParse() {
        base.HandlePostParse(); 
 
        EnsureMasterPageFileFromConfigApplied();
    } 

    // Get default settings from config
    internal override void ProcessConfigSettings() {
        base.ProcessConfigSettings(); 

        if (PagesConfig != null) { 
            // Check config for various attributes, and if they have non-default values, 
            // set them in _mainDirectiveConfigSettings.
 
            if (PagesConfig.Buffer != Page.BufferDefault)
                _mainDirectiveConfigSettings["buffer"] = Util.GetStringFromBool(PagesConfig.Buffer);

            if (PagesConfig.EnableViewStateMac != Page.EnableViewStateMacDefault) 
                _mainDirectiveConfigSettings["enableviewstatemac"] = Util.GetStringFromBool(PagesConfig.EnableViewStateMac);
 
            if (PagesConfig.EnableEventValidation != Page.EnableEventValidationDefault) 
                _mainDirectiveConfigSettings["enableEventValidation"] = Util.GetStringFromBool(PagesConfig.EnableEventValidation);
 
            if (PagesConfig.SmartNavigation != Page.SmartNavigationDefault)
                _mainDirectiveConfigSettings["smartnavigation"] = Util.GetStringFromBool(PagesConfig.SmartNavigation);

            if (PagesConfig.ThemeInternal != null && PagesConfig.Theme.Length != 0) 
                _mainDirectiveConfigSettings["theme"] = PagesConfig.Theme;
 
            if (PagesConfig.StyleSheetThemeInternal != null && PagesConfig.StyleSheetThemeInternal.Length != 0) 
                _mainDirectiveConfigSettings["stylesheettheme"] = PagesConfig.StyleSheetThemeInternal;
 
            if (PagesConfig.MasterPageFileInternal != null && PagesConfig.MasterPageFileInternal.Length != 0) {
                _configMasterPageFile = PagesConfig.MasterPageFileInternal;
            }
 
            if (PagesConfig.ViewStateEncryptionMode != Page.EncryptionModeDefault) {
                _mainDirectiveConfigSettings["viewStateEncryptionMode"] = Enum.Format(typeof(ViewStateEncryptionMode), PagesConfig.ViewStateEncryptionMode, "G"); 
            } 

            if (PagesConfig.MaintainScrollPositionOnPostBack != Page.MaintainScrollPositionOnPostBackDefault) { 
                _mainDirectiveConfigSettings["maintainScrollPositionOnPostBack"] = Util.GetStringFromBool(PagesConfig.MaintainScrollPositionOnPostBack);
            }

            if (PagesConfig.MaxPageStateFieldLength != Page.DefaultMaxPageStateFieldLength) { 
                _mainDirectiveConfigSettings["maxPageStateFieldLength"] = PagesConfig.MaxPageStateFieldLength;
            } 
 
            flags[requiresSessionState] = ((PagesConfig.EnableSessionState == PagesEnableSessionState.True) || (PagesConfig.EnableSessionState == PagesEnableSessionState.ReadOnly));
            flags[readOnlySessionState] = (PagesConfig.EnableSessionState == PagesEnableSessionState.ReadOnly); 
            flags[validateRequest] = PagesConfig.ValidateRequest;
            flags[aspCompatMode] = HttpRuntime.ApartmentThreading;

            if (PagesConfig.PageBaseTypeInternal != null) 
                BaseType = PagesConfig.PageBaseTypeInternal;
        } 
    } 

    internal override void ProcessDirective(string directiveName, IDictionary directive) { 

        if (StringUtil.EqualsIgnoreCase(directiveName, "previousPageType")) {

            if (_previousPageType != null) { 
                ProcessError(SR.GetString(SR.Only_one_directive_allowed, directiveName));
                return; 
            } 

            _previousPageType = GetDirectiveType(directive, directiveName); 
            Util.CheckAssignableType(typeof(Page), _previousPageType);
        }
        else if (StringUtil.EqualsIgnoreCase(directiveName, "masterType")) {
 
            if (_masterPageType != null) {
                ProcessError(SR.GetString(SR.Only_one_directive_allowed, directiveName)); 
                return; 
            }
 
            _masterPageType = GetDirectiveType(directive, directiveName);
            Util.CheckAssignableType(typeof(MasterPage), _masterPageType);
        }
        else { 
            base.ProcessDirective(directiveName, directive);
        } 
    } 

    // Override to get the location of maindirective. 
    internal override void ProcessMainDirective(IDictionary mainDirective) {
        // Remember the location of the main directive.
        _mainDirectiveLineNumber = _lineNumber;
 
        base.ProcessMainDirective(mainDirective);
    } 
 
    internal override bool ProcessMainDirectiveAttribute(string deviceName, string name,
        string value, IDictionary parseData) { 

        switch (name) {

        case "errorpage": 
            _errorPage = Util.GetNonEmptyAttribute(name, value);
 
            // Return false to let the generic attribute processing continue 
            return false;
 
        case "contenttype":
            // Check validity
            Util.GetNonEmptyAttribute(name, value);
 
            // Return false to let the generic attribute processing continue
            return false; 
 
        case "theme":
            if (IsExpressionBuilderValue(value)) { 
                return false;
            }

            // Check validity 
            Util.CheckThemeAttribute(value);
 
            // Return false to let the generic attribute processing continue 
            return false;
 
        case "stylesheettheme":
            // Make sure no device filter or expression builder was specified
            ValidateBuiltInAttribute(deviceName, name, value);
 
            // Check validity
            Util.CheckThemeAttribute(value); 
 
            _styleSheetTheme = value;
            return true; 

        case "enablesessionstate":
            flags[requiresSessionState] = true;
            flags[readOnlySessionState] = false; 
            if (Util.IsFalseString(value)) {
                flags[requiresSessionState] = false; 
            } 
            else if (StringUtil.EqualsIgnoreCase(value, "readonly")) {
                flags[readOnlySessionState] = true; 
            }
            else if (!Util.IsTrueString(value)) {
                ProcessError(SR.GetString(
                    SR.Enablesessionstate_must_be_true_false_or_readonly)); 
            }
 
            if (flags[requiresSessionState]) { 
                // Session state is only available for compiled pages
                OnFoundAttributeRequiringCompilation(name); 
            }
            break;

        case "culture": 
            _culture = Util.GetNonEmptyAttribute(name, value);
 
            // Setting culture requires medium permission 
            if (!HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Medium)) {
                throw new HttpException(SR.GetString(SR.Insufficient_trust_for_attribute, "culture")); 
            }

            //do not verify at parse time if potentially using browser AutoDetect
            if(StringUtil.EqualsIgnoreCase(value, HttpApplication.AutoCulture)) { 
                return false;
            } 
 

            // Create a CultureInfo just to verify validity 
            CultureInfo cultureInfo;

            try {
                if(StringUtil.StringStartsWithIgnoreCase(value, HttpApplication.AutoCulture)) { 
                    //safe to trim leading "auto:", string used elsewhere for null check
                    _culture = _culture.Substring(5); 
                } 
                cultureInfo = HttpServerUtility.CreateReadOnlyCultureInfo(_culture);
            } 
            catch {
                ProcessError(SR.GetString(SR.Invalid_attribute_value, _culture, "culture"));
                return false;
            } 

            // Don't allow neutral cultures (ASURT 77930) 
            if (cultureInfo.IsNeutralCulture) { 
                ProcessError(SR.GetString(SR.Invalid_culture_attribute,
                        Util.GetSpecificCulturesFormattedList(cultureInfo))); 
            }

            // Return false to let the generic attribute processing continue
            return false; 

        case "lcid": 
            // Skip validity check for expression builder (e.g. <%$ ... %>) 
            if (IsExpressionBuilderValue(value)) return false;
 
            _lcid = Util.GetNonNegativeIntegerAttribute(name, value);

            // Create a CultureInfo just to verify validity
            try { 
                HttpServerUtility.CreateReadOnlyCultureInfo(_lcid);
            } 
            catch { 
                ProcessError(SR.GetString(SR.Invalid_attribute_value,
                    _lcid.ToString(CultureInfo.InvariantCulture), "lcid")); 
            }

            // Return false to let the generic attribute processing continue
            return false; 

        case "uiculture": 
            // Check validity 
            Util.GetNonEmptyAttribute(name, value);
 
            // Return false to let the generic attribute processing continue
            return false;

        case "responseencoding": 
            // Skip validity check for expression builder (e.g. <%$ ... %>)
            if (IsExpressionBuilderValue(value)) return false; 
 
            _responseEncoding = Util.GetNonEmptyAttribute(name, value);
 
            // Call Encoding.GetEncoding just to verify validity
            Encoding.GetEncoding(_responseEncoding);

            // Return false to let the generic attribute processing continue 
            return false;
 
        case "codepage": 
            // Skip validity check for expression builder (e.g. <%$ ... %>)
            if (IsExpressionBuilderValue(value)) return false; 

            _codePage = Util.GetNonNegativeIntegerAttribute(name, value);

            // Call Encoding.GetEncoding just to verify validity 
            Encoding.GetEncoding(_codePage);
 
            // Return false to let the generic attribute processing continue 
            return false;
 
        case "transaction":
            // This only makes sense for compiled pages
            OnFoundAttributeRequiringCompilation(name);
 
            ParseTransactionAttribute(name, value);
            break; 
 
        case "aspcompat":
            // This only makes sense for compiled pages 
            OnFoundAttributeRequiringCompilation(name);

            flags[aspCompatMode] = Util.GetBooleanAttribute(name, value);
 
            // Only allow the use of aspcompat when we have UnmanagedCode access (ASURT 76694)
            if (flags[aspCompatMode] && !HttpRuntime.HasUnmanagedPermission()) { 
                throw new HttpException(SR.GetString(SR.Insufficient_trust_for_attribute, "AspCompat")); 
            }
 
            break;

        case "async":
            // This only makes sense for compiled pages 
            OnFoundAttributeRequiringCompilation(name);
 
            flags[asyncMode] = Util.GetBooleanAttribute(name, value); 

            // Async requires Medium trust 
            if (!HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Medium)) {
                throw new HttpException(SR.GetString(SR.Insufficient_trust_for_attribute, "async"));
            }
 
            break;
 
        case "tracemode": 
            // We use TraceModeInternal instead of TraceMode to disallow the 'default' value (ASURT 75783)
            object tmpObj = Util.GetEnumAttribute(name, value, typeof(TraceModeInternal)); 
            _traceMode = (TraceMode) tmpObj;
            break;

        case "trace": 
            bool traceEnabled = Util.GetBooleanAttribute(name, value);
            if (traceEnabled) 
                _traceEnabled = TraceEnable.Enable; 
            else
                _traceEnabled = TraceEnable.Disable; 
            break;

        case "smartnavigation":
            // Make sure no device filter or expression builder was specified, since it doesn't make much 
            // sense for smartnav (which only works on IE5.5+) (VSWhidbey 85876)
            ValidateBuiltInAttribute(deviceName, name, value); 
 
            // Ignore it if it has default value.  Otherwise, let the generic
            // attribute processing continue 
            bool smartNavigation = Util.GetBooleanAttribute(name, value);
            return (smartNavigation == Page.SmartNavigationDefault);

        case "maintainscrollpositiononpostback": 
            bool maintainScrollPosition = Util.GetBooleanAttribute(name, value);
            return (maintainScrollPosition == Page.MaintainScrollPositionOnPostBackDefault); 
 
        case "validaterequest":
            flags[validateRequest] = Util.GetBooleanAttribute(name, value); 
            break;

        case "clienttarget":
            // Skip validity check for expression builder (e.g. <%$ ... %>) 
            if (IsExpressionBuilderValue(value)) return false;
 
            // Check validity 
            HttpCapabilitiesEvaluator.GetUserAgentFromClientTarget(CurrentVirtualPath, value);
 
            // Return false to let the generic attribute processing continue
            return false;

        case "masterpagefile": 
            // Skip validity check for expression builder (e.g. <%$ ... %>)
            if (IsExpressionBuilderValue(value)) return false; 
 
            if (value.Length > 0) {
                // Add dependency on the Type by calling this method 
                Type type = GetReferencedType(value);

                // Make sure it has the correct base type
                if (!typeof(MasterPage).IsAssignableFrom(type)) { 
                    ProcessError(SR.GetString(SR.Invalid_master_base, value));
                } 
 
                if (deviceName.Length > 0) {
                    // Make sure the masterPageFile definition from config 
                    // is applied before filtered masterPageFile attributes.
                    EnsureMasterPageFileFromConfigApplied();
                }
            } 

            //VSWhidbey 479064 Remember the masterPageFile had been set even if it's empty string 
            _mainDirectiveMasterPageSet = true; 

            // Return false to let the generic attribute processing continue 
            return false;

        default:
            // We didn't handle the attribute.  Try the base class 
            return base.ProcessMainDirectiveAttribute(deviceName, name, value, parseData);
        } 
 
        // The attribute was handled
 
        // Make sure no device filter or resource expression was specified
        ValidateBuiltInAttribute(deviceName, name, value);

        return true; 
    }
 
    internal override void ProcessUnknownMainDirectiveAttribute(string filter, string attribName, string value) { 

        // asynctimeout is in seconds while the corresponding public page property is a timespan 
        // this requires a patch-up
        if (attribName == "asynctimeout") {
            int timeoutInSeconds = Util.GetNonNegativeIntegerAttribute(attribName, value);
            value = (new TimeSpan(0, 0, timeoutInSeconds)).ToString(); 
        }
 
        base.ProcessUnknownMainDirectiveAttribute(filter, attribName, value); 
    }
 
    internal override void PostProcessMainDirectiveAttributes(IDictionary parseData) {

        // Can't have an error page if buffering is off
        if (!flags[buffer] && _errorPage != null) { 
            ProcessError(SR.GetString(
                SR.Error_page_not_supported_when_buffering_off)); 
            return; 
        }
 
        if (_culture != null && _lcid > 0) {
            ProcessError(SR.GetString(SR.Attributes_mutually_exclusive, "Culture", "LCID"));
            return;
        } 

        if (_responseEncoding != null && _codePage > 0) { 
            ProcessError(SR.GetString(SR.Attributes_mutually_exclusive, "ResponseEncoding", "CodePage")); 
            return;
        } 

        // async can't be combined with aspcompat
        if (AsyncMode && AspCompatMode) {
            ProcessError(SR.GetString(SR.Async_and_aspcompat)); 
            return;
        } 
 
        // async can't be combined with transactions
        if (AsyncMode && _transactionMode != 0) { 
            ProcessError(SR.GetString(SR.Async_and_transaction));
            return;
        }
 
        // Let the base class do its post processing
        base.PostProcessMainDirectiveAttributes(parseData); 
    } 

    private enum TraceModeInternal { 
        SortByTime = 0,
        SortByCategory = 1
    }
 
    // This must be in its own method to avoid jitting System.EnterpriseServices.dll
    // when it is not needed (ASURT 71868) 
    private void ParseTransactionAttribute(string name, string value) { 
        object tmpObj = Util.GetEnumAttribute(name, value, typeof(TransactionOption));
        if (tmpObj != null) { 
            _transactionMode = (int) tmpObj;

            // Add a reference to the transaction assembly only if needed
            if (_transactionMode != 0 /*TransactionOption.Disabled*/) { 

                if (!HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Medium)) { 
                    throw new HttpException(SR.GetString(SR.Insufficient_trust_for_attribute, "transaction")); 
                }
 
                AddAssemblyDependency(typeof(TransactionOption).Assembly);
            }
        }
    } 

    internal const string defaultDirectiveName = "page"; 
    internal override string DefaultDirectiveName { 
        get { return defaultDirectiveName; }
    } 

    /*
     * Process the contents of the <%@ OutputCache ... %> directive
     */ 
    internal override void ProcessOutputCacheDirective(string directiveName, IDictionary directive) {
        string varyByContentEncoding; 
        string varyByHeader; 
        string sqlDependency;
        bool noStoreValue = false; 

        varyByContentEncoding = Util.GetAndRemoveNonEmptyAttribute(directive, "varybycontentencoding");
        if (varyByContentEncoding != null) {
            OutputCacheParameters.VaryByContentEncoding = varyByContentEncoding; 
        }
 
        varyByHeader = Util.GetAndRemoveNonEmptyAttribute(directive, "varybyheader"); 
        if (varyByHeader != null) {
            OutputCacheParameters.VaryByHeader = varyByHeader; 
        }

        object tmpObj = Util.GetAndRemoveEnumAttribute(directive, typeof(OutputCacheLocation), "location");
        if (tmpObj != null) { 
            _outputCacheLocation = (OutputCacheLocation) tmpObj;
            OutputCacheParameters.Location = _outputCacheLocation; 
        } 

        sqlDependency = Util.GetAndRemoveNonEmptyAttribute(directive, "sqldependency"); 
        if (sqlDependency != null) {
            OutputCacheParameters.SqlDependency = sqlDependency;
            // Validate the sqldependency attribute
            SqlCacheDependency.ValidateOutputCacheDependencyString(sqlDependency, true); 
        }
 
        // Get the "no store" bool value 
        if (Util.GetAndRemoveBooleanAttribute(directive, "nostore", ref noStoreValue)) {
            OutputCacheParameters.NoStore = noStoreValue; 
        }

        base.ProcessOutputCacheDirective(directiveName, directive);
    } 

    internal override bool FDurationRequiredOnOutputCache { 
        get { return _outputCacheLocation != OutputCacheLocation.None; } 
    }
 
    internal override bool FVaryByParamsRequiredOnOutputCache {
        get { return _outputCacheLocation != OutputCacheLocation.None; }
    }
 
    internal override string UnknownOutputCacheAttributeError {
        get { return SR.Attr_not_supported_in_pagedirective; } 
    } 
}
 
}


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK