Scott Hanselman

Ultimate Developer PC 2.0 - Part 2 - UPDATE and PODCAST on Building a WEI 7.9 and RFC for building a GOM (God's Own Machine)

July 14, 2010 Comment on this post [76] Posted in Hardware | Podcast
Sponsored By

Big Ass Mobo As a reminder, if you're just turning in, here's our glossary:

  • WEI - Windows Experience Index. How fast is your machine? If you say "I've got a WEI 6.0" you've got a good machine, for example.
  • RFC - Request for Comments. This is crowdsourcing. I want to know what YOU think we need to do to make a machine that is so fast that it'll max out at WEI 7.9 and be a GOM.
  • GOM - God's Own Machine. If the Good Lord had a computer, it'd be a 7.9. We want to build that machine.

There were lots of great comments in the original post. Here's some of my answers to those comments, as well as some on Twitter. The fun thing about doing hardware builds is that EVERYONE has an opinion. Also, since I'm a software guy (although I could totally rock a 486-SX build) your opinion, Dear Reader, is better than mine. I can only explain why I (and Pete, who is doing a similar build with me) made certain decisions.

We hosted a great podcast last week with some actual members of the WEI team and asked their ideas on how we could create the Ultimate Developer PC. You can listen to Hanselminutes Podcast 220 on "Creating the Ultimate Developer Machine 2.0 - How can we get a 7.9 WEI Score for under $3k?" here.

This I Believe - Hardware Edition

There's some guiding principles for this build.

  • We aren't trying to build the Ultimate PC. We don't have 20 grand or whatever the super PC is today.
  • We aren't trying to build the Ultimate Gamer PC
  • We don't want a divorce. We have a budget and we've been saving for 2 years, but give or take a few hundred dollars we can hide in tacos, we've got $3k.
  • We do have some existing parts. I've already got good monitors, as you might as well. I've got a decent case, keyboard and mouse. These don't count. Maybe the case, but you get the idea.
  • If we can stretch JUST a smidge and get a better piece of hardware for a few more bucks, or if we feel that if we DON'T get a certain level of hardware that we'll be sad, we'll go for it. Within reason.
  • We aren't AnandTech and don't claim to be.
  • We value multi-tasking as we do a lot of stuff a the same time. We think more cores is a good thing and you can't have enough memory.
  • Sometimes folks who write hardware websites talk perf, but it's unclear what they are actually DOING with these PCs, other than using them to run benchmarks. We are doing these things:
    • Communicating - Email, Twitter, Skype, Messenger, Communicator all running at the same time.
    • Coding - Multiple instances of VS2010, HippoEdit, e, IIS7, etc.
    • Virtual Machines - I usually have at least one VM doing, sometimes peaking at 2 or 3.
    • Writing - Live Writer, Excel, Word
    • Browsing - Chrome uses like 20-30 chrome.exe processes and thing slow down when Flash is involved.
    • Media - Usually running Zune or iTunes in the background. Sometimes a pinned video or Hulu on another monitor.
    • Gaming - Nope. Zip. I have an XBox, Wii and PS3 for that. And a Vectrex.

The Purchase

So here's what I purchased and what I was thinking when I did it.

  • $965 Intel Core i7-980X Extreme Edition 3.33GHz LGA 1366 130W Six-Core Desktop Processor
    • I thought about an overclocked P4, but I REALLY wanted an i series and I really wanted a hexacore and something overclockable to 4GHz without being an expert overclocker. Compile times need GHz and multitasking needs multiple cores so even though it's a grand for a processor, I feel good about it. It is the brain.
  • $699 (with combo actually $480) GIGABYTE GA-X58A-UD9 ATX Intel Motherboard
    • This was the UD7 before, but when I was on NewEgg they had a deal when purchased with memory that took $219 off it, so it was $699-$219 = $480 for the UD9 vs. the $339 UD7. The extra $140 seemed worth it for such an exceptional motherboard. It's a very flexible board, does 6-core and does SATA 6Gbit/s. It's an Intel X58 chipset, and has seven PCIe 2.0 x16 slots. I HATE running out of room. There's also enough space for dual slot graphics cards. I have four monitors (although I'm starting by running just two in this config) and I need the elbow room. It's also got two gigabit LAN, USB 3.0, and two eSATA as well. It supports 24GB of RAM which is nice breathing room, given I'll start at 12GB.
  • $374 OCZ Reaper Edition 12GB (3 x 4GB) 240-Pin DDR3 SDRAM DDR3 1333 (PC3 10666) Low Voltage Desktop Memory
    • Buttloads of RAM. Actually, I'd have preferred 16, as 12 just FEELS a little small. I have 8 now. Good news is, I can double this in a year or so when funds allow.
  • $320 NVidia GTX 470
    • Video cards are like Religions. The only thing that they all have in common is that you think YOURS is the One True Way. Why did I pick this one? I'm religious. No other reason. Why not eat Pork? It's a filthy animal, right? Of course not. But still. You never know! Why not buy ATI? They blue screened me ONE too many times years ago and I just can't do it. They're a filthy beast!
      Now, in fairness, read that paragraph again and swap ATI and NVidia. It works both ways.
      I like NVidia. You may think this is a gamer card, but it really came down to this. I want my Windows, and my (soon to be) hardware accelerated browsers to as well.
    • UPDATE: David in the comments said that I contradicted myself with my religious rant. To the numbers. This card gets me 7.9. I like NVidia. It'll run two 30" monitors no problem. Two of them will run four. It's in my budget and it's the Top NVidia card that'll push the pixels I want. That's why I picked it.
  • $610 Crucial RealSSD C300 CTFDDAC256MAG-1G1 2.5" MLC Internal Solid State Drive (SSD)
    • This was a hard one. Folks were suggesting "get a small C: drive" and a large spinning-rust drive for data. I have 2 TB of storage on a Windows Home Server and lots of External Drives around, so let's just say D: drive space is a non-issue. However, I can't abide a 64gig or 128gig C: drive. It's insane. There's no room. This is a great drive, a good balance between size and speed. It'll probably get a 7.7-7.8 WEI, but I really think that RAID 0 array of two drives is overkill. It also seems like I'd be asking for a drive failure. This was a good balance of price and performance. I need to update the firmware before building.
  • $200 SILVERSTONE ST1000-P 1000W Power Supply
    • A number of people thought this was overkill. Fortunately, I can always swap it out or return it if it was a bad idea. That said, when I add in another video card for the other two monitors, as well as a harddrive or three, I'm going to want the extra headroom.

I have likely (and will likely) make mistakes here, but that's part of the fun of building your own machine. Remember, Jedis build their own lightsabers, so you should build your own computer at least one!

I'll be building this in the next week or two.

QUESTION: Is there any interest in a "live build" where we stream the build and the viewers make suggestions, ask questions, etc?

Your thoughts?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Microsoft WebMatrix in Context and Deploying Your First Site

July 07, 2010 Comment on this post [30] Posted in ASP.NET | ASP.NET MVC | IIS | Learning .NET | WebMatrix
Sponsored By

 ScottGu announced Microsoft WebMatrix Beta today.

  • WebMatrix Starting PageIt's a small (15 megs if you have .NET 4, 50megs if you don't) lightweight IDE for making ASP.NET or PHP websites.
  • It has a small embedded file-based SQL Database, and a web-server called IIS Express that's compatible with the full version of IIS.
  • It uses a View Engine called "Razor" to make Web Pages, and your sites can be later be expanded to use all of ASP.NET MVC. It's a simple syntax that is easy to learn
  • It uses the WebDeploy engine to deploy apps to hosts, setting up permissions, copying databases, etc.
  • WebMatrix also has the Search Engine Optimization Toolkit built in, so you can spider your own site and see how Search Engines see it. It'll make recommendations and store reports.

I've said before that Microsoft is just now starting to get the "right-sized LEGO pieces." It the past some stuff was too little or too big, but now as an example, here's five separate and right-sized LEGOs (ya, I know it's singular) that are helpful for the professional and the folks just getting starter, or those who don't want to learn a bunch of stuff to setup and/or modify a website.

Visual Studio 2010 looks like a dashboard. It's big and powerful and overwhelming. I tried to get my wife, then later my 10 year old nephew to make a website and it was a non-starter. It worked later with WebMatrix. This isn't for professionals, even though it has components that professionals will use. Pros will like a free file-based SQL Server, and a non-service version of IIS that's more compatible than the Visual Web Developer, and pros might like using Razor as an alternative View Engine for their ASP.NET MVC sites.

However, folks that are starting out, or hobbyists, or maybe just installing a blog or forum will use WebMatrix to get stuff done.

Download and Install Matrix

Here's how you'd get WebMatrix, sign up for a new host, and deploy your first site.

Go to the WebMatrix site and click Download Now. It'll install the Web Platform Install (about 2 megs) and then you click Install. The WebMatrix download for me was 8megs, then SQL Compact was 2.5megs, and then some deployment dependencies brought my total download to 29 megs.

Run and Select a Site

You can install a site from the Gallery, like ScottGu did when he chose BlogEngine.NET. These are regular ASP.NET and PHP apps that you've probably used before. There's lots of Open Source apps like Blogs (like DasBlog, that runs this site!), Content Management Systems (like Umbraco, that powers http://asp.net!) and other apps that you can start working with immediately.

However, since we're learning, my wife and I are going to select Site from Template and pick the Bakery App. This is a basic store-type application that we can deploy in just a few minutes. We don't need to look at code if we don't want to.

WebMatrix Site from Template

Hit OK and I'm in WebMatrix looking a new screen.

image

At this point I can click Run to see my app.

image

It's running locally on IIS Express along with some others Apps I was looking at earlier. This is effectively FULL IIS (not Visual Web Developer) but installed as a User App...when I stop the app, it's gone. It's not an auto-startup service, but it is IIS, which means your apps will run the same locally as they do deployed.

image

I can run it locally, but how do I get it up to a host?

Deploying My App to a Host

Things usually get complicated when you go to deploy and app. It's pretty easy to get an application running locally, but it's sometimes a challenge to get that app up on a site. People can sign up for a Gmail or Hotmail account and get that running, so why can't they get a website up that they coded themselves?

I've blogged about WebDeployment before and shown examples in my Mix Video "If you're using XCopy you're doing it wrong." WebDeploy is part of WebMatrix also.

I'll click on Publish and "Find Web Hosting" and I get a list of hosts I can choose from. I'll select Applied Innovations and click Learn More. I do prefer hosts like AdHost that give you both a .NET 2 and .NET 4 Application Pools to work in, which means I can use apps from the Gallery and apps that use the new Razor Syntax at the same time.

I go to Applied Innovations, and fill out the form. I'll get free hosting until next year with 1 GB of Disk Space and 100 GB monthly transfer. I get .NET 3.5 and 4, but also PHP. I can use SQL Compact, but also mySQL.

I fill out a form -  no credit card needed - and they send me an email. Click a link and they send me back an email with all the details I need. This is the same experience you'll get with all the hosters.

My Opinion: Some hosts make you switch your AppPools between .NET 2 and .NET 4 and that's too hard for beginners, I think. Hopefully all the hosters will remove this step and offer two app pools, or make switching between them a top level button in their Control Panels. AdHost does this. I hope others will also.

To switch to .NET 4, go to the Control Panel URL in your welcome email. Click WebSites, Extensions and select ASP.NET 4 from the dropdown.

Control Panel

Other hosts to choose from during this Beta are:

I fill out the Publish Form in WebMatrix with the details direct from my new host.

Publishing

Notice I don't need to do anything special for my database, as it's a file-based SQL database, runs in Medium Trust and requires no configuration.

Click Publish, and I'll get a list of files that'll be copied up. This is a differential copy, so if you change one file later, only that file will go up. Be sure to click the checkbox to deploy your database.

Publishing Preview

The publish happens in the background...

Publish Progress Bar

Then it completes, and I can now visit my new Bakery site online at my host, AppliedI:

image

Of course, if I wanted to, I could change the site, maybe modify the Products page:

@{
LayoutPage = "~/_Layout.cshtml";
PageData["Title"] = "Product";

var db = Database.Open("bakery");
}

<h2>Available Products:</h2>
<div class="products group">
@foreach (var p in db.Query("SELECT * FROM PRODUCTS")) {
<div class="product">
<h3>@p.Name</h3>
<img src="@Href("~/Images/"+ p.ImageName)" alt="@p.Name"/>
<p>@p.Description</p>
<ul class="group">
<li class="price">$@string.Format("{0:f}", p.Price)</li>
<li class="order">
<form action="Order" method="post">
<input type="hidden" name="ProductId" value="@p.Id"/>
<input type="submit" value="Order Now"/>
</form>
</li>
<ul>
</div>
}
</div>

There's lots of nice helpers for Google Analytics and Twitter integration:

<div class="sidebar">
@Twitter.Search("#bakery", caption: "#bakery")
</div>
I could of course, also edit my data:

Database Editing in WebMatrix

All in a reasonably not scary-dashboard looking UI. It's all ASP.NET underneath, so I can graduate to ASP.NET MVC and move my logic into controllers, and I've already got Views written in the "Razor" syntax, which is the new default for ASP.NET MVC 3.

Context

If you're reading this blog, and you're not my Wife, this tool probably isn't for you. (Hi, wife.)

However, the pieces that make up WebMatrix probably are. SQL Compact is pretty sweet. It's small, free, file-based and easy to upgrade to SQL Express Big Boys and Girls Edition. The new Razor syntax is a nice alternative to the WebForms Syntax (as are other alternative ViewEngines). IIS Express is hotness, especially if you've ever had an app that acted differently on IIS than on Visual Web Developer.

If you are learning web development or just want to get a site up, check out WebMatrix. Even if you don't edit the code, you can get and deploy and app to a host quickly, be it an ASP.NET app or a PHP app. If you do choose to write an app yourself, you can get started with WebMatrix and then move to Visual Studio (Free Express or $ Pro) if you outgrow it.

I'll report back and see what the WAF (Wife Acceptance Factor) is on WebMatrix.

Related Links

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Removing Dead Tracks (Duplicates that don't exist) from iTunes using C#

July 04, 2010 Comment on this post [36] Posted in Source Code | Tools
Sponsored By

image I hate iTunes on Windows with the heat of a thousand suns. It is a pox on my existence and it has cost me hours of pain and suffering. I'm sure it's all unicorns and spun sugar on MAC, but as a guy using Windows with dozens of gigabytes of music on a shared file server that I've ripped since the first CD I ever purchased, it's hell on earth. I could manage all my music with Zune (and I do have a Zune Pass for leasing music I don't want to buy) but there are iDevices in the house and iTunes is what it takes.

Did I mention it sucks? It's slow, frustrating, and is effectively just a giant listbox that exists only to mess up my music library and occasionally try to sneak Safari and QuickTime onto my machines. But enough about Satan, let's yank some dead tracks, shall we?

At some point, I ended up with hundreds of dead tracks and/or duplicates. I ended up with "LL Cool J - I Need Love 1.mp3" and "LL Cool J - I Need Love 2.mp3" along side the original. It was taking up many gigs of duplicate space. I searched for *1.mp3 and *2.mp3, etc, and deleted the dupes on disk.

However, this then left me with a big iTunes database that THINKS it has music, even though the file on disk is long gone. Now, as a napalm-style solution, you CAN delete your iTunes library completely and re-add it. It'll add just files that exist, but you will lose any edits, artwork, etc, you may have added. This solution wasn't cool for me so I say, nay nay.

There's a MILLION stupid little shareware apps that purport to fix duplicates and remove dead tracks. In my case, removing dupes was easy, but yanking dead tracks isn't worth me spending money.

Instead, I sat down tonight and decided to write a script in C# that said something like "foreach track, does that track exist where the system thinks it should be? No? Delete it."

A little googling with Bing, however, brought me to a three year old post at ScarTech where Shawn (shame he's stopped blogging) did the code for me! Yay. Here's a bit of his code, using the iTunes COM SDK. His stuff was written using Visual Studio Express 2008, but I upgraded to 2010. Also, I'm on 64-bit and his COM code expects x86, so I changed the project properties from AnyCPU to x86 and it worked great.

//create a reference to iTunes
iTunesAppClass iTunes = new iTunesAppClass();
//get a reference to the collection of all tracks
IITTrackCollection tracks = iTunes.LibraryPlaylist.Tracks;
for (int i = trackCount; i > 0; i–)
{
IITTrack track = tracks[i];
if (track.Kind == ITTrackKind.ITTrackKindFile)
{
IITFileOrCDTrack fileTrack = (IITFileOrCDTrack)track;
//if the file doesn’t exist, we’ll delete it from iTunes
if (fileTrack.Location == String.Empty || !System.IO.File.Exists(fileTrack.Location))
{
fileTrack.Delete();
}
}
}

Here's before:

1

So I ran it...

iTunes COM Sample Screenshot 

...and here's the afterparty:

image

Looks like it checked 7219 tracks and removed 570 dead ones. Yum.

I'd also encourage you to check out the second part of Shawn's iTunes and C# tutorial series where he creates a duplicate finder that knows to keep the higher bitrate song.

You can download Shawn's code here but as he hasn't blogged in a LONG time, I've mirrored it at SkyDrive. Big thanks to Shawn at ScarTech for saving me my evening and for tidying up my iTunes.

Good stuff, the internets.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

The Weekly Source Code 54 - Can't have Multiple Attributes of the Same Type when using a TypeDescriptor

July 03, 2010 Comment on this post [5] Posted in ASP.NET Dynamic Data | Source Code
Sponsored By

When I was in a China a few weeks back, I had a nice chat with a fellow named Zhe Wang who was using ASP.NET Dynamic Data to create a website. He made his own Custom Attribute to apply to his entities and effectively made an authorization scheme so that certain users could access some actions but not others.

In this little example, EntityAuthorize is Zhe's own custom attribute with a few properties.

namespace MyModels.Metadata
{
[EntityAuthorize(Roles="Administrators", AllowedEntityActions=EntityActions.List | EntityActions.Edit)]
[EntityAuthorize(Users="Administrator", DeniedEntityActions=EntityActions.Edit)]
public partial class SurveyMetaData
{
string Address { get; set; }
string Content { get; set; }
string Something { get; set; }
EntityCollection<OtherStuff> OtherThings { get; set; }
}
}

In this example, he's got two attributes stacked up on the same class. There's nothing wrong with this, by the way.

Later on, when it came time to fetch these attributes and take action on them, something weird happened. He was only getting one of the attributes when he fetched them via MetaTable.Attributes.OfType<T>() which is the usual way in Dynamic Data. In frustration he tried to get them using GetCustomAttributes which is slow and not much fun. Here's his clever hack (note: this won't be needed as we'll solve this another way).

public static bool FilterVisible(this MetaTable table, EntityActions action)
{
var usn = HttpContext.Current.User.Identity.Name;
var roles = Roles.GetRolesForUser(usn);
var attrs = table.Attributes.OfType<EntityAuthorizeAttribute>()
.Where
(
//try to get the attributes we need using the DynamicData metatable,
// but we're only getting one of the attributes of this type.
).Union
(
//get it ourselves the slow way using GetCustomAttributes and it works.
table.Attributes.OfType<MetadataTypeAttribute>()
.Select(t => Attribute.GetCustomAttributes(t.MetadataClassType))
.SelectMany(col => col).OfType<EntityAuthorizeAttribute>()
);

var allow = attrs.Any(a => a.AllowedEntityActions.HasFlag(action));

var deny = attrs.Any(a => a.DeniedEntityActions.HasFlag(action));

return allow && (!deny);
}

How does MetaTable.Attributes get populated? Via the a standard System.ComponentModel.TypeDescriptor provider that does all the work of getting the attributes, merging them together and putting them in a collection. However, the TypeDescriptor is kind of goofy in this case due to a weird behavior deep in the system.

Here's a little reproduction application to show the behavior where the TypeDescriptor fails to get both attributes. The TypeDescriptor API has some subtle differences with the standard reflection API.

class Program {
static void Main(string[] args) {
var prop = TypeDescriptor.GetProperties(typeof(Product))["Num"];
foreach (Attribute attrib in prop.Attributes) {
Console.WriteLine(attrib.GetType());
}
}
}

public class Product {
[TestPermission("foo1", "bar1")]
[TestPermission("foo2", "bar2")]
public int Num { get; set; }
}

[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class TestPermissionAttribute : Attribute {
public TestPermissionAttribute(string role, string user) { }
}

Notice the explicit AllowMultiple = true in the AttributeUsage attribute. However, deep in Attribute (yes, System.Attribute) there's a virtual property called TypeID and the value of that property becomes a key in the hashtable that the TypeDescriptor uses to remove duplicates. Inside of Attribute, we see:

public virtual object TypeId
{
get
{
return base.GetType();
}
}

Which probably should be something like this, however it's not (psudocode):

public virtual TypeID {
get {
if (IsAllowMultiple()) return this;
return GetType();
}
}

Since it's not really this way, but it IS virtual, you can certainly change your implementation of TypeID to return this, like, ahem, this:

[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class TestPermissionAttribute : Attribute {
public TestPermissionAttribute(string role, string user) { }

public override object TypeId { get { return this; } }
}

However, in this naive example, this object has no state. Notice the parameters are not stored, so "this" would be the same object. Add a few fields so the objects are actually different as they now hold some states, and the sample works returning this as the TypeID:

using System;
using System.ComponentModel;
class Program
{
static void Main(string[] args)
{
var prop = TypeDescriptor.GetProperties(typeof(Product))["Num"];
foreach (Attribute attrib in prop.Attributes)
{
Console.WriteLine(attrib.GetType());
}
Console.ReadLine();
}
}

public class Product
{
[TestPermission("foo1", "bar1")]
[TestPermission("foo2", "bar2")]
public int Num { get; set; }
}

[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class TestPermissionAttribute : Attribute
{
public TestPermissionAttribute(string role, string user) { Role = role; User = user; }

private string Role;
private string User;

public override object TypeId { get { return this; } }
}

So, the moral is, if you're using TypeDescriptors to get CustomAttributes and you want to have multiple attributes of the same type, make sure you:

  • Override TypeId to return this
  • Make sure AllowMultiple = true
  • Make sure your object has some fields (i.e. state)

Thanks to Zhe Wang and David Ebbo for the samples and their help.

I hope the two people who made it this far into the post and the one person who would ever hit this edge case appreciates this tale of obscurity.

If you like, follow me on Twitter: @shanselman

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Installing, Configuring and Using Windows Server AppFabric and the "Velocity" Memory Cache in 10 minutes

July 02, 2010 Comment on this post [39] Posted in AppFabric | ASP.NET
Sponsored By

A few weeks back I blogged about the Windows Server AppFabric launch (AppFabric is Microsoft's "Application Server") and a number of folks had questions about how to install and configure the "Velocity" memory cache. It used to be kind of confusing during the betas but it's really easy now that it's released.

Here's the comment:

Have you tried to setup a appfabric (velocity) instance ? I suggest you try & even do a blog post, maybe under the scenario of using it like a memcache for dasblog. I would love to know how to setup it up, it's crazy hard for what it is.

No problem, happy to help. I won't do it for dasblog, but I'll give you easy examples that'll take about 10 minutes.

Get and Install AppFabric

You can go to http://msdn.com/appfabric and download it directly or just do it with the Web Platform Installer.

Run the installer and select AppFabric Cache. If you're on Windows 7, you'll want to install the IIS 7 Manager for Remote Administration which is a little plugin that lets you manage remote IIS servers from your Windows 7 machine.

NOTE: You can also an automated/unattended installation as well via SETUP /i CACHINGSERVICE to just get caching.

The configuration tool will pop up, and walk you through a small wizard. You can setup AppFabric Hosting Services for Monitoring and Workflow Persistence, but since I'm just doing Caching, I'll skip it.Windows Server AppFabric Setup Wizard

The Velocity Caching Service needs to know where to get its configuration and it can get it from one of two places - either a database or an XML file on a share. If you use the XML file on a share, you'll need to make sure the service account has access to the share, etc. I'll use a database. The config wizard can make it for you as well. Click Next then Finish up the configuration.

Windows Server AppFabric Caching Service configuration Store

Configuring the Configuration Database...

Windows Server AppFabric Configuration Wizard

Ok, let's start it up and poke around.

Start and Administer your Memory Cluster from PowerShell

Now what? Go to the Start Menu and type in Caching. You'll have an item called "Caching Administration Windows PowerShell." This is where you can connect to the cache, check out what's going on, make new caches, etc. Run it as Administrator.

Caching Administration Windows PowerShell

If you type "get-command *cache*" you'll see all the different commands available for cache management. I typed start-cachecluster.

C:\> Start-CacheCluster

HostName : CachePort      Service Name            Service Status Version Info
--------------------      ------------            -------------- ------------
HANSELMAN-W500:22233      AppFabricCachingService UP             1 [1,1][1,1]

Cool, it's up and running. If you look in the config database (or the XML file if you chose that) you'll see that I have one machine in my memory cluster. I could have lots and lots, and if I had Windows Server Enterprise I would also have high-availability if one of the nodes went down.

I download the AppFabric Caching Samples and opened the CacheSampleWebApp in Visual Studio. Immediately we notice the two new references we don't usually see in a web application, Microsoft.ApplicationServer.Caching.Core and .Client.

image

Remember that for security everything is locked down by default, so you'll need to grant access to the cache for whatever user you'll be using to access it. I'm running as "ScottHa" so I'll run

Grant-CacheAllowedClientAccount scottha

...and you should do the same for whatever account your IIS is running as.

Use Your Memory Cache from ASP.NET

Remember that you can chop up your memory caches into logical buckets (partitions) and a memory cluster can serve more than one application, if you wanted.

Your cache can be hooked up in the web.config or from code (however you like). Here's a code example helper method where the sample does this manually. This data could come from wherever you like, you just need to tell it a machine to talk to and the portnumber. It'll automatically connect to the

Caches can also be partitioned. For example, I'm using a named cache called "default" but I could have multiple logically segmented areas like "shoppingcart" and "productcatalog" if I wanted.

using Microsoft.ApplicationServer.Caching;
using System.Collections.Generic;

public class CacheUtil
{
private static DataCacheFactory _factory = null;
private static DataCache _cache = null;

public static DataCache GetCache()
{
if (_cache != null)
return _cache;

//Define Array for 1 Cache Host
List<DataCacheServerEndpoint> servers = new List<DataCacheServerEndpoint>(1);

//Specify Cache Host Details
// Parameter 1 = host name
// Parameter 2 = cache port number
servers.Add(new DataCacheServerEndpoint("mymachine", 22233));

//Create cache configuration
DataCacheFactoryConfiguration configuration = new DataCacheFactoryConfiguration();

//Set the cache host(s)
configuration.Servers = servers;

//Set default properties for local cache (local cache disabled)
configuration.LocalCacheProperties = new DataCacheLocalCacheProperties();

//Disable tracing to avoid informational/verbose messages on the web page
DataCacheClientLogManager.ChangeLogLevel(System.Diagnostics.TraceLevel.Off);

//Pass configuration settings to cacheFactory constructor
_factory = new DataCacheFactory(configuration);

//Get reference to named cache called "default"
_cache = _factory.GetCache("default");

return _cache;
}
}

Once your cache is setup, it's trivial to use.

m_cache.Add(orderid, order);

and

Order order = (Order)m_cache.Get(orderid);

or updating an existing object:

m_cache.Put(orderid, order);

Check your Caching Statistics

So after adding a bunch of items to the cache, then requesting a bunch back I can go into PowerShell and see what's going on:

C:\> get-cache

CacheName            [Host]
                     Regions
---------            ---------------
default              [HANSELMAN-W500:22233]
                     Default_Region_0103(Primary)

C:\> Get-CacheStatistics default

Size         : 2493
ItemCount    : 5
RegionCount  : 5
RequestCount : 17
MissCount    : 3

You can use Performance Monitor as there is an imperial buttload of different Performance Counters Available. As I mentioned, you can make different partitions, like "default" or "poopypants" and check the stats on each of those separate, or the cache as a whole:

AppFabric Velocity Caching in PerfMon

And of course, I can recycle my webserver, start it up again and fetch an order and it's still there. You've effectively got a big, partitionable distributed (and optionally highly available) hashtable across multiple machines.

Diagram Explaining what AppFabric looks like as an architecture

Replacing ASP.NET Session State with AppFabric Caching

If you want, in ASP.NET 4 you can also swap out the default in-memory Session State Provider for AppFabric via your web.config. Here's an example web.config.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

<!--configSections must be the FIRST element -->
<configSections>
<!-- required to read the <dataCacheClient> element -->
<section name="dataCacheClient"
type="Microsoft.ApplicationServer.Caching.DataCacheClientSection,
Microsoft.ApplicationServer.Caching.Core, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35"
allowLocation="true"
allowDefinition="Everywhere"/>
</configSections>

<!-- cache client -->
<dataCacheClient>
<!-- cache host(s) -->
<hosts>
<host
name="CacheServer1"
cachePort="22233"/>
</hosts>
</dataCacheClient>

<system.web>
<sessionState mode="Custom" customProvider="AppFabricCacheSessionStoreProvider">
<providers>
<!-- specify the named cache for session data -->
<add
name="AppFabricCacheSessionStoreProvider"
type="Microsoft.ApplicationServer.Caching.DataCacheSessionStoreProvider"
cacheName="poopylands"
sharedId="MySharedApp"/>
</providers>
</sessionState>
</system.web>
</configuration>

Resources and Links

Here's a recent AppFabric caching slidedeck from Ron Jacobs I found useful. More links below. Microsoft Windows Server AppFabric Slides at SlideShare.

As with all things, a little abstraction goes a long way. If you have an existing caching strategy (via EntLib, or whatever) you can almost certainly swap out your internal storage for AppFabric Caching.

Related Links

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.