Friday, September 26, 2008

CacheItemRemovedCallback and asynchronous programming model for ASP.NET Cache

ASP.NET has a very good asynchronous programming model that uses the CacheItemRemovedCallback delegate to inform the application when a cache item is expired and helps the developer to write code to retrieve it.

The CacheItemRemovedCallback is defined as
public delegate void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason);

To explain the concept I will use the following classes which have a parent – child relationship.

public class User

{

public Int32 ID { get; set; }

public String Name { get; set; }

}

public class Details

{

public User User { get; set; }

public Int32 Extension { get; set; }

public String Project { get; set; }

}

You can instantiate and initialize the objects in your code like

User parent = new User { Name = "Me", ID = 1 };

Details child = new Details {User = parent, Project = "My Project", Extension = 555 };

And later when adding the objects into Cache you create the dependencies and the callback function reference for the child data as follows.

Insert parent object and create CacheDependency.

Cache.Insert("Parent", parent);

CacheDependency dependency = new CacheDependency(null, new String[] { " Parent" });


Insert child object and add a CacheItemRemovedCallback delegate.

Cache.Insert(

"Child",

child,

dependency,

DateTime.Now.AddHours(30),

TimeSpan.Zero,

CacheItemPriority.Normal,

new CacheItemRemovedCallback(

delegate(String key, Object value, CacheItemRemovedReason reason)

{

if(reason == CacheItemRemovedReason.DependencyChanged)

//Use AJAX/ events here if required.

Cache.Insert(key, new Details { User = null, Extension = default(Int32), Project = String.Empty });

})

);

Now whenever the parent object is removed from the cache the anonymous method gets called and you can do an appropriate action based on the design.

CodeDOM helper methods

The CodeDOM provides types that represent many common types of source code elements. You can design a program that builds a source code model using CodeDOM elements to assemble an object graph. This object graph can be rendered as source code using a CodeDOM code generator for a supported programming language. The CodeDOM can also be used to compile source code into a binary assembly.

This article contains some helper methods you can use to create a class using CodeDOM.

Creating a namespace

private CodeNamespace CreateNameSpace(String name)

{

CodeNamespace CurrentNameSpace = new CodeNamespace(name);

CurrentNameSpace.Imports.Add(new CodeNamespaceImport("System"));

CurrentNameSpace.Imports.Add(new CodeNamespaceImport("System.Text"));

CurrentNameSpace.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));

CurrentNameSpace.Imports.Add(new CodeNamespaceImport("System.IO"));

CurrentNameSpace.Imports.Add(new CodeNamespaceImport("System.Collections.Specialized"));

CurrentNameSpace.Imports.Add(new CodeNamespaceImport("System.Collections.ObjectModel"));

return CurrentNameSpace;

}

Or

private CodeNamespace CreateNameSpace(String name, CodeNamespaceImport[] imports)

{

CodeNamespace CurrentNameSpace = new CodeNamespace(name);

CurrentNameSpace.Imports.AddRange(imports);

return CurrentNameSpace;

}

Creating a class

private CodeTypeDeclaration CreateClass(String className)

{

CodeTypeDeclaration ctd = new CodeTypeDeclaration(className);

ctd.IsClass = true;

ctd.Attributes = MemberAttributes.Public;

return ctd;

}

Creating class variables

private CodeMemberField CreateClassVariable(System.Type type, String name)

{

CodeMemberField classVariable = new CodeMemberField(type, name);

classVariable.Attributes = MemberAttributes.Private;

return classVariable;

}

Create Properties

private CodeMemberProperty CreateClassProperty(Boolean isReadOnly, String name, Type type, String variableName)

{

CodeMemberProperty property = new CodeMemberProperty();

property.Name = name;

property.Type = new CodeTypeReference(type);

property.Attributes = MemberAttributes.Public;

property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), variableName)));

if(!isReadOnly)

property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), variableName), new CodePropertySetValueReferenceExpression()));

return property;

}

Creating methods

private CodeMemberMethod CreateMethod(String methodName, CodeTypeReference returnType, CodeParameterDeclarationExpressionCollection methodParams, MemberAttributes accessModifier)

{

CodeMemberMethod method = new CodeMemberMethod();

method.Name = methodName;

method.ReturnType = returnType;

method.Parameters.AddRange(methodParams);

method.Attributes = accessModifier;

return method;

}

Tuesday, September 9, 2008

ThreadStatic Attribute

The [ThreadStatic]attribute indicates that the variable has one instance for each thread. This is a variation of the static variables. Static variables have one instance throughout the lifecycle of the program. A variable marked with [ThreadStatic]has one instance per thread in the program.

See the example for more details.
class Program
{
public static Int32 singleton = 0;
[ThreadStatic]
public static Int32 threadSingleton = 0;
static void Main(string[] args)
{
Program executingProgram = new Program();
Thread firstThread = new Thread(new ThreadStart(executingProgram.FirstThread));
Thread secondThread = new Thread(new ThreadStart(executingProgram.SecondThread));
firstThread.Start();
firstThread.Join();
secondThread.Start();
firstThread.Join();
Console.Read();
}

public void FirstThread()
{
singleton++;
threadSingleton++;
Console.WriteLine("Singleton = {0} ThreadSingleton = {1}", singleton.ToString(), threadSingleton.ToString());
}

public void SecondThread()
{
singleton++;
threadSingleton++;
Console.WriteLine("Singleton = {0} ThreadSingleton = {1}", singleton.ToString(), threadSingleton.ToString());
}
}

Output
Singleton = 1 ThreadSingleton = 1
Singleton = 2 ThreadSingleton = 1