General Ramblings comments edit

The training I was in transitioned nicely into Thanksgiving. It was almost like having a whole week of vacation… but not.

Thursday (Thanksgiving) we went to the Hometown Buffet for dinner. My parents, my sister Tori, Jenn, my grandfather, Stu, and Tif all went. This proved to be an excellent answer to all of the issues that usually arise with Thanksgiving dinner. For example, what if someone (like me) doesn’t like turkey? No problem - you can have pretty much anything you want. What about the cleanup? There is none. Preparation? Nope. Everyone gets what they want, and as much of it as they want. It couldn’t be any better. I even had a cheeseburger. Right on! Plus, Granddad paid. Thanks, Granddad!

After dinner, Jenn went off to visit her family (and would later rejoin us), Granddad went to visit some other friends, and the rest of us returned to my parents’ place for some games. We played Lord of the Rings Risk, Apples to Apples, and even got some Donkey Konga in there. (Bongos on Thanksgiving is cool.) That went reasonably late into the evening, then we called it a night and departed for our respective residences.

Black Friday came and I had no intention of going anywhere, nor did I. Instead, Stu and Tif came over. Stu and I played some of The Warriors (like, 8 hours’ worth) while the ladies entertained themselves. The night ran late, but it was awesome - the first time in a while I’ve gotten a decent gaming session in.

(As far as The Warriors is concerned… it’s a lot of fun, but the camera could use some work. It’s a pain to control. That, and in a two-player game the screen is split vertically and it would have been better to split it horizontally because there is very little vertical movement. But it’s fun, and a good two-player game.)

Saturday Jenn and I ran around to stores looking to reap the benefits of the remaining sales on a few items but came out empty-handed. That evening, though, we went to the Winter Hawks hockey game to see the Teddy Bear Toss. When the Hawks score their first goal, the crowd throws stuffed animals onto the ice which then get collected and distributed to local childrens’ hospitals. Good fun for a good cause. Each year they try to break the record set by the year before. This year we beat last year’s record (and set the new league record) with 21,067 bears donated. That’s pretty good.

Oh, Saturday I discovered I’m allergic to my deodorant, too (causes a nice rash - thanks, Speed Stick Gel), so I’m going without for a couple of days (sorry, co-workers) to let the rash go away and I’m going to have to shop for a new one. (They stopped making the one I had been using for years, so I had to switch - unfortunately, I chose poorly.) Awesome.

Sunday was sort of a “catch up on all the stuff you’ve neglected” day. From morning until around 1:00p Jenn and I were outside cleaning up the yard. Had a hell of a time getting the lawnmower to start and just about kicked the crap out of it when I found the secret - you have to tip it back slightly while you’re starting it. That’s not documented anywhere and I don’t remember having to do that before, but that’s the trick. Weird.

After the lawn, having played The Warriors with Stu on Friday, I went to the video store and rented the 1979 movie the game is based on. It wasn’t too bad, and the game is totally dead on with its reproduction. I also rented Logan’s Run (I wanted to see it for the pop culture reference, but the movie itself is horrible) and The Jacket (which was pretty decent, plus Keira Knightley is hot).

And now it’s Monday and I’m catching up on email and so on. Somehow I think it’s going to be a looooong week.

media, music, sql comments edit

I’m working on setting up various Smart Playlists in iTunes and every time I’m working with them I totally run into all these shortcomings with the way they work. Like, what if I want all of the pop songs by Depeche Mode and Erasure that show up between 1980 and 1990? You have your choice of AND or OR, right? So it’s “Genre is Pop” and “Year is in the range 1980 to 1990” and… what? “Artist is Depeche Mode” and “Artist is Erasure” won’t work. I need an OR.

Why can’t I just do this: SELECT * FROM Library WHERE Year BETWEEN 1980 AND 1990 AND Genre = 'Pop' AND Artist IN ('Erasure', 'Depeche Mode')

No reason, that’s why. Come on, guys, get with the program.

sql comments edit

I’m going to combine days two and three into one big entry because I don’t think I’ll get a chance to do a full day-three review at the end of today.

Yesterday was day two and we looked at SQL Server 2005 service broker stuff, its native HTTP support, and Notification Services.

The service broker facilities they’ve added are pretty cool. The ability to set up messages and queues and such inside the server is neat, and it folds nicely into the native HTTP support to allow for exposure of these things via web service. Cool. SQLXML has rolled into SQL Server, which we all anticipated and love.

Notification Services, though… OK, I’m just going to be brutally honest:

SQL Server 2005 Notification Services sucks big fat donkey dong.

Seriously.

Notification Services is the biggest hunk of claptrap Rube Goldberg mechanics I’ve been introduced to in a long time. It’s not debuggable, it’s super-hard to set up, and for what it offers I’m not sure it’s worth the effort.

We had a lab to set up some rudimentary Notification Services. The lab involved us creating a lot of hand-cranked XML configuration, running some setup to get the services up and running, then testing it out.

Problem 1: The XML contains SQL that turns into stored procedures. Why is that bad? When they make the stored procedures, there’s nothing to tell you whether you have a typo in the SQL. I mistyped a database object name and it never had a problem with it. In fact, I found that error in the Event Viewer - not even in the SQL error log - and only when it actually tried to execute the procedure. NO!

Problem 2: There’s insufficient logging. After I corrected my error, I tried to use the service again and something else went wrong. What happened? I have no idea. It just swallows the errors and moves on like there’s no issue. No errors, no warnings, no log. How am I supposed to debug that?

The whole thing where the XML that you have to hand-generate (and there’s a LOT) has a lot of magic words in it that you just have to sort of “know” about (like you have to just “know” that when you type “Foo” in one element that it becomes a stored proc with a name like “ServiceFooSomeProcNameHere” - yeah, that’s intuitive. It really does work like Rube Goldberg machines - this bit of XML kicks this block of code out that rolls down the hill and knocks this table row down and flips over and tosses a message over to that service… Come on, guys. It’s like someone took a weekend, architected the thing, and clamped it on the side of SQL Server 2005 so they could have a selling point or something.

Today we’ll be learning about managed code in SQL Server 2005, which looks great; working with client apps (ADO.NET), which won’t be news for me; and SQL management objects, which also looks great.

Oh, and before I forget, tomorrow is Thanksgiving, so Happy Thanksgiving to all!

gists, csharp, dotnet comments edit

I’m looking at different ways to provide caching from within an application so I can read in some information from a file, keep it in memory, and have cache dependencies perform a callback to update the cache whenever the file changes.

This is simple to do in an ASP.NET app using the System.Web.Caching.Cache object that you find in HttpRequest. Just add something to the cache with a cache dependency and you’re set. But what about if you’re working in a console or Windows Forms app?

I did an experiment and it looks like you can access the cache from any application as long as you access it through HttpRuntime directly. I haven’t tested to see if this works on a machine that doesn’t have IIS installed, but I don’t see why it wouldn’t.

Below is my experiment code. It’s a console app that reads/writes the cache with a file dependency that constantly changes. Running it, you can see that the cache is doing what you expect, just like in a web app.

using System;
using System.Diagnostics;
using System.IO;
using System.Web;
using System.Web.Caching;

namespace ConsoleApplication1{
  class Class1{
    const string KEY = "mykey";
    const string FILENAME = "dependency.txt";

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args){
      WriteFile();
      InsertItem();

      for(int i = 0; i < 1000; i++){
        ReadItem();
        WriteFile();
      }
      ReadItem();

      if(Debugger.IsAttached){
        Console.ReadLine();
      }
    }

    static void InsertItem(){
      DateTime t = DateTime.Now;
      Console.WriteLine("Inserting item into cache: {0:m.s.ffffff}", t);
      HttpRuntime.Cache.Insert(
          KEY,
          t,
          new CacheDependency(Path.GetFullPath(FILENAME)),
          DateTime.MaxValue,
          TimeSpan.Zero,
          CacheItemPriority.Default,
          new CacheItemRemovedCallback(CallBack));
    }

    static void ReadItem(){
      object item = HttpRuntime.Cache[KEY];
      if(item == null){
        Console.WriteLine("Item is null.");
      }
      else if(item is DateTime){
        Console.WriteLine("Item is {0:m.s.ffffff}", item);
      }
      else{
        Console.WriteLine("Item is wrong type: {0}", item.GetType());
      }
    }

    static void WriteFile(){
      if(File.Exists(FILENAME)){
        File.Delete(FILENAME);
      }
      Console.WriteLine("Removing file.");
      FileStream stm = File.Create(FILENAME);
      stm.Close();
      Console.WriteLine("Wrote file.  File exists: {0}", File.Exists(FILENAME));
    }

    static void CallBack(string key, object value, CacheItemRemovedReason reason){
      Console.WriteLine("Callback invoked: {0}", reason);
      InsertItem();
    }
  }
}

If anyone finds a problem with it, do leave me a comment with reproduction info. Seems to work, though, which is pretty cool.