AdRotator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / Web / UI / WebControls / AdRotator.cs / 1305376 / AdRotator.cs

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

namespace System.Web.UI.WebControls { 
    using System.IO; 
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls; 
    using System.Web.UI;
    using System.Web.Caching;
    using System.Web;
    using System; 
    using System.Collections;
    using System.Collections.Specialized; 
    using System.ComponentModel; 
    using System.ComponentModel.Design;
    using System.Drawing.Design; 
    using System.Xml;
    using System.Globalization;
    using System.Web.Util;
    using System.Reflection; 
    using System.Text;
 
 
    /// 
    ///    Displays a randomly selected ad banner on a page. 
    /// 
    [
    DefaultEvent("AdCreated"),
    DefaultProperty("AdvertisementFile"), 
    Designer("System.Web.UI.Design.WebControls.AdRotatorDesigner, " + AssemblyRef.SystemDesign),
    ToolboxData("<{0}:AdRotator runat=\"server\">") 
    ] 
    public class AdRotator : DataBoundControl {
 
        private static readonly object EventAdCreated = new object();

        private const string XmlDocumentTag = "Advertisements";
        private const string XmlDocumentRootXPath = "/" + XmlDocumentTag; 
        private const string XmlAdTag = "Ad";
 
        private const string KeywordProperty = "Keyword"; 
        private const string ImpressionsProperty = "Impressions";
 
        // static copy of the Random object. This is a pretty hefty object to
        // initialize, so you don't want to create one each time.
        private static Random _random;
 
        private String _baseUrl;
        private string _advertisementFile; 
        private AdCreatedEventArgs _adCreatedEventArgs; 

        private AdRec [] _adRecs; 
        private bool _isPostCacheAdHelper;
        private string _uniqueID;

        private static readonly Type _adrotatorType = typeof(AdRotator); 
        private static readonly Type[] _AdCreatedParameterTypes = {typeof(AdCreatedEventArgs)};
 
 
        /// 
        /// Initializes a new instance of the  class. 
        /// 
        public AdRotator() {
        }
 

        ///  
        ///    Gets or sets the path to the XML file that contains advertisement data. 
        /// 
        [ 
        Bindable(true),
        WebCategory("Behavior"),
        DefaultValue(""),
        Editor("System.Web.UI.Design.XmlUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)), 
        UrlProperty(),
        WebSysDescription(SR.AdRotator_AdvertisementFile) 
        ] 
        public string AdvertisementFile {
            get { 
                return((_advertisementFile == null) ? String.Empty : _advertisementFile);
            }
            set {
                _advertisementFile = value; 
            }
        } 
 

        [ 
        WebCategory("Behavior"),
        DefaultValue(AdCreatedEventArgs.AlternateTextElement),
        WebSysDescription(SR.AdRotator_AlternateTextField)
        ] 
        public String AlternateTextField {
            get { 
                String s = (String) ViewState["AlternateTextField"]; 
                return((s != null) ? s : AdCreatedEventArgs.AlternateTextElement);
            } 
            set {
                ViewState["AlternateTextField"] = value;
            }
        } 

        ///  
        ///   The base url corresponds for mapping of other url elements such as 
        ///   imageUrl and navigateUrl.
        ///  
        internal String BaseUrl {
            get {
                if (_baseUrl == null) {
                    // Deal with app relative syntax (e.g. ~/foo) 
                    string tplSourceDir = TemplateControlVirtualDirectory.VirtualPathString;
 
                    // For the AdRotator, use the AdvertisementFile directory as the base, and fall back to the 
                    // page/user control location as the base.
                    String absoluteFile = null; 
                    String fileDirectory = null;
                    if (!String.IsNullOrEmpty(AdvertisementFile)) {
                        absoluteFile = UrlPath.Combine(tplSourceDir, AdvertisementFile);
                        fileDirectory = UrlPath.GetDirectory(absoluteFile); 
                    }
 
                    _baseUrl = string.Empty; 
                    if (fileDirectory != null) {
                        _baseUrl = fileDirectory; 
                    }
                    if (_baseUrl.Length == 0) {
                        _baseUrl = tplSourceDir;
                    } 
                }
                return _baseUrl; 
            } 
        }
 
        /// 
        /// 
        ///    Font property. Has no effect on this control, so hide it.
        ///  
        [
        Browsable(false), 
        EditorBrowsableAttribute(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ] 
        public override FontInfo Font {
            get {
                return base.Font;
            } 
        }
 
 
        [
        WebCategory("Behavior"), 
        DefaultValue(AdCreatedEventArgs.ImageUrlElement),
        WebSysDescription(SR.AdRotator_ImageUrlField)
        ]
        public String ImageUrlField { 
            get {
                String s = (String) ViewState["ImageUrlField"]; 
                return((s != null) ? s : AdCreatedEventArgs.ImageUrlElement); 
            }
            set { 
                ViewState["ImageUrlField"] = value;
            }
        }
 
        private bool IsTargetSet {
            get { 
                return (ViewState["Target"] != null); 
            }
        } 

        internal bool IsPostCacheAdHelper {
            get {
                return _isPostCacheAdHelper; 
            }
            set { 
                _isPostCacheAdHelper = value; 
            }
        } 


        /// 
        ///    Gets or sets a category keyword used for matching related advertisements in the advertisement file. 
        /// 
        [ 
        Bindable(true), 
        WebCategory("Behavior"),
        DefaultValue(""), 
        WebSysDescription(SR.AdRotator_KeywordFilter)
        ]
        public string KeywordFilter {
            get { 
                string s = (string)ViewState["KeywordFilter"];
                return((s == null) ? String.Empty : s); 
            } 
            set {
                // trim the filter value 
                if (String.IsNullOrEmpty(value)) {
                    ViewState.Remove("KeywordFilter");
                }
                else { 
                    ViewState["KeywordFilter"] = value.Trim();
                } 
            } 
        }
 

        [
        WebCategory("Behavior"),
        DefaultValue(AdCreatedEventArgs.NavigateUrlElement), 
        WebSysDescription(SR.AdRotator_NavigateUrlField)
        ] 
        public String NavigateUrlField { 
            get {
                String s = (String) ViewState["NavigateUrlField"]; 
                return((s != null) ? s : AdCreatedEventArgs.NavigateUrlElement);
            }
            set {
                ViewState["NavigateUrlField"] = value; 
            }
        } 
 

        private AdCreatedEventArgs SelectedAdArgs { 
            get {
                return _adCreatedEventArgs;
            }
            set { 
                _adCreatedEventArgs = value;
            } 
        } 

 
        /// 
        ///    Gets
        ///       or sets the name of the browser window or frame to display the advertisement.
        ///  
        [
        Bindable(true), 
        WebCategory("Behavior"), 
        DefaultValue("_top"),
        WebSysDescription(SR.AdRotator_Target), 
        TypeConverter(typeof(TargetConverter))
        ]
        public string Target {
            get { 
                string s = (string)ViewState["Target"];
                return((s == null) ? "_top" : s); 
            } 
            set {
                ViewState["Target"] = value; 
            }
        }

 
        protected override HtmlTextWriterTag TagKey {
            get { 
                return HtmlTextWriterTag.A; 
            }
        } 

        public override string UniqueID {
            get {
                if (_uniqueID == null) { 
                    _uniqueID = base.UniqueID;
                } 
                return _uniqueID; 
            }
        } 


        /// 
        ///    Occurs once per round trip after the creation of the 
        ///       control before the page is rendered. 
        ///  
        [ 
        WebCategory("Action"),
        WebSysDescription(SR.AdRotator_OnAdCreated) 
        ]
        public event AdCreatedEventHandler AdCreated {
            add {
                Events.AddHandler(EventAdCreated, value); 
            }
            remove { 
                Events.RemoveHandler(EventAdCreated, value); 
            }
        } 

        private void CheckOnlyOneDataSource() {
            int numOfDataSources = ((AdvertisementFile.Length > 0) ? 1 : 0);
            numOfDataSources += ((DataSourceID.Length > 0) ? 1 : 0); 
            numOfDataSources += ((DataSource != null) ? 1 : 0);
 
            if (numOfDataSources > 1) { 
                throw new HttpException(SR.GetString(SR.AdRotator_only_one_datasource, ID));
            } 
        }

        // Currently this is designed to be called when PostCache Substitution is being initialized
        internal void CopyFrom(AdRotator adRotator) { 
            _adRecs = adRotator._adRecs;
 
            AccessKey = adRotator.AccessKey; 
            AlternateTextField = adRotator.AlternateTextField;
            Enabled = adRotator.Enabled; 
            ImageUrlField = adRotator.ImageUrlField;
            NavigateUrlField = adRotator.NavigateUrlField;
            TabIndex = adRotator.TabIndex;
            Target = adRotator.Target; 
            ToolTip = adRotator.ToolTip;
 
            string id = adRotator.ID; 
            if (!String.IsNullOrEmpty(id)) {
                ID = adRotator.ClientID; 
            }

            // Below are properties that need to be handled specially and saved
            // to private variables. 
            _uniqueID = adRotator.UniqueID;
            _baseUrl = adRotator.BaseUrl; 
 
            // Special copy to properties that cannot be assigned directly
            if (adRotator.HasAttributes) { 
                foreach(string key in adRotator.Attributes.Keys) {
                    Attributes[key] = adRotator.Attributes[key];
                }
            } 

            if (adRotator.ControlStyleCreated) { 
                ControlStyle.CopyFrom(adRotator.ControlStyle); 
            }
        } 


        private ArrayList CreateAutoGeneratedFields(IEnumerable dataSource) {
            if (dataSource == null) { 
                return null;
            } 
 
            ArrayList generatedFields = new ArrayList();
            PropertyDescriptorCollection propertyDescriptors = null; 

            if (dataSource is ITypedList) {
                propertyDescriptors =
                    ((ITypedList)dataSource).GetItemProperties(new PropertyDescriptor[0]); 
            }
 
            if (propertyDescriptors == null) { 

                IEnumerator enumerator = dataSource.GetEnumerator(); 
                if (enumerator.MoveNext()) {

                    Object sampleItem = enumerator.Current;
                    if (IsBindableType(sampleItem.GetType())) { 
                        // Raise error since we are expecting some record
                        // containing multiple data values. 
                        throw new HttpException(SR.GetString( 
                                SR.AdRotator_expect_records_with_advertisement_properties,
                                ID, sampleItem.GetType())); 
                    }
                    else {
                        propertyDescriptors = TypeDescriptor.GetProperties(sampleItem);
                    } 
                }
            } 
            if (propertyDescriptors != null && propertyDescriptors.Count > 0) { 

                foreach (PropertyDescriptor pd in propertyDescriptors) { 
                    if (IsBindableType(pd.PropertyType)) {
                        generatedFields.Add(pd.Name);
                    }
                } 
            }
 
            return generatedFields; 
        }
 

        //

 

 
 

 

        internal bool DoPostCacheSubstitutionAsNeeded(HtmlTextWriter writer) {
            if (!IsPostCacheAdHelper && SelectedAdArgs == null &&
                Page.Response.HasCachePolicy && 
                (int)Page.Response.Cache.GetCacheability() != (int)HttpCacheabilityLimits.None) {
 
                // The checking of the cacheability is to see if the page is output cached 
                AdPostCacheSubstitution adPostCacheSubstitution = new AdPostCacheSubstitution(this);
                adPostCacheSubstitution.RegisterPostCacheCallBack(Context, Page, writer); 
                return true;
            }
            return false;
        } 

        ///  
        ///     Select an ad from ad records and create the event 
        ///     argument object.
        ///  
        private AdCreatedEventArgs GetAdCreatedEventArgs() {
            IDictionary adInfo = SelectAdFromRecords();
            AdCreatedEventArgs adArgs =
                new AdCreatedEventArgs(adInfo, 
                                       ImageUrlField,
                                       NavigateUrlField, 
                                       AlternateTextField); 
           return adArgs;
        } 


        private AdRec [] GetDataSourceData(IEnumerable dataSource) {
 
            ArrayList fields = CreateAutoGeneratedFields(dataSource);
 
            ArrayList adDicts = new ArrayList(); 
            IEnumerator enumerator = dataSource.GetEnumerator();
            while(enumerator.MoveNext()) { 
                IDictionary dict = null;
                foreach (String field in fields){
                    if (dict == null) {
                        dict = new HybridDictionary(); 
                    }
                    dict.Add(field, DataBinder.GetPropertyValue(enumerator.Current, field)); 
                } 

                if (dict != null) { 
                    adDicts.Add(dict);
                }
            }
 
            return SetAdRecs(adDicts);
        } 
 

        ///  
        ///   Gets the ad data for the given file by loading the file, or reading from the
        ///   application-level cache.
        /// 
        private AdRec [] GetFileData(string fileName) { 

            // VSWhidbey 208626: Adopting similar code from xml.cs to support virtual path provider 
 
            // First, figure out if it's a physical or virtual path
            VirtualPath virtualPath; 
            string physicalPath;
            ResolvePhysicalOrVirtualPath(fileName, out virtualPath, out physicalPath);

            // try to get it from the ASP.NET cache 
            string fileKey = CacheInternal.PrefixAdRotator + ((!String.IsNullOrEmpty(physicalPath)) ?
                physicalPath : virtualPath.VirtualPathString); 
            CacheInternal cacheInternal = System.Web.HttpRuntime.CacheInternal; 
            AdRec [] adRecs = cacheInternal[fileKey] as AdRec[];
 
            if (adRecs == null) {
                // Otherwise load it
                CacheDependency dependency;
                try { 
                    using (Stream stream = OpenFileAndGetDependency(virtualPath, physicalPath, out dependency)) {
                        adRecs = LoadStream(stream); 
                        Debug.Assert(adRecs != null); 
                    }
                } 
                catch (Exception e) {
                    if (!String.IsNullOrEmpty(physicalPath) && HttpRuntime.HasPathDiscoveryPermission(physicalPath)) {
                        // We want to catch the error message, but not propage the inner exception. Otherwise we can throw up
                        // logon prompts through IE; 
                        throw new HttpException(SR.GetString(SR.AdRotator_cant_open_file, ID, e.Message));
                    } 
                    else { 
                        throw new HttpException(SR.GetString(SR.AdRotator_cant_open_file_no_permission, ID));
                    } 
                }

                // Cache it, but only if we got a dependency
                if (dependency != null) { 
                    using (dependency) {
                        // and store it in the cache, dependent on the file name 
                        cacheInternal.UtcInsert(fileKey, adRecs, dependency); 
                    }
                } 
            }
            return adRecs;
        }
 
        private static int GetRandomNumber(int maxValue) {
            if (_random == null) { 
                _random = new Random(); 
            }
            return _random.Next(maxValue) + 1; 
        }

        private AdRec [] GetXmlDataSourceData(XmlDataSource xmlDataSource) {
            Debug.Assert(xmlDataSource != null); 

            XmlDocument doc = xmlDataSource.GetXmlDocument(); 
            if (doc == null) { 
                return null;
            } 
            return LoadXmlDocument(doc);
        }

        private bool IsBindableType(Type type) { 
            return(type.IsPrimitive ||
                   (type == typeof(String)) || 
                   (type == typeof(DateTime)) || 
                   (type == typeof(Decimal)));
        } 

        private bool IsOnAdCreatedOverridden() {
            bool result = false;
            Type type = this.GetType(); 
            if (type != _adrotatorType) {
                MethodInfo methodInfo = type.GetMethod("OnAdCreated", 
                                                       BindingFlags.NonPublic | BindingFlags.Instance, 
                                                       null,
                                                       _AdCreatedParameterTypes, 
                                                       null);
                if (methodInfo.DeclaringType != _adrotatorType) {
                    result = true;
                } 
            }
            return result; 
        } 

        private AdRec [] LoadFromXmlReader(XmlReader reader) { 
            ArrayList adDicts = new ArrayList();

            while (reader.Read()) {
                if (reader.Name == "Advertisements") { 
                    if (reader.Depth != 0) {
                        return null; 
                    } 
                    break;
                } 
            }

            while (reader.Read()) {
                if (reader.NodeType == XmlNodeType.Element && reader.Name == "Ad" && reader.Depth == 1) { 

                    IDictionary dict = null; 
                    reader.Read(); 
                    while (!(reader.NodeType == XmlNodeType.EndElement)) {
                        if (reader.NodeType == XmlNodeType.Element && !reader.IsEmptyElement) { 
                            if (dict == null) {
                                dict = new HybridDictionary();
                            }
                            dict.Add(reader.LocalName, reader.ReadString()); 
                        }
                        reader.Skip(); 
                    } 

                    if (dict != null) { 
                        adDicts.Add(dict);
                    }
                }
            } 

            AdRec [] adRecs = SetAdRecs(adDicts); 
            return adRecs; 
        }
 
        /// 
        ///   Loads the given XML stream into an array of AdRec structures
        /// 
        private AdRec [] LoadStream(Stream stream) { 

            AdRec [] adRecs = null; 
            try { 
                // Read the XML stream into an array of dictionaries
                XmlReader reader = new XmlTextReader(stream); 

                // Perf: We use LoadFromXmlReader instead of LoadXmlDocument to
                // do the text parsing only once
                adRecs = LoadFromXmlReader(reader); 
            }
            catch (Exception e) { 
                throw new HttpException( 
                    SR.GetString(SR.AdRotator_parse_error, ID, e.Message), e);
            } 

            if (adRecs == null) {
                throw new HttpException(
                    SR.GetString(SR.AdRotator_no_advertisements, ID, AdvertisementFile)); 
            }
 
            return adRecs; 
        }
 
        private AdRec [] LoadXmlDocument(XmlDocument doc) {
            // Read the XML data into an array of dictionaries
            ArrayList adDicts = new ArrayList();
 
            if (doc.DocumentElement != null &&
                doc.DocumentElement.LocalName == XmlDocumentTag) { 
 
                XmlNode elem = doc.DocumentElement.FirstChild;
 
                while (elem != null) {
                    IDictionary dict = null;
                    if (elem.LocalName.Equals(XmlAdTag)) {
                        XmlNode prop = elem.FirstChild; 
                        while (prop != null) {
                            if (prop.NodeType == XmlNodeType.Element) { 
                                if (dict == null) { 
                                    dict = new HybridDictionary();
                                } 
                                dict.Add(prop.LocalName, prop.InnerText);
                            }
                            prop = prop.NextSibling;
                        } 
                    }
                    if (dict != null) { 
                        adDicts.Add(dict); 
                    }
                    elem = elem.NextSibling; 
                }
            }

            AdRec [] adRecs = SetAdRecs(adDicts); 
            return adRecs;
        } 
 
        /// 
        ///   Used to determine if the advertisement meets current criteria. Does a comparison with 
        ///   KeywordFilter if it is set.
        /// 
        private bool MatchingAd(AdRec adRec, string keywordFilter) {
            Debug.Assert(keywordFilter != null && keywordFilter.Length > 0); 
            return(String.Equals(keywordFilter, adRec.keyword, StringComparison.OrdinalIgnoreCase));
        } 
 

        ///  
        /// Raises the  event for an .
        /// 
        protected virtual void OnAdCreated(AdCreatedEventArgs e) {
            AdCreatedEventHandler handler = (AdCreatedEventHandler)Events[EventAdCreated]; 
            if (handler != null) handler(this, e);
        } 
 

        protected internal override void OnInit(EventArgs e) { 
            base.OnInit(e);

            // VSWhidbey 419600: We just always need binding data every time since
            // AdRotator doesn't store the entire Ad data in ViewState for selecting 
            // Ad during postbacks.  It's too big for storing in ViewState.
            RequiresDataBinding = true; 
        } 

        ///  
        /// 
        ///    Gets the advertisement information for rendering in its parameter, then calls
        ///     the OnAdCreated event to render the ads.
        ///  
        protected internal override void OnPreRender(EventArgs e) {
            base.OnPreRender(e); 
 
            // If after PreRender (which would call DataBind if DataSource or DataSourceID available)
            // and no _adRecs created, it must be the normal v1 behavior which uses ad file. 
            if (_adRecs == null && AdvertisementFile.Length > 0) {
                PerformAdFileBinding();
            }
 
            // If handler is specified, we don't do any post-cache
            // substitution because the handler code would not be executed. 
            // 
            // VSWhidbey 213759: We also don't want any post-cache substitution
            // if OnAdCreated has been overridden 
            if (Events[EventAdCreated] != null || IsOnAdCreatedOverridden()) {
                // Fire the user event for further customization
                SelectedAdArgs = GetAdCreatedEventArgs();
                OnAdCreated(SelectedAdArgs); 
            }
        } 
 
        private void PerformAdFileBinding() {
            // Getting ad data from physical file is V1 way which is not supported 
            // by the base class DataBoundControl so we had above code to handle
            // this case.  However, we need to support DataBound control events
            // in Whidbey and since above code doesn't go through the event
            // raising in the base class DataBoundControl, here we mimic them. 
            OnDataBinding(EventArgs.Empty);
 
            // get the ads from the file or app cache 
            _adRecs = GetFileData(AdvertisementFile);
 
            OnDataBound(EventArgs.Empty);
        }

        protected internal override void PerformDataBinding(IEnumerable data) { 
            if (data != null) {
                // We retrieve ad data from xml format in a specific way. 
                XmlDataSource xmlDataSource = null; 
                object dataSource = DataSource;
                if (dataSource != null) { 
                    xmlDataSource = dataSource as XmlDataSource;
                }
                else { // DataSourceID case, we know that only one source is available
                    xmlDataSource = GetDataSource() as XmlDataSource; 
                }
 
                if (xmlDataSource != null) { 
                    _adRecs = GetXmlDataSourceData(xmlDataSource);
                } 
                else {
                    _adRecs = GetDataSourceData(data);
                }
            } 
        }
 
        protected override void PerformSelect() { 
            // VSWhidbey 141362
            CheckOnlyOneDataSource(); 

            if (AdvertisementFile.Length > 0) {
                PerformAdFileBinding();
            } 
            else {
                base.PerformSelect(); 
            } 
        }
 
        //
        internal AdCreatedEventArgs PickAd() {
            AdCreatedEventArgs adArgs = SelectedAdArgs;
            if (adArgs == null) { 
                adArgs = GetAdCreatedEventArgs();
            } 
            adArgs.ImageUrl = ResolveAdRotatorUrl(BaseUrl, adArgs.ImageUrl); 
            adArgs.NavigateUrl = ResolveAdRotatorUrl(BaseUrl, adArgs.NavigateUrl);
            return adArgs; 
        }


        ///  
        /// 
        /// Displays the  on the client. 
        ///  
        protected internal override void Render(HtmlTextWriter writer) {
            if (!DesignMode && !IsPostCacheAdHelper && 
                DoPostCacheSubstitutionAsNeeded(writer)) {
                return;
            }
 
            AdCreatedEventArgs adArgs = PickAd();
            RenderLink(writer, adArgs); 
        } 

        private void RenderLink(HtmlTextWriter writer, AdCreatedEventArgs adArgs) { 
            Debug.Assert(writer != null);
            Debug.Assert(adArgs != null);

            HyperLink bannerLink = new HyperLink(); 

            bannerLink.NavigateUrl = adArgs.NavigateUrl; 
            bannerLink.Target = Target; 

            if (HasAttributes) { 
                foreach(string key in Attributes.Keys) {
                    bannerLink.Attributes[key] = Attributes[key];
                }
            } 

            string id = ID; 
            if (!String.IsNullOrEmpty(id)) { 
                bannerLink.ID = ClientID;
            } 

            if (!Enabled) {
                bannerLink.Enabled = false;
            } 

            // WebControl's properties use a private flag to determine if a 
            // property is set and does not return the value unless the flag is 
            // marked.  So here we access those properites (inherited from WebControl)
            // directly from the ViewState bag because if ViewState bag reference 
            // was copied to the helper class in the optimized case during the
            // Initialize() method, the flags of the properties wouldn't be set
            // in the helper class.
            string accessKey = (string) ViewState["AccessKey"]; 
            if (!String.IsNullOrEmpty(accessKey)) {
                bannerLink.AccessKey = accessKey; 
            } 

            object o = ViewState["TabIndex"]; 
            if (o != null) {
                short tabIndex = (short) o;
                if (tabIndex != (short) 0) {
                    bannerLink.TabIndex = tabIndex; 
                }
            } 
 
            bannerLink.RenderBeginTag(writer);
 
            // create inner Image
            Image bannerImage = new Image();
            // apply styles to image
            if (ControlStyleCreated) { 
                bannerImage.ApplyStyle(ControlStyle);
            } 
 
            string alternateText = adArgs.AlternateText;
            if (!String.IsNullOrEmpty(alternateText)) { 
                bannerImage.AlternateText = alternateText;
            }
            else {
                // 25914 Do not render empty 'alt' attribute if  tag is never specified 
                IDictionary adProps = adArgs.AdProperties;
                string altTextKey = (AlternateTextField.Length != 0) 
                                        ? AlternateTextField : AdCreatedEventArgs.AlternateTextElement; 
                string altText = (adProps == null) ? null : (string) adProps[altTextKey];
                if (altText != null && altText.Length == 0) { 
                    bannerImage.GenerateEmptyAlternateText = true;
                }
            }
 
            // Perf work: AdRotator should have resolved the NavigateUrl and
            // ImageUrl when assigning them and have UrlResolved set properly. 
            bannerImage.UrlResolved = true; 
            string imageUrl = adArgs.ImageUrl;
            if (!String.IsNullOrEmpty(imageUrl)) { 
                bannerImage.ImageUrl = imageUrl;
            }

            if (adArgs.HasWidth) { 
                bannerImage.ControlStyle.Width = adArgs.Width;
            } 
 
            if (adArgs.HasHeight) {
                bannerImage.ControlStyle.Height = adArgs.Height; 
            }

            string toolTip = (string) ViewState["ToolTip"];
            if (!String.IsNullOrEmpty(toolTip)) { 
                bannerImage.ToolTip = toolTip;
            } 
 
            bannerImage.RenderControl(writer);
            bannerLink.RenderEndTag(writer); 
        }

        private string ResolveAdRotatorUrl(string baseUrl, string relativeUrl) {
 
            if ((relativeUrl == null) ||
                (relativeUrl.Length == 0) || 
                (UrlPath.IsRelativeUrl(relativeUrl) == false) || 
                (baseUrl == null) ||
                (baseUrl.Length == 0)) { 
                return relativeUrl;
            }

            // make it absolute 
            return UrlPath.Combine(baseUrl, relativeUrl);
        } 
 
        /// 
        ///     Selects an advertisement from the a list of records based 
        ///     on different factors.
        /// 
        private IDictionary SelectAdFromRecords() {
            if (_adRecs == null || _adRecs.Length == 0) { 
                return null;
            } 
 
            string keywordFilter = KeywordFilter;
            bool noKeywordFilter = String.IsNullOrEmpty(keywordFilter); 
            if (!noKeywordFilter) {
                // do a lower case comparison
                keywordFilter = keywordFilter.ToLower(CultureInfo.InvariantCulture);
            } 

            // sum the matching impressions 
            int totalImpressions = 0; 
            for (int i = 0; i < _adRecs.Length; i++) {
                if (noKeywordFilter || MatchingAd(_adRecs[i], keywordFilter)) { 
                    totalImpressions += _adRecs[i].impressions;
                }
            }
 
            if (totalImpressions == 0) {
                return null; 
            } 

            // select one using a random number between 1 and totalImpressions 
            int selectedImpression = GetRandomNumber(totalImpressions);
            int impressionCounter = 0;
            int selectedIndex = -1;
            for (int i = 0; i < _adRecs.Length; i++) { 
                // Is this the ad?
                if (noKeywordFilter || MatchingAd(_adRecs[i], keywordFilter)) { 
                    impressionCounter += _adRecs[i].impressions; 
                    if (selectedImpression <= impressionCounter) {
                        selectedIndex = i; 
                        break;
                    }
                }
            } 
            Debug.Assert(selectedIndex >= 0 && selectedIndex < _adRecs.Length, "Index not found");
 
            return _adRecs[selectedIndex].adProperties; 
        }
 
        private AdRec [] SetAdRecs(ArrayList adDicts) {
            if (adDicts == null || adDicts.Count == 0) {
                return null;
            } 

            // Create an array of AdRec structures from the dictionaries, removing blanks 
            AdRec [] adRecs = new AdRec[adDicts.Count]; 
            int iRec = 0;
            for (int i = 0; i < adDicts.Count; i++) { 
                if (adDicts[i] != null) {
                    adRecs[iRec].Initialize((IDictionary) adDicts[i]);
                    iRec++;
                } 
            }
            Debug.Assert(iRec == adDicts.Count, "Record count did not match non-null entries"); 
 
            return adRecs;
        } 



        ///  
        ///   Structure to store ads in memory for fast selection by multiple instances of adrotator
        ///   Stores the dictionary and caches some values for easier selection. 
        ///  
        private struct AdRec {
            public string keyword; 
            public int impressions;
            public IDictionary adProperties;

 
            /// 
            ///   Initialize the stuct based on a dictionary containing the advertisement properties 
            ///  
            public void Initialize(IDictionary adProperties) {
 
                // Initialize the values we need to keep for ad selection
                Debug.Assert(adProperties != null, "Required here");
                this.adProperties = adProperties;
 
                // remove null and trim keyword for easier comparisons.
                // VSWhidbey 114634: Be defensive and only retrieve the keyword 
                // value if it is in string type 
                object keywordValue = adProperties[KeywordProperty];
                if (keywordValue != null && keywordValue is string) { 
                    keyword = ((string) keywordValue).Trim();
                }
                else {
                    keyword = string.Empty; 
                }
 
                // get the impressions, but be defensive: let the schema enforce the rules. Default to 1. 
                string impressionsString = adProperties[ImpressionsProperty] as string;
                if (String.IsNullOrEmpty(impressionsString) || 
                    !int.TryParse(impressionsString, NumberStyles.Integer,
                                   CultureInfo.InvariantCulture, out impressions)) {
                    impressions = 1;
                } 
                if (impressions < 0) {
                    impressions = 1; 
                } 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.UI.WebControls { 
    using System.IO; 
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls; 
    using System.Web.UI;
    using System.Web.Caching;
    using System.Web;
    using System; 
    using System.Collections;
    using System.Collections.Specialized; 
    using System.ComponentModel; 
    using System.ComponentModel.Design;
    using System.Drawing.Design; 
    using System.Xml;
    using System.Globalization;
    using System.Web.Util;
    using System.Reflection; 
    using System.Text;
 
 
    /// 
    ///    Displays a randomly selected ad banner on a page. 
    /// 
    [
    DefaultEvent("AdCreated"),
    DefaultProperty("AdvertisementFile"), 
    Designer("System.Web.UI.Design.WebControls.AdRotatorDesigner, " + AssemblyRef.SystemDesign),
    ToolboxData("<{0}:AdRotator runat=\"server\">") 
    ] 
    public class AdRotator : DataBoundControl {
 
        private static readonly object EventAdCreated = new object();

        private const string XmlDocumentTag = "Advertisements";
        private const string XmlDocumentRootXPath = "/" + XmlDocumentTag; 
        private const string XmlAdTag = "Ad";
 
        private const string KeywordProperty = "Keyword"; 
        private const string ImpressionsProperty = "Impressions";
 
        // static copy of the Random object. This is a pretty hefty object to
        // initialize, so you don't want to create one each time.
        private static Random _random;
 
        private String _baseUrl;
        private string _advertisementFile; 
        private AdCreatedEventArgs _adCreatedEventArgs; 

        private AdRec [] _adRecs; 
        private bool _isPostCacheAdHelper;
        private string _uniqueID;

        private static readonly Type _adrotatorType = typeof(AdRotator); 
        private static readonly Type[] _AdCreatedParameterTypes = {typeof(AdCreatedEventArgs)};
 
 
        /// 
        /// Initializes a new instance of the  class. 
        /// 
        public AdRotator() {
        }
 

        ///  
        ///    Gets or sets the path to the XML file that contains advertisement data. 
        /// 
        [ 
        Bindable(true),
        WebCategory("Behavior"),
        DefaultValue(""),
        Editor("System.Web.UI.Design.XmlUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)), 
        UrlProperty(),
        WebSysDescription(SR.AdRotator_AdvertisementFile) 
        ] 
        public string AdvertisementFile {
            get { 
                return((_advertisementFile == null) ? String.Empty : _advertisementFile);
            }
            set {
                _advertisementFile = value; 
            }
        } 
 

        [ 
        WebCategory("Behavior"),
        DefaultValue(AdCreatedEventArgs.AlternateTextElement),
        WebSysDescription(SR.AdRotator_AlternateTextField)
        ] 
        public String AlternateTextField {
            get { 
                String s = (String) ViewState["AlternateTextField"]; 
                return((s != null) ? s : AdCreatedEventArgs.AlternateTextElement);
            } 
            set {
                ViewState["AlternateTextField"] = value;
            }
        } 

        ///  
        ///   The base url corresponds for mapping of other url elements such as 
        ///   imageUrl and navigateUrl.
        ///  
        internal String BaseUrl {
            get {
                if (_baseUrl == null) {
                    // Deal with app relative syntax (e.g. ~/foo) 
                    string tplSourceDir = TemplateControlVirtualDirectory.VirtualPathString;
 
                    // For the AdRotator, use the AdvertisementFile directory as the base, and fall back to the 
                    // page/user control location as the base.
                    String absoluteFile = null; 
                    String fileDirectory = null;
                    if (!String.IsNullOrEmpty(AdvertisementFile)) {
                        absoluteFile = UrlPath.Combine(tplSourceDir, AdvertisementFile);
                        fileDirectory = UrlPath.GetDirectory(absoluteFile); 
                    }
 
                    _baseUrl = string.Empty; 
                    if (fileDirectory != null) {
                        _baseUrl = fileDirectory; 
                    }
                    if (_baseUrl.Length == 0) {
                        _baseUrl = tplSourceDir;
                    } 
                }
                return _baseUrl; 
            } 
        }
 
        /// 
        /// 
        ///    Font property. Has no effect on this control, so hide it.
        ///  
        [
        Browsable(false), 
        EditorBrowsableAttribute(EditorBrowsableState.Never), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ] 
        public override FontInfo Font {
            get {
                return base.Font;
            } 
        }
 
 
        [
        WebCategory("Behavior"), 
        DefaultValue(AdCreatedEventArgs.ImageUrlElement),
        WebSysDescription(SR.AdRotator_ImageUrlField)
        ]
        public String ImageUrlField { 
            get {
                String s = (String) ViewState["ImageUrlField"]; 
                return((s != null) ? s : AdCreatedEventArgs.ImageUrlElement); 
            }
            set { 
                ViewState["ImageUrlField"] = value;
            }
        }
 
        private bool IsTargetSet {
            get { 
                return (ViewState["Target"] != null); 
            }
        } 

        internal bool IsPostCacheAdHelper {
            get {
                return _isPostCacheAdHelper; 
            }
            set { 
                _isPostCacheAdHelper = value; 
            }
        } 


        /// 
        ///    Gets or sets a category keyword used for matching related advertisements in the advertisement file. 
        /// 
        [ 
        Bindable(true), 
        WebCategory("Behavior"),
        DefaultValue(""), 
        WebSysDescription(SR.AdRotator_KeywordFilter)
        ]
        public string KeywordFilter {
            get { 
                string s = (string)ViewState["KeywordFilter"];
                return((s == null) ? String.Empty : s); 
            } 
            set {
                // trim the filter value 
                if (String.IsNullOrEmpty(value)) {
                    ViewState.Remove("KeywordFilter");
                }
                else { 
                    ViewState["KeywordFilter"] = value.Trim();
                } 
            } 
        }
 

        [
        WebCategory("Behavior"),
        DefaultValue(AdCreatedEventArgs.NavigateUrlElement), 
        WebSysDescription(SR.AdRotator_NavigateUrlField)
        ] 
        public String NavigateUrlField { 
            get {
                String s = (String) ViewState["NavigateUrlField"]; 
                return((s != null) ? s : AdCreatedEventArgs.NavigateUrlElement);
            }
            set {
                ViewState["NavigateUrlField"] = value; 
            }
        } 
 

        private AdCreatedEventArgs SelectedAdArgs { 
            get {
                return _adCreatedEventArgs;
            }
            set { 
                _adCreatedEventArgs = value;
            } 
        } 

 
        /// 
        ///    Gets
        ///       or sets the name of the browser window or frame to display the advertisement.
        ///  
        [
        Bindable(true), 
        WebCategory("Behavior"), 
        DefaultValue("_top"),
        WebSysDescription(SR.AdRotator_Target), 
        TypeConverter(typeof(TargetConverter))
        ]
        public string Target {
            get { 
                string s = (string)ViewState["Target"];
                return((s == null) ? "_top" : s); 
            } 
            set {
                ViewState["Target"] = value; 
            }
        }

 
        protected override HtmlTextWriterTag TagKey {
            get { 
                return HtmlTextWriterTag.A; 
            }
        } 

        public override string UniqueID {
            get {
                if (_uniqueID == null) { 
                    _uniqueID = base.UniqueID;
                } 
                return _uniqueID; 
            }
        } 


        /// 
        ///    Occurs once per round trip after the creation of the 
        ///       control before the page is rendered. 
        ///  
        [ 
        WebCategory("Action"),
        WebSysDescription(SR.AdRotator_OnAdCreated) 
        ]
        public event AdCreatedEventHandler AdCreated {
            add {
                Events.AddHandler(EventAdCreated, value); 
            }
            remove { 
                Events.RemoveHandler(EventAdCreated, value); 
            }
        } 

        private void CheckOnlyOneDataSource() {
            int numOfDataSources = ((AdvertisementFile.Length > 0) ? 1 : 0);
            numOfDataSources += ((DataSourceID.Length > 0) ? 1 : 0); 
            numOfDataSources += ((DataSource != null) ? 1 : 0);
 
            if (numOfDataSources > 1) { 
                throw new HttpException(SR.GetString(SR.AdRotator_only_one_datasource, ID));
            } 
        }

        // Currently this is designed to be called when PostCache Substitution is being initialized
        internal void CopyFrom(AdRotator adRotator) { 
            _adRecs = adRotator._adRecs;
 
            AccessKey = adRotator.AccessKey; 
            AlternateTextField = adRotator.AlternateTextField;
            Enabled = adRotator.Enabled; 
            ImageUrlField = adRotator.ImageUrlField;
            NavigateUrlField = adRotator.NavigateUrlField;
            TabIndex = adRotator.TabIndex;
            Target = adRotator.Target; 
            ToolTip = adRotator.ToolTip;
 
            string id = adRotator.ID; 
            if (!String.IsNullOrEmpty(id)) {
                ID = adRotator.ClientID; 
            }

            // Below are properties that need to be handled specially and saved
            // to private variables. 
            _uniqueID = adRotator.UniqueID;
            _baseUrl = adRotator.BaseUrl; 
 
            // Special copy to properties that cannot be assigned directly
            if (adRotator.HasAttributes) { 
                foreach(string key in adRotator.Attributes.Keys) {
                    Attributes[key] = adRotator.Attributes[key];
                }
            } 

            if (adRotator.ControlStyleCreated) { 
                ControlStyle.CopyFrom(adRotator.ControlStyle); 
            }
        } 


        private ArrayList CreateAutoGeneratedFields(IEnumerable dataSource) {
            if (dataSource == null) { 
                return null;
            } 
 
            ArrayList generatedFields = new ArrayList();
            PropertyDescriptorCollection propertyDescriptors = null; 

            if (dataSource is ITypedList) {
                propertyDescriptors =
                    ((ITypedList)dataSource).GetItemProperties(new PropertyDescriptor[0]); 
            }
 
            if (propertyDescriptors == null) { 

                IEnumerator enumerator = dataSource.GetEnumerator(); 
                if (enumerator.MoveNext()) {

                    Object sampleItem = enumerator.Current;
                    if (IsBindableType(sampleItem.GetType())) { 
                        // Raise error since we are expecting some record
                        // containing multiple data values. 
                        throw new HttpException(SR.GetString( 
                                SR.AdRotator_expect_records_with_advertisement_properties,
                                ID, sampleItem.GetType())); 
                    }
                    else {
                        propertyDescriptors = TypeDescriptor.GetProperties(sampleItem);
                    } 
                }
            } 
            if (propertyDescriptors != null && propertyDescriptors.Count > 0) { 

                foreach (PropertyDescriptor pd in propertyDescriptors) { 
                    if (IsBindableType(pd.PropertyType)) {
                        generatedFields.Add(pd.Name);
                    }
                } 
            }
 
            return generatedFields; 
        }
 

        //

 

 
 

 

        internal bool DoPostCacheSubstitutionAsNeeded(HtmlTextWriter writer) {
            if (!IsPostCacheAdHelper && SelectedAdArgs == null &&
                Page.Response.HasCachePolicy && 
                (int)Page.Response.Cache.GetCacheability() != (int)HttpCacheabilityLimits.None) {
 
                // The checking of the cacheability is to see if the page is output cached 
                AdPostCacheSubstitution adPostCacheSubstitution = new AdPostCacheSubstitution(this);
                adPostCacheSubstitution.RegisterPostCacheCallBack(Context, Page, writer); 
                return true;
            }
            return false;
        } 

        ///  
        ///     Select an ad from ad records and create the event 
        ///     argument object.
        ///  
        private AdCreatedEventArgs GetAdCreatedEventArgs() {
            IDictionary adInfo = SelectAdFromRecords();
            AdCreatedEventArgs adArgs =
                new AdCreatedEventArgs(adInfo, 
                                       ImageUrlField,
                                       NavigateUrlField, 
                                       AlternateTextField); 
           return adArgs;
        } 


        private AdRec [] GetDataSourceData(IEnumerable dataSource) {
 
            ArrayList fields = CreateAutoGeneratedFields(dataSource);
 
            ArrayList adDicts = new ArrayList(); 
            IEnumerator enumerator = dataSource.GetEnumerator();
            while(enumerator.MoveNext()) { 
                IDictionary dict = null;
                foreach (String field in fields){
                    if (dict == null) {
                        dict = new HybridDictionary(); 
                    }
                    dict.Add(field, DataBinder.GetPropertyValue(enumerator.Current, field)); 
                } 

                if (dict != null) { 
                    adDicts.Add(dict);
                }
            }
 
            return SetAdRecs(adDicts);
        } 
 

        ///  
        ///   Gets the ad data for the given file by loading the file, or reading from the
        ///   application-level cache.
        /// 
        private AdRec [] GetFileData(string fileName) { 

            // VSWhidbey 208626: Adopting similar code from xml.cs to support virtual path provider 
 
            // First, figure out if it's a physical or virtual path
            VirtualPath virtualPath; 
            string physicalPath;
            ResolvePhysicalOrVirtualPath(fileName, out virtualPath, out physicalPath);

            // try to get it from the ASP.NET cache 
            string fileKey = CacheInternal.PrefixAdRotator + ((!String.IsNullOrEmpty(physicalPath)) ?
                physicalPath : virtualPath.VirtualPathString); 
            CacheInternal cacheInternal = System.Web.HttpRuntime.CacheInternal; 
            AdRec [] adRecs = cacheInternal[fileKey] as AdRec[];
 
            if (adRecs == null) {
                // Otherwise load it
                CacheDependency dependency;
                try { 
                    using (Stream stream = OpenFileAndGetDependency(virtualPath, physicalPath, out dependency)) {
                        adRecs = LoadStream(stream); 
                        Debug.Assert(adRecs != null); 
                    }
                } 
                catch (Exception e) {
                    if (!String.IsNullOrEmpty(physicalPath) && HttpRuntime.HasPathDiscoveryPermission(physicalPath)) {
                        // We want to catch the error message, but not propage the inner exception. Otherwise we can throw up
                        // logon prompts through IE; 
                        throw new HttpException(SR.GetString(SR.AdRotator_cant_open_file, ID, e.Message));
                    } 
                    else { 
                        throw new HttpException(SR.GetString(SR.AdRotator_cant_open_file_no_permission, ID));
                    } 
                }

                // Cache it, but only if we got a dependency
                if (dependency != null) { 
                    using (dependency) {
                        // and store it in the cache, dependent on the file name 
                        cacheInternal.UtcInsert(fileKey, adRecs, dependency); 
                    }
                } 
            }
            return adRecs;
        }
 
        private static int GetRandomNumber(int maxValue) {
            if (_random == null) { 
                _random = new Random(); 
            }
            return _random.Next(maxValue) + 1; 
        }

        private AdRec [] GetXmlDataSourceData(XmlDataSource xmlDataSource) {
            Debug.Assert(xmlDataSource != null); 

            XmlDocument doc = xmlDataSource.GetXmlDocument(); 
            if (doc == null) { 
                return null;
            } 
            return LoadXmlDocument(doc);
        }

        private bool IsBindableType(Type type) { 
            return(type.IsPrimitive ||
                   (type == typeof(String)) || 
                   (type == typeof(DateTime)) || 
                   (type == typeof(Decimal)));
        } 

        private bool IsOnAdCreatedOverridden() {
            bool result = false;
            Type type = this.GetType(); 
            if (type != _adrotatorType) {
                MethodInfo methodInfo = type.GetMethod("OnAdCreated", 
                                                       BindingFlags.NonPublic | BindingFlags.Instance, 
                                                       null,
                                                       _AdCreatedParameterTypes, 
                                                       null);
                if (methodInfo.DeclaringType != _adrotatorType) {
                    result = true;
                } 
            }
            return result; 
        } 

        private AdRec [] LoadFromXmlReader(XmlReader reader) { 
            ArrayList adDicts = new ArrayList();

            while (reader.Read()) {
                if (reader.Name == "Advertisements") { 
                    if (reader.Depth != 0) {
                        return null; 
                    } 
                    break;
                } 
            }

            while (reader.Read()) {
                if (reader.NodeType == XmlNodeType.Element && reader.Name == "Ad" && reader.Depth == 1) { 

                    IDictionary dict = null; 
                    reader.Read(); 
                    while (!(reader.NodeType == XmlNodeType.EndElement)) {
                        if (reader.NodeType == XmlNodeType.Element && !reader.IsEmptyElement) { 
                            if (dict == null) {
                                dict = new HybridDictionary();
                            }
                            dict.Add(reader.LocalName, reader.ReadString()); 
                        }
                        reader.Skip(); 
                    } 

                    if (dict != null) { 
                        adDicts.Add(dict);
                    }
                }
            } 

            AdRec [] adRecs = SetAdRecs(adDicts); 
            return adRecs; 
        }
 
        /// 
        ///   Loads the given XML stream into an array of AdRec structures
        /// 
        private AdRec [] LoadStream(Stream stream) { 

            AdRec [] adRecs = null; 
            try { 
                // Read the XML stream into an array of dictionaries
                XmlReader reader = new XmlTextReader(stream); 

                // Perf: We use LoadFromXmlReader instead of LoadXmlDocument to
                // do the text parsing only once
                adRecs = LoadFromXmlReader(reader); 
            }
            catch (Exception e) { 
                throw new HttpException( 
                    SR.GetString(SR.AdRotator_parse_error, ID, e.Message), e);
            } 

            if (adRecs == null) {
                throw new HttpException(
                    SR.GetString(SR.AdRotator_no_advertisements, ID, AdvertisementFile)); 
            }
 
            return adRecs; 
        }
 
        private AdRec [] LoadXmlDocument(XmlDocument doc) {
            // Read the XML data into an array of dictionaries
            ArrayList adDicts = new ArrayList();
 
            if (doc.DocumentElement != null &&
                doc.DocumentElement.LocalName == XmlDocumentTag) { 
 
                XmlNode elem = doc.DocumentElement.FirstChild;
 
                while (elem != null) {
                    IDictionary dict = null;
                    if (elem.LocalName.Equals(XmlAdTag)) {
                        XmlNode prop = elem.FirstChild; 
                        while (prop != null) {
                            if (prop.NodeType == XmlNodeType.Element) { 
                                if (dict == null) { 
                                    dict = new HybridDictionary();
                                } 
                                dict.Add(prop.LocalName, prop.InnerText);
                            }
                            prop = prop.NextSibling;
                        } 
                    }
                    if (dict != null) { 
                        adDicts.Add(dict); 
                    }
                    elem = elem.NextSibling; 
                }
            }

            AdRec [] adRecs = SetAdRecs(adDicts); 
            return adRecs;
        } 
 
        /// 
        ///   Used to determine if the advertisement meets current criteria. Does a comparison with 
        ///   KeywordFilter if it is set.
        /// 
        private bool MatchingAd(AdRec adRec, string keywordFilter) {
            Debug.Assert(keywordFilter != null && keywordFilter.Length > 0); 
            return(String.Equals(keywordFilter, adRec.keyword, StringComparison.OrdinalIgnoreCase));
        } 
 

        ///  
        /// Raises the  event for an .
        /// 
        protected virtual void OnAdCreated(AdCreatedEventArgs e) {
            AdCreatedEventHandler handler = (AdCreatedEventHandler)Events[EventAdCreated]; 
            if (handler != null) handler(this, e);
        } 
 

        protected internal override void OnInit(EventArgs e) { 
            base.OnInit(e);

            // VSWhidbey 419600: We just always need binding data every time since
            // AdRotator doesn't store the entire Ad data in ViewState for selecting 
            // Ad during postbacks.  It's too big for storing in ViewState.
            RequiresDataBinding = true; 
        } 

        ///  
        /// 
        ///    Gets the advertisement information for rendering in its parameter, then calls
        ///     the OnAdCreated event to render the ads.
        ///  
        protected internal override void OnPreRender(EventArgs e) {
            base.OnPreRender(e); 
 
            // If after PreRender (which would call DataBind if DataSource or DataSourceID available)
            // and no _adRecs created, it must be the normal v1 behavior which uses ad file. 
            if (_adRecs == null && AdvertisementFile.Length > 0) {
                PerformAdFileBinding();
            }
 
            // If handler is specified, we don't do any post-cache
            // substitution because the handler code would not be executed. 
            // 
            // VSWhidbey 213759: We also don't want any post-cache substitution
            // if OnAdCreated has been overridden 
            if (Events[EventAdCreated] != null || IsOnAdCreatedOverridden()) {
                // Fire the user event for further customization
                SelectedAdArgs = GetAdCreatedEventArgs();
                OnAdCreated(SelectedAdArgs); 
            }
        } 
 
        private void PerformAdFileBinding() {
            // Getting ad data from physical file is V1 way which is not supported 
            // by the base class DataBoundControl so we had above code to handle
            // this case.  However, we need to support DataBound control events
            // in Whidbey and since above code doesn't go through the event
            // raising in the base class DataBoundControl, here we mimic them. 
            OnDataBinding(EventArgs.Empty);
 
            // get the ads from the file or app cache 
            _adRecs = GetFileData(AdvertisementFile);
 
            OnDataBound(EventArgs.Empty);
        }

        protected internal override void PerformDataBinding(IEnumerable data) { 
            if (data != null) {
                // We retrieve ad data from xml format in a specific way. 
                XmlDataSource xmlDataSource = null; 
                object dataSource = DataSource;
                if (dataSource != null) { 
                    xmlDataSource = dataSource as XmlDataSource;
                }
                else { // DataSourceID case, we know that only one source is available
                    xmlDataSource = GetDataSource() as XmlDataSource; 
                }
 
                if (xmlDataSource != null) { 
                    _adRecs = GetXmlDataSourceData(xmlDataSource);
                } 
                else {
                    _adRecs = GetDataSourceData(data);
                }
            } 
        }
 
        protected override void PerformSelect() { 
            // VSWhidbey 141362
            CheckOnlyOneDataSource(); 

            if (AdvertisementFile.Length > 0) {
                PerformAdFileBinding();
            } 
            else {
                base.PerformSelect(); 
            } 
        }
 
        //
        internal AdCreatedEventArgs PickAd() {
            AdCreatedEventArgs adArgs = SelectedAdArgs;
            if (adArgs == null) { 
                adArgs = GetAdCreatedEventArgs();
            } 
            adArgs.ImageUrl = ResolveAdRotatorUrl(BaseUrl, adArgs.ImageUrl); 
            adArgs.NavigateUrl = ResolveAdRotatorUrl(BaseUrl, adArgs.NavigateUrl);
            return adArgs; 
        }


        ///  
        /// 
        /// Displays the  on the client. 
        ///  
        protected internal override void Render(HtmlTextWriter writer) {
            if (!DesignMode && !IsPostCacheAdHelper && 
                DoPostCacheSubstitutionAsNeeded(writer)) {
                return;
            }
 
            AdCreatedEventArgs adArgs = PickAd();
            RenderLink(writer, adArgs); 
        } 

        private void RenderLink(HtmlTextWriter writer, AdCreatedEventArgs adArgs) { 
            Debug.Assert(writer != null);
            Debug.Assert(adArgs != null);

            HyperLink bannerLink = new HyperLink(); 

            bannerLink.NavigateUrl = adArgs.NavigateUrl; 
            bannerLink.Target = Target; 

            if (HasAttributes) { 
                foreach(string key in Attributes.Keys) {
                    bannerLink.Attributes[key] = Attributes[key];
                }
            } 

            string id = ID; 
            if (!String.IsNullOrEmpty(id)) { 
                bannerLink.ID = ClientID;
            } 

            if (!Enabled) {
                bannerLink.Enabled = false;
            } 

            // WebControl's properties use a private flag to determine if a 
            // property is set and does not return the value unless the flag is 
            // marked.  So here we access those properites (inherited from WebControl)
            // directly from the ViewState bag because if ViewState bag reference 
            // was copied to the helper class in the optimized case during the
            // Initialize() method, the flags of the properties wouldn't be set
            // in the helper class.
            string accessKey = (string) ViewState["AccessKey"]; 
            if (!String.IsNullOrEmpty(accessKey)) {
                bannerLink.AccessKey = accessKey; 
            } 

            object o = ViewState["TabIndex"]; 
            if (o != null) {
                short tabIndex = (short) o;
                if (tabIndex != (short) 0) {
                    bannerLink.TabIndex = tabIndex; 
                }
            } 
 
            bannerLink.RenderBeginTag(writer);
 
            // create inner Image
            Image bannerImage = new Image();
            // apply styles to image
            if (ControlStyleCreated) { 
                bannerImage.ApplyStyle(ControlStyle);
            } 
 
            string alternateText = adArgs.AlternateText;
            if (!String.IsNullOrEmpty(alternateText)) { 
                bannerImage.AlternateText = alternateText;
            }
            else {
                // 25914 Do not render empty 'alt' attribute if  tag is never specified 
                IDictionary adProps = adArgs.AdProperties;
                string altTextKey = (AlternateTextField.Length != 0) 
                                        ? AlternateTextField : AdCreatedEventArgs.AlternateTextElement; 
                string altText = (adProps == null) ? null : (string) adProps[altTextKey];
                if (altText != null && altText.Length == 0) { 
                    bannerImage.GenerateEmptyAlternateText = true;
                }
            }
 
            // Perf work: AdRotator should have resolved the NavigateUrl and
            // ImageUrl when assigning them and have UrlResolved set properly. 
            bannerImage.UrlResolved = true; 
            string imageUrl = adArgs.ImageUrl;
            if (!String.IsNullOrEmpty(imageUrl)) { 
                bannerImage.ImageUrl = imageUrl;
            }

            if (adArgs.HasWidth) { 
                bannerImage.ControlStyle.Width = adArgs.Width;
            } 
 
            if (adArgs.HasHeight) {
                bannerImage.ControlStyle.Height = adArgs.Height; 
            }

            string toolTip = (string) ViewState["ToolTip"];
            if (!String.IsNullOrEmpty(toolTip)) { 
                bannerImage.ToolTip = toolTip;
            } 
 
            bannerImage.RenderControl(writer);
            bannerLink.RenderEndTag(writer); 
        }

        private string ResolveAdRotatorUrl(string baseUrl, string relativeUrl) {
 
            if ((relativeUrl == null) ||
                (relativeUrl.Length == 0) || 
                (UrlPath.IsRelativeUrl(relativeUrl) == false) || 
                (baseUrl == null) ||
                (baseUrl.Length == 0)) { 
                return relativeUrl;
            }

            // make it absolute 
            return UrlPath.Combine(baseUrl, relativeUrl);
        } 
 
        /// 
        ///     Selects an advertisement from the a list of records based 
        ///     on different factors.
        /// 
        private IDictionary SelectAdFromRecords() {
            if (_adRecs == null || _adRecs.Length == 0) { 
                return null;
            } 
 
            string keywordFilter = KeywordFilter;
            bool noKeywordFilter = String.IsNullOrEmpty(keywordFilter); 
            if (!noKeywordFilter) {
                // do a lower case comparison
                keywordFilter = keywordFilter.ToLower(CultureInfo.InvariantCulture);
            } 

            // sum the matching impressions 
            int totalImpressions = 0; 
            for (int i = 0; i < _adRecs.Length; i++) {
                if (noKeywordFilter || MatchingAd(_adRecs[i], keywordFilter)) { 
                    totalImpressions += _adRecs[i].impressions;
                }
            }
 
            if (totalImpressions == 0) {
                return null; 
            } 

            // select one using a random number between 1 and totalImpressions 
            int selectedImpression = GetRandomNumber(totalImpressions);
            int impressionCounter = 0;
            int selectedIndex = -1;
            for (int i = 0; i < _adRecs.Length; i++) { 
                // Is this the ad?
                if (noKeywordFilter || MatchingAd(_adRecs[i], keywordFilter)) { 
                    impressionCounter += _adRecs[i].impressions; 
                    if (selectedImpression <= impressionCounter) {
                        selectedIndex = i; 
                        break;
                    }
                }
            } 
            Debug.Assert(selectedIndex >= 0 && selectedIndex < _adRecs.Length, "Index not found");
 
            return _adRecs[selectedIndex].adProperties; 
        }
 
        private AdRec [] SetAdRecs(ArrayList adDicts) {
            if (adDicts == null || adDicts.Count == 0) {
                return null;
            } 

            // Create an array of AdRec structures from the dictionaries, removing blanks 
            AdRec [] adRecs = new AdRec[adDicts.Count]; 
            int iRec = 0;
            for (int i = 0; i < adDicts.Count; i++) { 
                if (adDicts[i] != null) {
                    adRecs[iRec].Initialize((IDictionary) adDicts[i]);
                    iRec++;
                } 
            }
            Debug.Assert(iRec == adDicts.Count, "Record count did not match non-null entries"); 
 
            return adRecs;
        } 



        ///  
        ///   Structure to store ads in memory for fast selection by multiple instances of adrotator
        ///   Stores the dictionary and caches some values for easier selection. 
        ///  
        private struct AdRec {
            public string keyword; 
            public int impressions;
            public IDictionary adProperties;

 
            /// 
            ///   Initialize the stuct based on a dictionary containing the advertisement properties 
            ///  
            public void Initialize(IDictionary adProperties) {
 
                // Initialize the values we need to keep for ad selection
                Debug.Assert(adProperties != null, "Required here");
                this.adProperties = adProperties;
 
                // remove null and trim keyword for easier comparisons.
                // VSWhidbey 114634: Be defensive and only retrieve the keyword 
                // value if it is in string type 
                object keywordValue = adProperties[KeywordProperty];
                if (keywordValue != null && keywordValue is string) { 
                    keyword = ((string) keywordValue).Trim();
                }
                else {
                    keyword = string.Empty; 
                }
 
                // get the impressions, but be defensive: let the schema enforce the rules. Default to 1. 
                string impressionsString = adProperties[ImpressionsProperty] as string;
                if (String.IsNullOrEmpty(impressionsString) || 
                    !int.TryParse(impressionsString, NumberStyles.Integer,
                                   CultureInfo.InvariantCulture, out impressions)) {
                    impressions = 1;
                } 
                if (impressions < 0) {
                    impressions = 1; 
                } 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

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