You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			975 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			975 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //------------------------------------------------------------------------------
 | |
| // <copyright file="AdRotator.cs" company="Microsoft">
 | |
| //     Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| // </copyright>
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| 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;
 | |
| 
 | |
| 
 | |
|     /// <devdoc>
 | |
|     ///    <para>Displays a randomly selected ad banner on a page.</para>
 | |
|     /// </devdoc>
 | |
|     [
 | |
|     DefaultEvent("AdCreated"),
 | |
|     DefaultProperty("AdvertisementFile"),
 | |
|     Designer("System.Web.UI.Design.WebControls.AdRotatorDesigner, " + AssemblyRef.SystemDesign),
 | |
|     ToolboxData("<{0}:AdRotator runat=\"server\"></{0}:AdRotator>")
 | |
|     ]
 | |
|     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)};
 | |
| 
 | |
| 
 | |
|         /// <devdoc>
 | |
|         /// <para>Initializes a new instance of the <see cref='System.Web.UI.WebControls.AdRotator'/> class.</para>
 | |
|         /// </devdoc>
 | |
|         public AdRotator() {
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <devdoc>
 | |
|         ///    <para>Gets or sets the path to the XML file that contains advertisement data.</para>
 | |
|         /// </devdoc>
 | |
|         [
 | |
|         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;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <devdoc>
 | |
|         ///   The base url corresponds for mapping of other url elements such as
 | |
|         ///   imageUrl and navigateUrl.
 | |
|         /// </devdoc>
 | |
|         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;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <internalonly/>
 | |
|         /// <devdoc>
 | |
|         ///    Font property. Has no effect on this control, so hide it.
 | |
|         /// </devdoc>
 | |
|         [
 | |
|         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;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <devdoc>
 | |
|         ///    <para>Gets or sets a category keyword used for matching related advertisements in the advertisement file.</para>
 | |
|         /// </devdoc>
 | |
|         [
 | |
|         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;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <devdoc>
 | |
|         ///    <para>Gets
 | |
|         ///       or sets the name of the browser window or frame to display the advertisement.</para>
 | |
|         /// </devdoc>
 | |
|         [
 | |
|         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;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <devdoc>
 | |
|         ///    <para>Occurs once per round trip after the creation of the
 | |
|         ///       control before the page is rendered. </para>
 | |
|         /// </devdoc>
 | |
|         [
 | |
|         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;
 | |
|         }
 | |
| 
 | |
|         /// <devdoc>
 | |
|         ///     <para>Select an ad from ad records and create the event
 | |
|         ///     argument object.</para>
 | |
|         /// </devdoc>
 | |
|         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);
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <devdoc>
 | |
|         ///   Gets the ad data for the given file by loading the file, or reading from the
 | |
|         ///   application-level cache.
 | |
|         /// </devdoc>
 | |
|         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);
 | |
|             CacheStoreProvider cacheInternal = System.Web.HttpRuntime.Cache.InternalCache;
 | |
|             AdRec[] adRecs = cacheInternal.Get(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.Insert(fileKey, adRecs, new CacheInsertOptions() { Dependencies = 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;
 | |
|         }
 | |
| 
 | |
|         /// <devdoc>
 | |
|         ///   Loads the given XML stream into an array of AdRec structures
 | |
|         /// </devdoc>
 | |
|         private AdRec [] LoadStream(Stream stream) {
 | |
| 
 | |
|             AdRec [] adRecs = null;
 | |
|             try {
 | |
|                 // Read the XML stream into an array of dictionaries
 | |
|                 XmlReader reader = XmlUtils.CreateXmlReader(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;
 | |
|         }
 | |
| 
 | |
|         /// <devdoc>
 | |
|         ///   Used to determine if the advertisement meets current criteria. Does a comparison with
 | |
|         ///   KeywordFilter if it is set.
 | |
|         /// </devdoc>
 | |
|         private bool MatchingAd(AdRec adRec, string keywordFilter) {
 | |
|             Debug.Assert(keywordFilter != null && keywordFilter.Length > 0);
 | |
|             return(String.Equals(keywordFilter, adRec.keyword, StringComparison.OrdinalIgnoreCase));
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <devdoc>
 | |
|         /// <para>Raises the <see cref='System.Web.UI.WebControls.AdRotator.AdCreated'/> event for an <see cref='System.Web.UI.WebControls.AdRotator'/>.</para>
 | |
|         /// </devdoc>
 | |
|         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;
 | |
|         }
 | |
| 
 | |
|         /// <internalonly/>
 | |
|         /// <devdoc>
 | |
|         ///    <para>Gets the advertisement information for rendering in its parameter, then calls
 | |
|         ///     the OnAdCreated event to render the ads.</para>
 | |
|         /// </devdoc>
 | |
|         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;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <internalonly/>
 | |
|         /// <devdoc>
 | |
|         /// <para>Displays the <see cref='System.Web.UI.WebControls.AdRotator'/> on the client.</para>
 | |
|         /// </devdoc>
 | |
|         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 <AlternateText> 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);
 | |
|         }
 | |
| 
 | |
|         /// <devdoc>
 | |
|         ///     <para>Selects an advertisement from the a list of records based
 | |
|         ///     on different factors.</para>
 | |
|         /// </devdoc>
 | |
|         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;
 | |
|         }
 | |
| 
 | |
| 
 | |
| 
 | |
|         /// <devdoc>
 | |
|         ///   Structure to store ads in memory for fast selection by multiple instances of adrotator
 | |
|         ///   Stores the dictionary and caches some values for easier selection.
 | |
|         /// </devdoc>
 | |
|         private struct AdRec {
 | |
|             public string keyword;
 | |
|             public int impressions;
 | |
|             public IDictionary adProperties;
 | |
| 
 | |
| 
 | |
|             /// <devdoc>
 | |
|             ///   Initialize the stuct based on a dictionary containing the advertisement properties
 | |
|             /// </devdoc>
 | |
|             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;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |