Wednesday, September 30, 2009

Demo Parallel Extensions .NET 4.0

Yesterday I a gave a presentation/demonstration about the upcoming .NET 4.0 framework release. Unfortunately, there wasn't enough time to show the complete parallel demo. Here I show a couple of ways to display all integers between 0 and 100 that are dividable by 10.


class Program
{
// objects for classic parallel code
static object locker = new object();
static Queue<int> integers;
//with concurrent Queue, we don't need a locker
static ConcurrentQueue<int> concurrentIntegers;

static void Main(string[] args)
{
int steps = 100;
steps.WriteOnConsole(); //extension method to display an integer on the console
Classic(); //classic for loop, no parallel code
ClassicParallel(); //classic parallel invocation

New(steps); //parallel for loop
NewMoreLikeClassic(steps); //parallel the new way, but looks like classic parallel

Linq(steps); //old LINQ way
PLinq(steps); //new Parallel LINQ
}

private static void Classic(int steps = 100)
{
for (int i = 0; i < steps; i++)
{
if (i % 10 == 0)
{
i.WriteOnConsole();
}
}
}

private static void ClassicParallel(int steps = 100)
{
integers = new Queue<int>(steps);
// fill the queue with all integers
for (int i = 0; i < steps; i++)
{
integers.Enqueue(i);
}

int workerCount = 5; //arbitrary number for workercount.
Thread[] workers = new Thread[workerCount];
// Create and start a separate thread for each worker
for (int i = 0; i < workerCount; i++)
{
workers[i] = new Thread(Consume);//.Start();
}
foreach (Thread worker in workers)
{
worker.Start();
}
}

private static void Consume()
{
while (true)
{
int i;
lock (locker)
{
if (integers.Count == 0) return; // run until the queue is empty
i = integers.Dequeue();
}
if (i % 10 == 0)
{
i.WriteOnConsole();
}
}
}

private static void New(int steps)
{
ParallelLoopResult result = Parallel.For(0, steps, (i, loop) =>
{
if (i % 10 == 0)
{
i.WriteOnConsole();
}
//With the LoopState, we can break and terminate the processing of the loop
if (i == 50)
{
loop.Break();
}
}
);
Console.WriteLine("Completed: {0}, Breaked at iteration {1}",
result.IsCompleted,
result.LowestBreakIteration);
}

private static void NewMoreLikeClassic(int steps = 100)
{
concurrentIntegers = new ConcurrentQueue<int>(Enumerable.Range(0, steps));
Parallel.Invoke(() =>
{
ConsumeQueue();
}
);
}

private static void ConsumeQueue()
{
// note: there is no locking used here, because we use a ConcurrentQueue
int i;
bool success = concurrentIntegers.TryDequeue(out i);
if (success && (i % 10 == 0))
{
i.WriteOnConsole();
}
}

private static void Linq(int steps)
{
Enumerable.Range(0,steps).Where(i => i % 10 == 0)
.ToList<int>().ForEach(i=>i.WriteOnConsole());
}

private static void PLinq(int steps)
{
Enumerable.Range(0, steps).Where(i => i % 10 == 0).AsParallel()
.ToList<int>().ForEach(i => i.WriteOnConsole());
}
}

Wednesday, September 16, 2009

ASP.NET favicon.ico routing to deep link

After seeing some errors in my application log complaining about a non existing business object with id favicon.ico, and being sure that I had a <link href="/resources/images/favicon.ico" rel="shortcut icon" /> tag in my header section, I realized that old non-standard-compliant browsers do a request for the hard-coded /favicon.ico url. So I wanted to add a route in my route table to redirect these requests to the proper icon location. Unfortunately, there is no public StaticFileHandler available with a virtual path in its constructor, so I had to built them myself. The following couple of lines do the trick:

Registering the routes in the application startup:

routes.Add(new Route("favicon.ico", new StaticFileRouteHandler("~/Resources/images/favicon.ico")));
// generic, catch-all rule, caused the error for favicon.ico
routes.Add(Routes.BusinessObject, new Route(
string.Format("{{{0}}}", RouteParameters.BusinessObjectIdentifier),
new CustomRouteHandler("~/Pages/BusinessObjectDetails.aspx")));


The StaticFileRouteHandler to serve the the static file from the request.

public class StaticFileRouteHandler : IRouteHandler
{
public string VirtualPath { get; set; }
public StaticFileRouteHandler(string virtualPath)
{
VirtualPath = virtualPath;
}

#region IRouteHandler Members
public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
{
HttpContext.Current.RewritePath(VirtualPath);
return new DefaultHttpHandler();
}
#endregion
}

Wednesday, September 2, 2009

New VS2010 / .NET 4.0 features

I already love the new dynamic keyword in VS2010, and missing it in my day to day work with Tridion COM objects. Although the drawback is no IntelliSense in VS on the object, see the following code to get the item title from a Tridion TOM item:

Old code

object obj = tdse.GetObject(tcmUri, EnumOpenMode.OpenModeView, null, XMLReadFilter.XMLReadAll );
string title = null;
if (obj is Component)
{
Component component = (Component) obj;
title = component.Title;
}
if (obj is Folder)
{
Folder folder = (Folder) obj;
title = folder.Title;
}
if (obj is Page)
{
Page page = (Page) obj;
title = page.Title;
}


New code

dynamic tridionItem = tdse.GetObject(tcmUri, EnumOpenMode.OpenModeView);
string title = tridionItem.Title;


Another long-missing-but-finally-added feature is the support of optional COM Interop parameters in C#. Before 4.0, you needed to specify all optional parameters in Interop method calls, even if you wanted to use the default values, leading to extremely long method calls (maybe not in Tridion, but infamous in Office Interop with Type.Missing). These method parameters do now have the block parentheses around them in IntelliSense: