Home > .NET, ASP.NET, C#, Distribued Cache, Velocity > Velocity (CTP3) – DataCache.GetObjectsByAnyTag Method

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”
(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 3: key = “333″, content = “ccc”, tag = “a,b,c”
Item 3: key = “333″, content = “ccc”, tag = “a,b,c”
Item 2: key = “222″, content = “bbb”, tag = “b”

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”&gt;

<html xmlns=”http://www.w3.org/1999/xhtml&#8221; >

<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>&nbsp;</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>&nbsp;</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 = “&nbsp;”;

}

}

}

}

}

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.

ScreenShot001

This screenshot has 3 cache items.

ScreenShot002

This screenshot is search by AllTags <a>.

ScreenShot003

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

ScreenShot004

This screenshot is search by AnyTag <a>.

ScreenShot005

This screenshot is search by AnyTag <b>.

ScreenShot006

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

ScreenShot007

About these ads
  1. July 7, 2010 at 11:08 am

    Hi,
    I appreciate you for writing this article. Actually i am new to ASP.NET and Microsoft Velocity. This code helps me a lot. My application needs to cache a database(dataset). Actually i don’t know how to serialize a dataset and put in the cache and retrieve it. Any help will be appreciated more!!!

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: