Velocity (CTP3) – DataCache.GetObjectsByAnyTag Method
I was writing some code to experiment the Tag search in Velocity CTP3 and I found there is some small bug in one of the get objects by tag methods – DataCache.GetObjectsByAnyTag.
The definition of the method of DataCache.GetObjectsByAnyTag is:
Gets an enumerable list of all cached objects in the specified region that have any of the same tags in common.
For example I have 3 cache items:
Item 1: key = “111″, content = “aaa”, tag = “a”
Item 2: key = “222″, content = “bbb”, tag = “b”
Item 3: key = “333″, content = “ccc”, tag = “a,b,c”
Here are some scenarios:
(1) If I search with Tag “a” via DataCache.GetObjectsByAnyTag(<a>, “my_region”), I get:
Item 1: key = “111″, content = “aaa”, tag = “a”
Item 3: key = “333″, content = “ccc”, tag = “a,b,c”
(2) If I search with Tag “b” via DataCache.GetObjectsByAnyTag(<b>, “my_region”), I get:
Item 2: key = “222″, content = “bbb”, tag = “b”
Item 3: key = “333″, content = “ccc”, tag = “a,b,c”
(3) But if I search with Tags “a,b” via DataCache.GetObjectsByAnyTag(<a, b>, “my_region”), I get:
Item 1: key = “111″, content = “aaa”, tag = “a”
Item 2: key = “222″, content = “bbb”, tag = “b”
Item 3: key = “333″, content = “ccc”, tag = “a,b,c”
Item 3: key = “333″, content = “ccc”, tag = “a,b,c”
In scenario (3), the item 3 has been added twice because its tags are “a,b,c” and I search by <a,b> (Any Tag).
I believe this method - DataCache.GetObjectsByAnyTag - should check if the cache key is contained in the collection, if not, then add it to the collection – unless the velocity team want the developers do the checking of duplicated key in the caller program.
I will list my code and some screenshots.
The first file is CacheWorker.cs:
using System;
using Microsoft.Data.Caching;
namespace VelocityTest
{
public class CacheWorker
{
public const string DEFAULT_CACHE_REGION = “Default_Cache_Region”;
private static object _synclock = new object();
private static CacheWorker _cacheWorker = null;
private static DataCacheFactory _cacheFactory = null;
private static DataCache _defaultCache = null;
private static DataCache _eventCache = null;
private CacheWorker()
{
}
public static CacheWorker Instance
{
get
{
lock (_synclock)
{
try
{
if (_cacheWorker == null)
{
_cacheWorker = new CacheWorker();
// we use configuration file
_cacheFactory = new DataCacheFactory();
// default cache
_defaultCache = _cacheFactory.GetDefaultCache();
_defaultCache.RemoveRegion(DEFAULT_CACHE_REGION);
_defaultCache.CreateRegion(DEFAULT_CACHE_REGION, true);
// names cache
_eventCache = _cacheFactory.GetCache(“Event2″);
}
return _cacheWorker;
}
catch (DataCacheException ex)
{
return null;
}
}
}
}
public DataCacheFactory CacheFactory
{
get { return _cacheFactory; }
}
public DataCache DefaultCache
{
get { return _defaultCache; }
}
public DataCache EventCache
{
get { return _eventCache; }
}
public DataCacheItemVersion AddCache(string key, object value, TimeSpan? timeout)
{
DataCacheItemVersion version = null;
if (timeout.HasValue)
{
version = _defaultCache.Put(key, value, timeout.Value);
}
else
{
version = _defaultCache.Put(key, value);
}
return version;
}
}
}
The second file is Default3.aspx page:
<%@ Page Language=”C#” AutoEventWireup=”true” CodeBehind=”Default3.aspx.cs” Inherits=”VelocityTest.Default3″ %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
<title>Velocity – Tag Example</title>
</head>
<body>
<form id=”form1″ runat=”server”>
<p>
<h3>Velocity – Tag Example</h3>
<table border=”0″ cellpadding=”2″>
<tr>
<td><b>Cache Key</b></td>
<td>
<asp:TextBox ID=”txtCacheKey” runat=”server” />
<asp:RequiredFieldValidator ID=”vadCacheKey” runat=”server” ControlToValidate=”txtCacheKey” ErrorMessage=”* required” Display=”Dynamic” />
</td>
</tr>
<tr>
<td><b>Cache Content</b></td>
<td>
<asp:TextBox ID=”txtCacheContent” runat=”server” />
<asp:RequiredFieldValidator ID=”vadCacheContent” runat=”server” ControlToValidate=”txtCacheContent” ErrorMessage=”* required” Display=”Dynamic” />
</td>
</tr>
<tr>
<td><b>Cache Tags</b></td>
<td><asp:TextBox ID=”txtCacheTag” runat=”server” />(Tags are seperated by comma)</td>
</tr>
<tr>
<td> </td>
<td>
<asp:Button ID=”btnCancel” runat=”server” Text=”Cancel” CausesValidation=”false” />
<asp:Button ID=”btnSave” runat=”server” Text=”Save” />
</td>
</tr>
</table>
</p>
<hr />
<p>
<table border=”0″ cellpadding=”2″>
<tr>
<td><b>Search Method:</b></td>
<td>
<asp:RadioButtonList ID=”radSearchMethodList” runat=”server” RepeatDirection=”Horizontal”>
<asp:ListItem Text=”No Tag” Value=”NoTag” />
<asp:ListItem Text=”All Tags” Value=”AllTags” />
<asp:ListItem Text=”Any Tag” Value=”AnyTag” />
<asp:ListItem Text=”One Tag” Value=”OneTag” />
</asp:RadioButtonList>
</td>
</tr>
<tr>
<td><b>Search Tags:</b></td>
<td><asp:TextBox ID=”txtSearchTag” runat=”server” />(Tags are seperated by comma)</td>
</tr>
<tr>
<td> </td>
<td>
<asp:Button ID=”btnClearSearch” runat=”server” Text=”Clear” CausesValidation=”false” />
<asp:Button ID=”btnSearch” runat=”server” Text=”Search” CausesValidation=”false” />
</td>
</tr>
</table>
</p>
<hr />
<p>
<asp:GridView ID=”gvCache” runat=”server”
AutoGenerateColumns=”false”
EmptyDataText=”No cache data”>
<Columns>
<asp:TemplateField HeaderText=”Key” ShowHeader=”true”>
<ItemTemplate>
<asp:Label ID=”lblCacheKey” runat=”server” />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText=”Content” ShowHeader=”true”>
<ItemTemplate>
<asp:Label ID=”lblCacheContent” runat=”server” />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText=”Tags” ShowHeader=”true”>
<ItemTemplate>
<asp:Label ID=”lblCacheTag” runat=”server” />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</p>
</form>
</body>
</html>
The third file is Default3.aspx.cs code-behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using Microsoft.Data.Caching;
namespace VelocityTest
{
[Serializable]
public class MyCacheItem
{
public string Key { get; set; }
public string Content { get; set; }
public List<DataCacheTag> Tags { get; set; }
public MyCacheItem(string key, string conent)
{
Key = key;
Content = conent;
Tags = new List<DataCacheTag>();
}
public MyCacheItem(string key, string conent, string[] tags)
{
Key = key;
Content = conent;
Tags = new List<DataCacheTag>();
foreach (string tag in tags)
{
Tags.Add(new DataCacheTag(tag));
}
}
public string[] GetTags()
{
string[] tags = null;
if (Tags != null && Tags.Count > 0)
{
tags = new string[Tags.Count];
int i = 0;
foreach (DataCacheTag tag in Tags)
{
tags[i++] = tag.ToString();
}
}
return tags;
}
}
public enum TagSearchMethod
{
NoTag,
AllTags,
AnyTag,
OneTag
}
public partial class Default3 : System.Web.UI.Page
{
protected const string DEFAULT_DELIMITER = “,”;
protected DataCacheFactory _factory = CacheWorker.Instance.CacheFactory;
protected DataCache _cache = CacheWorker.Instance.DefaultCache;
protected void Page_Load(object sender, EventArgs e)
{
btnSave.Click += new EventHandler(btnSave_Click);
btnCancel.Click += new EventHandler(btnCancel_Click);
btnClearSearch.Click += new EventHandler(btnClearSearch_Click);
btnSearch.Click += new EventHandler(btnSearch_Click);
gvCache.RowDataBound += new GridViewRowEventHandler(gvCache_RowDataBound);
gvCache.DataSource = GetCacheDataSource(TagSearchMethod.NoTag, null);
gvCache.DataBind();
}
protected List<MyCacheItem> GetCacheDataSource(TagSearchMethod method, List<DataCacheTag> tags)
{
List<MyCacheItem> items = new List<MyCacheItem>();
IEnumerable<KeyValuePair<string, Object>> cachePairs = null;
if (method == TagSearchMethod.NoTag)
{
cachePairs = _cache.GetObjectsInRegion(CacheWorker.DEFAULT_CACHE_REGION);
}
else if (method == TagSearchMethod.AllTags)
{
cachePairs = _cache.GetObjectsByAllTags(tags, CacheWorker.DEFAULT_CACHE_REGION);
}
else if (method == TagSearchMethod.AnyTag)
{
cachePairs = _cache.GetObjectsByAnyTag(tags, CacheWorker.DEFAULT_CACHE_REGION);
}
else if (method == TagSearchMethod.OneTag)
{
cachePairs = _cache.GetObjectsByTag(tags[0], CacheWorker.DEFAULT_CACHE_REGION);
}
if (cachePairs != null)
{
foreach (KeyValuePair<string, object> item in cachePairs)
{
items.Add((MyCacheItem)item.Value);
}
}
return items;
}
protected void gvCache_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
MyCacheItem data = e.Row.DataItem as MyCacheItem;
if (data != null)
{
Label lblCacheKey = e.Row.FindControl(“lblCacheKey”) as Label;
if (lblCacheKey != null)
{
lblCacheKey.Text = data.Key;
}
Label lblCacheContent = e.Row.FindControl(“lblCacheContent”) as Label;
if (lblCacheContent != null)
{
lblCacheContent.Text = data.Content;
}
Label lblCacheTag = e.Row.FindControl(“lblCacheTag”) as Label;
if (lblCacheTag != null)
{
if (data.Tags != null)
{
lblCacheTag.Text = String.Join(“,”, data.GetTags());
}
else
{
lblCacheTag.Text = “ ”;
}
}
}
}
}
protected void btnSearch_Click(object sender, EventArgs e)
{
if (radSearchMethodList.SelectedItem != null)
{
TagSearchMethod method = (TagSearchMethod)Enum.Parse(typeof(TagSearchMethod), radSearchMethodList.SelectedValue);
List<DataCacheTag> tags = GetTags(txtSearchTag.Text.Trim());
gvCache.DataSource = GetCacheDataSource(method, tags);
}
else
{
gvCache.DataSource = GetCacheDataSource(TagSearchMethod.NoTag, null);
}
gvCache.DataBind();
}
protected void btnClearSearch_Click(object sender, EventArgs e)
{
Response.Redirect(Request.RawUrl);
}
protected void btnCancel_Click(object sender, EventArgs e)
{
Response.Redirect(Request.RawUrl);
}
protected void btnSave_Click(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(txtCacheKey.Text.Trim()) &&
!String.IsNullOrEmpty(txtCacheContent.Text.Trim()))
{
MyCacheItem item = null;
string[] tags = null;
if (!String.IsNullOrEmpty(txtCacheTag.Text.Trim()))
{
tags = (string[])txtCacheTag.Text.Trim().Split(DEFAULT_DELIMITER.ToCharArray());
}
if (tags != null && tags.Length > 0)
{
item = new MyCacheItem(txtCacheKey.Text.Trim(), txtCacheContent.Text.Trim(), tags);
}
else
{
item = new MyCacheItem(txtCacheKey.Text.Trim(), txtCacheContent.Text.Trim());
}
_cache.Put(item.Key, item, item.Tags, CacheWorker.DEFAULT_CACHE_REGION);
}
gvCache.DataSource = GetCacheDataSource(TagSearchMethod.NoTag, null);
gvCache.DataBind();
}
protected List<DataCacheTag> GetTags(string tagString)
{
List<DataCacheTag> tags = new List<DataCacheTag>();
string[] items = tagString.Split(DEFAULT_DELIMITER.ToCharArray());
foreach (string item in items)
{
tags.Add(new DataCacheTag(item));
}
return tags;
}
}
}
The following are screenshots.
This screenshot has nothing is cache.

This screenshot has 3 cache items.

This screenshot is search by AllTags <a>.

This screenshot is search by AllTags <a, b>.

This screenshot is search by AnyTag <a>.

This screenshot is search by AnyTag <b>.

This screenshot is search by Tag <a, b> – there are 4 cache items!

No comments yet
Leave a reply