Mad Props!

Omniscience is just a Google-search away.

Login

You're reading Mabsterama, the weblog of Matt Hamilton. Enjoy your stay.

Type Alias Quirk

Scott Hanselman tweeted this afternoon about it being a drag using a type like this:

List<KeyValuePair<String, Func<Brush, UserControl>>>

It's certainly a complex type with all those nested generics. My first instinct, apart from deriving new non-generic classes from the generic ones, was to try type aliases to simplify the declaration. This first try worked:

using BrushUserControlFunc = System.Func<
    System.Windows.Media.Brush,
    System.Windows.Controls.UserControl>;

With that code outside of my namespace declaration, I was free to declare a type like this:

List<KeyValuePair<String, BrushUserControlFunc>> foo;

Still pretty ugly though, so logically the next thing to do would be to alias off the KeyValuePair type. That's where I struck a hurdle. This doesn't compile:

using BrushUserControlFunc = System.Func<
    System.Windows.Media.Brush,
    System.Windows.Controls.UserControl>; using StringFuncPair = System.Collections.Generic.KeyValuePair<
    string,
    BrushUserControlFunc>;

It seems that you can't make one aliased type the generic parameter to another. Moving the second declaration into my namespace made it work, though:

using BrushUserControlFunc = System.Func<
    System.Windows.Media.Brush,
    System.Windows.Controls.UserControl>; namespace WpfApplication1 { using StringFuncPair = KeyValuePair<string, BrushUserControlFunc>;
So that's a strange quirk with type aliases. It's a hell of an edge case, but there you go.

AWDNUG July

Last night's meeting of the Albury/Wodonga .NET User Group was a little bit different - we held it at the local pub and combined the meeting with a geek dinner.

The meeting was the third in our Heroes Happen Here series, in which we look at the 2008 line of products from Microsoft. We've already looked at SQL Server 2008 and Windows Server 2008, and last night I took the guys through some of the new features in Visual Studio 2008. I focused on language enhancements because to be honest, I don't do a whole lot of work in the areas in which the IDE got the most attention, like ASP.NET, VSTO etc.

The best thing about the meeting was the turn-out: We had 13 people! That's probably as many people as we have ever had to a meeting, and it included three newcomers from Border Express. Great to see new faces and they really seemed to know their stuff, so I look forward to seeing them presenting too, one day.

The geek dinner/meeting concept worked so well that we're considering moving the meeting to the pub for good. We have to bring our own projector etc, but they provided an out-of-the-way function room for us so it worked really well.

Next meeting is August 12! See you there!

Ex Machina

Just finished volume one of Ex Machina, by Brian K Vaughan. As a big fan of Y: The Last Man I figured I'd like this one, and I was right.

The story revolves around Mitchell Hundred, the mayor of New York City who, in a previous life, was a crime-fighting super hero. His power: he can talk to machines. Any sufficiently complex piece of machinery will obey his command. He can, for example, force a gun to jam, or tell lights to dim. Having retired from the super-hero business, Hundred focuses on managing the city, and the result is like The West Wing meets Iron Man.

Of particular interest, and something I didn't realise until I'd reached the last few pages of the trade, is that this book was drawn using real photo references - the artist had people pose for photos and then changed them into the characters as he redrew the photos. It makes for a very realistic art style and it's fascinating to see his "photo to completed page" story boards at the end of the book.

Anyway, here's a link (an affiliate link) to the book on Amazon.com in case you're interested. It's well worth a read. I've already ordered volume two and have added four more to my wish list!

Another IDbCommand Extension - Fill

I'm on a roll creating extension methods for IDbCommand, so here's another one.

Quite often we see this pattern when reading from a command:

using (var rdr = cmd.ExecuteReader()) { while (rdr.Read()) { var thing = new Thing() { Date = rdr.GetDateTime(0), Foo = rdr.GetInt32(1) }; things.Add(thing); } }

It's pretty straight-forward code, but it's code nonetheless. Here's an extension method on IDbCommand that wraps this logic up into one call. It accepts an IList<T> as a parameter, and a function which, given an IDataReader, returns an instance of T:

public static void Fill<T>(this IDbCommand cmd,
    IList<T> list, Func<IDataReader, T> rowConverter)
{
    using (var rdr = cmd.ExecuteReader())
    {
        while (rdr.Read())
        {
            list.Add(rowConverter(rdr));
        }
    }
}

This takes care of wrapping the reader in a "using" statement, so there's one less thing you have to remember to do. If you took the code in the first snippet and wrapped the call to GetDateTime and GetInt32 into its own little extension method on IDataReader called "GetThing", then you'd be able to turn that into this:

cmd.Fill(things, r => r.GetThing());
The less code you have to write, the less the chance you'll introduce bugs, so for me this is a handy method. What do you think? Do you prefer to spell it out, or are extension methods ringing your bell too?

Adding IDbCommand Parameters with Anonymous Types

To take my previous post to the next level, I decided to try a different approach to adding parameters to an IDbCommand by using anonymous types. This is inspired by the way you set up routes in ASP.NET MVC, and example of which you can see here on ScottGu's blog. The idea is that you simply pass in an anonymous type, whose properties match the parameter names you want to define.

First, here's the extension method:

internal static void AddInputParameters<T>(this IDbCommand cmd,
    T parameters) where T : class
{
    foreach (var prop in parameters.GetType().GetProperties())
    {
        object val = prop.GetValue(parameters, null);
        var p = cmd.CreateParameter();
        p.ParameterName = prop.Name;
        p.Value = val ?? DBNull.Value;
        cmd.Parameters.Add(p);
    }
}

So I'm iterating through the properties of "parameters", and for each one I'm adding an input parameter based on its value. I'm supporting null by simply adding a parameter with DBNull.Value.

Note that this has a slightly different behaviour with strings than my previous attempt, in that it will not treat an empty string as DBNull, but I think this is probably preferable.

Here's how you'd use it:

cmd.AddInputParameters(new
    {
        Date = eventDate,
        Operator = oper,
        Weight = weight
    });

Pretty succinct! Of course it's no more compile-checked than literal strings (except for the fact that it only allows valid identifiers as parameter names), but it's much more readable than a small chunk of code for each parameter.

AddWithValue via Extension Methods

On a recent .NET Rocks panel show, Ayende complained that the abstract classes to access databases (for example, IDbCommand) were lacking some fundamental pieces that make the concrete classes (eg SqlCommand) easier to use. The example he cited was the AddWithValue method, to quickly add a parameter to an SqlCommand along with its value.

I know how he feels; the act of calling CreateParameter, then setting the parameter's name and value, then calling Parameters.Add is a lot more code than it should be for such a simple operation.

So I've gone ahead and made myself a quartet of handy extension methods to give me similar functionality to the AddWithValue method. In fact, my version is a little more powerful, since it accepts nullable types and passes DBNull if the value isn't specified. Here's the code:

internal static class DbCommandExtensions
{
    internal static int AddInputParameter<T>(this IDbCommand cmd, 
        string name, T value) 
    {
        var p = cmd.CreateParameter();
        p.ParameterName = name;
        p.Value = value;
        return cmd.Parameters.Add(p);
    }

    internal static int AddInputParameter<T>(this IDbCommand cmd, 
        string name, Nullable<T> value) where T : struct
    {
        var p = cmd.CreateParameter();
        p.ParameterName = name;
        p.Value = value.HasValue ? (object)value : DBNull.Value;
        return cmd.Parameters.Add(p);
    }

    internal static int AddInputParameter(this IDbCommand cmd, 
        string name, string value) 
    {
        var p = cmd.CreateParameter();
        p.ParameterName = name;
        p.Value = string.IsNullOrEmpty(value) ? DBNull.Value : (object)value;
        return cmd.Parameters.Add(p);
    }

    internal static IDbDataParameter AddOutputParameter(this IDbCommand cmd, 
        string name, DbType dbType)
    {
        var p = cmd.CreateParameter();
        p.ParameterName = name;
        p.DbType = dbType;
        p.Direction = ParameterDirection.Output;
        cmd.Parameters.Add(p);
        return p;
    }
}

So this gives us essentially two new methods on IDbCommand, "AddInputParameter" and "AddOutputParameter". You use them like this:

var cmd = _connection.CreateCommand();

cmd.AddInputParameter("@id", eventDate);
var idParam = cmd.AddOutputParameter("@id", DbType.Guid);

 

Pretty straight forward, I think, and it saves a lot of code. It also hasn't broken any of our tests, because all the expectations we've set on our mocks are still being met.

Moq Triqs - Successive Expectations

I've posted this to the Moq discussion forum but I think it warrants its own post here too.

One of the (very minor) limitations we struck with Moq if that if you expect to call the same method more than once and get a different result each time, there's no straight forward way to set that up. If you try this:

mockCommand.Expect(c => c.CreateParameter()).Returns(mockParam1.Object);
mockCommand.Expect(c => c.CreateParameter()).Returns(mockParam2.Object);

... then when your code calls CreateParameter() it'll just get the "mockParam2" object back twice, because the second expectation has "overwritten" the first.

We stumbled upon a nice workaround for this particular problem using an overload of IExpect.Returns which takes an expression rather than a value. Basically, every time the expected method is called, the expression is evaluated and its result is returned. So we use an expression to return a series of values, one after the other. Even nicer, we do so using the generic Queue object. Here's the code:

var pq = new Queue<IDbDataParameter>(new[]
    { 
        mockParam1.Object, 
        mockParam2.Object 
    });
mockCommand.Expect(c => c.CreateParameter()).Returns(() => pq.Dequeue());

See what's happening? We "queue up" two parameters, and then "dequeue" them as the CreateParameter is called each time.

I know that the Moq guys are considering some sort of "sequence" feature to overcome the "successive expectations overwrite the previous ones" problem, but this queuing method works a treat for us.

Sharing Membership between Community Server and Graffiti

A little tip if you've followed Dan Bartels' excellent guide to setting up shared ASP.NET membership with Graffiti:

Something that Graffiti requires (at least version 1.1 does) is that all users are a member of the "gEveryone" role. If you read my earlier post about logging in you'll remember that I had to assign the "gEveryone" role to all my existing users before they could see the front page of the site once logged in.

Well, there's one more hiccup around this issue: New users don't get assigned the "gEveryone" role by default. I've had about three folks sign up in the past few days, and I'll bet they've been seeing "access denied" messages when they visit the site. Poor buggers.

Let's fix that, shall we? In Community Server this turns out to be really easy. Open up your "communityserver.config" file, and find this line in the "<Core>" section:

defaultRoles = "Everyone;Registered Users"

Hopefully it's self-explanatory. All we need to do is add "gEveryone" to that semi-colon-separated list, and new users automatically get assigned that role.

So now everyone can sign up and post in the forums! Huzzah!

A Custom 404 Page for Graffiti

Have you seen a 404 error on madprops.org? I hope not. But if you have, you would have noticed that it's not the default 404 page that your browser normally shows.

After re-reading Jeff Atwood's post about custom 404 errors, and seeing the great job Dave did on his when he migrated to BlogEngine.NET, I decided that this site, too, should have a custom 404 page with some helpful links on it, and I decided to use Graffiti's theme engine to do it.

First, I created a new, uncategorized post. I gave the post the title of "Not Found!" and switched over to the options and set its name to "404". For the body of the post, I wrote a brief spiel about how the page you were looking for isn't here anymore, and that you should try some other options - for example the lists of most recent and most popular posts.

Now I needed to get those links to appear on my page. Graffiti's Chalk theme engine allows for custom "views" based on the name of the post, so I created a new file called "404.view" which would be used to display just that one post.

My 404.view file, then, contains the standard markup for rendering a post (without the extra bits like when the post was created, what tags it has, or any kind of comments), along with a few extra bits underneath. First, to display the last 15 posts made to my site, I use this markup:

<h3>Recent Posts</h3>
<ul>$macros.ULRecentPosts(15)</ul>

Then, to display the 15 most-viewed posts, I use this:

#foreach ($post in $data.PopularPosts(15))
#beforeall
<ul>
#each
<li><a href="$post.Url">$post.Title</a></li>
#afterall
</ul>
#end

You can see how powerful Graffiti's theme system is, making use of the NVelocity templating engine.

Lastly, I wanted to make sure that the 404 page didn't show my sidebar boxes, just for neatness. To accomplish this, I made a custom layout file called "404.layout.view", which excluded all the sidebar markup that I use on the default layout page. The "postname.layout.view" syntax means that Graffiti will use that file as the overall structure of the site for that post, rather than the default "layout.view" file.

The result, then, is a "Not Found!" page that hopefully guides the visitor if not to the page they were looking for, then at least to a page they'll be interested in reading.

Please Fix ASAP

An interesting little story from work today.

Late last week we had a call from the feedmill, telling us that a program they run which lets them view reports had stopped working. Upon closer investigation it seemed that the program used an embedded WebBrowser control to hit a local SQL Server Reporting Services machine and display a list of reports to the user. The server it was trying to talk to, though, hasn't been running Reporting Services for ages - it's an old SQL 2000 box that was superceded by a new one many months ago.

To work around the problem, we simply gave them an Internet Explorer shortcut to the same list of reports on the correct server. So their "reports" button in the application is still broken, but at least they could get the information they needed.

Today we got a call from a manager in a more senior position over there asking when it was going to be fixed. He apparently didn't realise that we'd put a workaround in place, so I can't blame him for chasing it up, but it got me curious.

I connected to the old server that the program was trying to talk to, and had a look at its IIS logs (in C:\WinNT\System32\LogFiles\W3SVC1). I opened yesterday's, and found an entry like this:

2008-06-29 21:27:47 192.168.XX.XXX - 192.168.XX.XX 80 GET /Reports/Pages/SearchResults.aspx SearchText=ProdUtil 404 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.0;+.NET+CLR+2.0.50727)

Fair enough - a 404 on the URL they requested. Makes sense, since that's the error they're seeing in their application.

So I jumped into PowerShell on my local machine, changed into that folder using a UNC path, and (after a bit of trial and error) ran this command:

select-string "ProdUtil" -path ex08*

Plenty of results there, but a closer look at the filenames that were being returned revealed the fact that they were all on or after June 25th - mid last week. There were no mentions of "ProdUtil" in any of the log files from this year before that date.

Now, I know for a fact that the application they're running has a timestamp of around July 2007, so it's not like somebody gave them a new, broken version of the program. They simply haven't tried to use this feature all year.

So it's an interesting insight into the mind of some users, when problems arise that need to be fixed "ASAP", because they're stopping people from doing something that they're supposed to do every day, yet we find that they have in fact gone over six months without using the feature at all.