AdRotator.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. //
  2. // System.Web.UI.WebControls.AdRotator.cs
  3. //
  4. // Authors:
  5. // Gaurav Vaish ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. // Andreas Nahr ([email protected])
  8. // Sanjay Gupta ([email protected])
  9. //
  10. // (c) 2002 Ximian, Inc. (http://www.ximian.com)
  11. // (C) Gaurav Vaish (2002)
  12. // (C) 2003 Andreas Nahr
  13. // (C) 2004 Novell, Inc. (http://www.novell.com)
  14. //
  15. //
  16. // Permission is hereby granted, free of charge, to any person obtaining
  17. // a copy of this software and associated documentation files (the
  18. // "Software"), to deal in the Software without restriction, including
  19. // without limitation the rights to use, copy, modify, merge, publish,
  20. // distribute, sublicense, and/or sell copies of the Software, and to
  21. // permit persons to whom the Software is furnished to do so, subject to
  22. // the following conditions:
  23. //
  24. // The above copyright notice and this permission notice shall be
  25. // included in all copies or substantial portions of the Software.
  26. //
  27. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  28. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  29. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  30. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  31. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  32. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  33. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  34. //
  35. using System;
  36. using System.IO;
  37. using System.Collections;
  38. using System.Collections.Specialized;
  39. using System.Web;
  40. using System.Web.Caching;
  41. using System.Web.UI;
  42. using System.Xml;
  43. using System.Web.Util;
  44. using System.ComponentModel;
  45. using System.ComponentModel.Design;
  46. namespace System.Web.UI.WebControls
  47. {
  48. [DefaultEvent("AdCreated")]
  49. [DefaultProperty("AdvertisementFile")]
  50. [Designer ("System.Web.UI.Design.WebControls.AdRotatorDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]
  51. [ToolboxData("<{0}:AdRotator runat=\"server\" Height=\"60px\" "
  52. + "Width=\"468\"></{0}:AdRotator>")]
  53. public class AdRotator: WebControl
  54. {
  55. string advertisementFile;
  56. static readonly object AdCreatedEvent = new object();
  57. // Will be set values during (On)PreRender-ing
  58. string alternateText;
  59. string imageUrl;
  60. string navigateUrl;
  61. string fileDirectory;
  62. Random random;
  63. public AdRotator ()
  64. {
  65. advertisementFile = "";
  66. fileDirectory = null;
  67. }
  68. AdRecord[] LoadAdFile (string file)
  69. {
  70. Stream fStream;
  71. try {
  72. fStream = new FileStream (file, FileMode.Open, FileAccess.Read, FileShare.Read);
  73. } catch (Exception e) {
  74. throw new HttpException("AdRotator: Unable to open file", e);
  75. }
  76. ArrayList list = new ArrayList ();
  77. try {
  78. IDictionary hybridDict = null;
  79. XmlDocument document = new XmlDocument ();
  80. document.Load (fStream);
  81. XmlElement docElem = document.DocumentElement;
  82. if (docElem == null)
  83. throw new HttpException ("No advertisements found");
  84. if (docElem.LocalName != "Advertisements")
  85. throw new HttpException ("No advertisements found: invalid document element");
  86. XmlNode node = docElem.FirstChild;
  87. while (node != null) {
  88. if (node.LocalName == "Ad") {
  89. XmlNode innerNode = node.FirstChild;
  90. while (innerNode != null) {
  91. if (node.NodeType == XmlNodeType.Element) {
  92. if (hybridDict == null)
  93. hybridDict = new HybridDictionary ();
  94. hybridDict.Add (innerNode.LocalName, innerNode.InnerText);
  95. }
  96. innerNode = innerNode.NextSibling;
  97. }
  98. if (hybridDict != null) {
  99. list.Add (hybridDict);
  100. hybridDict = null;
  101. }
  102. }
  103. node = node.NextSibling;
  104. }
  105. } catch(Exception e) {
  106. throw new HttpException("Parse error:" + file, e);
  107. } finally {
  108. if (fStream != null)
  109. fStream.Close();
  110. }
  111. if (list.Count == 0)
  112. throw new HttpException ("No advertisements found");
  113. AdRecord [] adsArray = new AdRecord [list.Count];
  114. int count = list.Count;
  115. for (int i = 0; i < count; i++)
  116. adsArray [i] = new AdRecord ((IDictionary) list [i]);
  117. return adsArray;
  118. }
  119. AdRecord [] GetData (string file)
  120. {
  121. string physPath = MapPathSecure (file);
  122. string AdKey = "AdRotatorCache: " + physPath;
  123. fileDirectory = UrlUtils.GetDirectory (UrlUtils.Combine (TemplateSourceDirectory, file));
  124. Cache cache = HttpRuntime.Cache;
  125. AdRecord[] records = (AdRecord[]) cache [AdKey];
  126. if (records == null) {
  127. records = LoadAdFile (physPath);
  128. cache.Insert (AdKey, records, new CacheDependency (physPath));
  129. }
  130. return records;
  131. }
  132. IDictionary SelectAd ()
  133. {
  134. AdRecord[] records = GetData (AdvertisementFile);
  135. if (records == null || records.Length ==0)
  136. return null;
  137. int impressions = 0;
  138. int rlength = records.Length;
  139. for (int i=0 ; i < rlength; i++) {
  140. if (IsAdMatching (records [i]))
  141. impressions += records [i].Hits;
  142. }
  143. if (impressions == 0)
  144. return null;
  145. if (random == null)
  146. random = new Random ();
  147. int rnd = random.Next (impressions) + 1;
  148. int counter = 0;
  149. int index = 0;
  150. for (int i = 0; i < rlength; i++) {
  151. if(IsAdMatching(records[i])) {
  152. if (rnd <= (counter + records [i].Hits)) {
  153. index = i;
  154. break;
  155. }
  156. counter += records [i].Hits;
  157. }
  158. }
  159. return records [index].Properties;
  160. }
  161. private bool IsAdMatching (AdRecord currAd)
  162. {
  163. if (KeywordFilter != String.Empty)
  164. return (0 == String.Compare (currAd.Keyword, KeywordFilter, true));
  165. return true;
  166. }
  167. private string ResolveAdUrl (string relativeUrl)
  168. {
  169. if (relativeUrl.Length==0 || !UrlUtils.IsRelativeUrl (relativeUrl))
  170. return relativeUrl;
  171. string fullUrl;
  172. if (fileDirectory != null)
  173. fullUrl = fileDirectory;
  174. else
  175. fullUrl = TemplateSourceDirectory;
  176. if (fullUrl.Length == 0)
  177. return relativeUrl;
  178. return UrlUtils.Combine (fullUrl, relativeUrl);
  179. }
  180. [WebCategory("Action")]
  181. [WebSysDescription("AdRotator_OnAdCreated")]
  182. public event AdCreatedEventHandler AdCreated {
  183. add { Events.AddHandler (AdCreatedEvent, value); }
  184. remove { Events.RemoveHandler (AdCreatedEvent, value); }
  185. }
  186. [Bindable(true)]
  187. [DefaultValue("")]
  188. [Editor ("System.Web.UI.Design.XmlUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
  189. [WebCategory("Behavior")]
  190. [WebSysDescription("AdRotator_AdvertisementFile")]
  191. #if NET_2_0
  192. [Localizable (true)]
  193. [UrlProperty ()]
  194. #endif
  195. public string AdvertisementFile {
  196. get { return ((advertisementFile != null) ? advertisementFile : ""); }
  197. set { advertisementFile = value; }
  198. }
  199. [Browsable (false), EditorBrowsable (EditorBrowsableState.Never)]
  200. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  201. public override FontInfo Font {
  202. get { return base.Font; }
  203. }
  204. [Bindable(true)]
  205. [DefaultValue("")]
  206. [WebCategory("Behavior")]
  207. [WebSysDescription("AdRotator_KeywordFilter")]
  208. public string KeywordFilter {
  209. get {
  210. object o = ViewState ["KeywordFilter"];
  211. if (o != null)
  212. return (string) o;
  213. return String.Empty;
  214. }
  215. set {
  216. if(value != null)
  217. ViewState ["KeywordFilter"] = value.Trim ();
  218. }
  219. }
  220. [Bindable(true)]
  221. [DefaultValue("")]
  222. [TypeConverter(typeof(TargetConverter))]
  223. [WebCategory("Behavior")]
  224. [WebSysDescription("AdRotator_Target")]
  225. public string Target {
  226. get {
  227. object o = ViewState ["Target"];
  228. if (o != null)
  229. return (string) o;
  230. return "_top";
  231. }
  232. set {
  233. ViewState["Target"] = value;
  234. }
  235. }
  236. protected override ControlCollection CreateControlCollection ()
  237. {
  238. return new EmptyControlCollection (this);
  239. }
  240. protected virtual void OnAdCreated (AdCreatedEventArgs e)
  241. {
  242. if (Events == null)
  243. return;
  244. AdCreatedEventHandler aceh = (AdCreatedEventHandler) Events [AdCreatedEvent];
  245. if (aceh != null)
  246. aceh (this, e);
  247. }
  248. protected override void OnPreRender (EventArgs e)
  249. {
  250. if(AdvertisementFile == String.Empty)
  251. return;
  252. AdCreatedEventArgs acea = new AdCreatedEventArgs (SelectAd ());
  253. OnAdCreated (acea);
  254. imageUrl = acea.ImageUrl;
  255. navigateUrl = acea.NavigateUrl;
  256. alternateText = acea.AlternateText;
  257. }
  258. [MonoTODO ("Update method with net 2.0 properties added for AdRotator class")]
  259. protected override void Render (HtmlTextWriter writer)
  260. {
  261. HyperLink hLink = new HyperLink ();
  262. Image adImage = new Image();
  263. foreach (string current in Attributes.Keys)
  264. hLink.Attributes [current] = Attributes [current];
  265. if (ID != null && ID.Length > 0)
  266. hLink.ID = ID;
  267. hLink.Target = Target;
  268. hLink.AccessKey = AccessKey;
  269. hLink.Enabled = Enabled;
  270. hLink.TabIndex = TabIndex;
  271. if (navigateUrl != null && navigateUrl.Length != 0)
  272. hLink.NavigateUrl = ResolveAdUrl (navigateUrl);
  273. hLink.RenderBeginTag (writer);
  274. if (ControlStyleCreated)
  275. adImage.ApplyStyle(ControlStyle);
  276. if(imageUrl!=null && imageUrl.Length > 0)
  277. adImage.ImageUrl = ResolveAdUrl (imageUrl);
  278. adImage.AlternateText = alternateText;
  279. adImage.ToolTip = ToolTip;
  280. adImage.RenderControl (writer);
  281. hLink.RenderEndTag (writer);
  282. }
  283. #if NET_2_0
  284. AdType adType;
  285. [DefaultValueAttribute ("Banner")]
  286. [WebCategoryAttribute ("Behavior")]
  287. [WebSysDescriptionAttribute ("Advertisement of specific type is created by specified value")]
  288. public AdType AdType {
  289. get { return adType; }
  290. set { adType = value; }
  291. }
  292. string alternateTextField;
  293. [DefaultValueAttribute ("AlternateText")]
  294. [WebCategoryAttribute ("Behavior")]
  295. [WebSysDescriptionAttribute ("Alternate text is retrieved from the elmenet name specified.")]
  296. //[VerificationAttribute ()]
  297. public string AlternateTextField {
  298. get { return alternateTextField; }
  299. set { alternateTextField = value; }
  300. }
  301. bool countClicks;
  302. [DefaultValueAttribute (false)]
  303. [WebCategoryAttribute ("Site Counters")]
  304. [WebSysDescriptionAttribute ("On clicking an advertisement, click-through events should be counted.")]
  305. public bool CountClicks {
  306. get { return countClicks; }
  307. set { countClicks = value; }
  308. }
  309. string counterGroup;
  310. [DefaultValueAttribute ("AdRotator")]
  311. [WebCategoryAttribute ("Site Counters")]
  312. [WebSysDescriptionAttribute ("Name of the group which takes care of counting.")]
  313. public string CounterGroup {
  314. get { return counterGroup; }
  315. set { counterGroup = value; }
  316. }
  317. string counterName;
  318. [DefaultValueAttribute ("")]
  319. [WebCategoryAttribute ("Site Counters")]
  320. [WebSysDescriptionAttribute ("Name of the group which takes care of counting.")]
  321. public string CounterName {
  322. get { return counterName; }
  323. set { counterName = value; }
  324. }
  325. bool countViews;
  326. [DefaultValueAttribute (false)]
  327. [WebCategoryAttribute ("Site Counters")]
  328. [WebSysDescriptionAttribute ("On creation of an advertisement, view events should be counted.")]
  329. public bool CountViews {
  330. get { return countViews; }
  331. set { countViews = value; }
  332. }
  333. string imageUrlField;
  334. [DefaultValueAttribute ("ImageUrl")]
  335. [WebCategoryAttribute ("Behavior")]
  336. [WebSysDescriptionAttribute ("Image URL is retrieved from the elmenet name specified.")]
  337. public string ImageUrlField {
  338. get { return imageUrlField; }
  339. set { imageUrlField = value; }
  340. }
  341. string navigateUrlField;
  342. [DefaultValueAttribute ("NavigateUrl")]
  343. [WebCategoryAttribute ("Behavior")]
  344. [WebSysDescriptionAttribute ("Advertisement Web page URL is retrieved from the elmenet name specified.")]
  345. public string NavigateUrlField {
  346. get { return navigateUrlField; }
  347. set { navigateUrlField = value; }
  348. }
  349. int popFrequency;
  350. [DefaultValueAttribute ("100")]
  351. [WebCategoryAttribute ("Behavior")]
  352. [WebSysDescriptionAttribute ("Frequency in percentage for creation of Popup or PopUnder advertisement.")]
  353. public int PopFrequency {
  354. get { return popFrequency; }
  355. set { popFrequency = value; }
  356. }
  357. int popPositionLeft;
  358. [DefaultValueAttribute ("-1")]
  359. [WebCategoryAttribute ("Appearance")]
  360. [WebSysDescriptionAttribute ("Specifies X-coordinate in pixels of Popunder or Popup advertisements top-left corner.")]
  361. public int PopPositionLeft {
  362. get { return popPositionLeft; }
  363. set { popPositionLeft = value; }
  364. }
  365. int popPositionTop;
  366. [DefaultValueAttribute ("-1")]
  367. [WebCategoryAttribute ("Appearance")]
  368. [WebSysDescriptionAttribute ("Specifies Y-coordinate in pixels of Popunder or Popup advertisements top-left corner.")]
  369. public int PopPositionTop {
  370. get { return popPositionTop; }
  371. set { popPositionTop = value; }
  372. }
  373. int rowsPerDay;
  374. [DefaultValueAttribute ("-1")]
  375. [WebCategoryAttribute ("Site Counters")]
  376. [WebSysDescriptionAttribute ("On a given day this many number of rows of data needs to be collected.")]
  377. public int RowsPerDay {
  378. get { return rowsPerDay; }
  379. set { rowsPerDay = value; }
  380. }
  381. string siteCountersProvider;
  382. [DefaultValueAttribute ("")]
  383. [WebCategoryAttribute ("Site Counters")]
  384. [WebSysDescriptionAttribute ("Control uses the specified provider.")]
  385. public string SiteCountersProvider {
  386. get { return siteCountersProvider; }
  387. set { siteCountersProvider = value; }
  388. }
  389. bool trackApplicationName;
  390. [DefaultValueAttribute (true)]
  391. [WebCategoryAttribute ("Site Counters")]
  392. [WebSysDescriptionAttribute ("SiteCounters service tracks and stores the specified application name in a database.")]
  393. public bool TrackApplicationName {
  394. get { return trackApplicationName; }
  395. set { trackApplicationName = value; }
  396. }
  397. bool trackNavigateUrl;
  398. [DefaultValueAttribute (true)]
  399. [WebCategoryAttribute ("Site Counters")]
  400. [WebSysDescriptionAttribute ("SiteCounters service tracks and stores the destination URL of click through event in a database.")]
  401. public bool TrackNavigateUrl {
  402. get { return trackNavigateUrl; }
  403. set { trackNavigateUrl = value; }
  404. }
  405. bool trackPageUrl;
  406. [DefaultValueAttribute (true)]
  407. [WebCategoryAttribute ("Site Counters")]
  408. [WebSysDescriptionAttribute ("SiteCounters service tracks and stores the originating page URL in a database.")]
  409. public bool TrackPageUrl {
  410. get { return trackPageUrl; }
  411. set { trackPageUrl = value; }
  412. }
  413. #endif
  414. class AdRecord
  415. {
  416. public IDictionary Properties;
  417. public int Hits; // or impressions or clicks
  418. public string Keyword;
  419. public AdRecord (IDictionary adProps)
  420. {
  421. this.Properties = adProps;
  422. Keyword = Properties ["Keyword"] as string;
  423. if (Keyword == null)
  424. Keyword = "";
  425. string imp = Properties ["Impressions"] as string;
  426. Hits = 1;
  427. if (imp != null) {
  428. try {
  429. Hits = Int32.Parse (imp);
  430. } catch {
  431. }
  432. }
  433. }
  434. }
  435. }
  436. }