Chris Cavanagh’s Blog

Batch Updates and Deletes with LINQ to SQL

April 14, 2008 · No Comments

My co-worker / colleague Terry Aney has posted a kick-ass article about coaxing LINQ to SQL into generating more efficient SQL batch UPDATE and DELETE commands (in the current LINQ to SQL release, separate UPDATE / DELETE commands are executed for each row).  It’s an interesting read and the end result is pretty sweet too :)

→ No CommentsCategories: .NET

Excel add-ins in C#

April 13, 2008 · 1 Comment

My colleague Terry Aney has posted a detailed article on the “fun” he’s had creating Excel add-ins in C# (after migrating from XLAs + VBA).  If you need to make several thousand calls between add-ins and Excel and want to use .NET, you should definitely run some performance comparisons first :)

In a related post he discusses source control strategies / workarounds for XLA files.

→ 1 CommentCategories: .NET · COM Interop · Excel · VB

ASP.NET Routing… Goodbye URL rewriting?

March 11, 2008 · 8 Comments

UPDATE 2: You can find a sample project and more details here.

UPDATE: Be sure to check out Phil Haack’s post covering some of the security implications of this.  I’ve also added a related comment to the end of this post :)

The recent ASP.NET MVC Preview 2 release brought some interesting stuff for “traditional” ASP.NET developers.  The new System.Web.Routing and System.Web.Abstractions assemblies have no dependency on MVC and can be leveraged pretty easily.  Check out this post by Phil Haack (and be sure to keep up with his upcoming posts that will go into more detail).

One of the obvious uses for the new routing mechanism is as a “clean” alternative to URL rewriting (and possibly custom VirtualPathProviders for simple scenarios) for traditional / postback-based ASP.NET sites.  After a little experimentation I found some minimal steps that work pretty well:

  • Create a custom IRouteHandler that instantiates your pages
  • Register new Routes associated with your IRouteHandler
  • That’s it!

The IRouteHandler implementation can be as simple or elaborate as you like.  Just implement the GetHttpHandler method and return a new instance of an ASP.NET page (if you want to use an ASPX you can instantiate it with BuildManager.CreateInstanceFromVirtualPath).

Here’s a very simple IRouteHandler implementation that instantiates a single page (compiled or ASPX) for any request sent to it:

public class WebFormRouteHandler<T> : IRouteHandler where T : IHttpHandler, new()
{
    public string VirtualPath { get; set; }

    public WebFormRouteHandler( string virtualPath )
    {
        this.VirtualPath = virtualPath;
    }

    #region IRouteHandler Members

    public IHttpHandler GetHttpHandler( RequestContext requestContext )
    {
        return ( VirtualPath != null )
            ? (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath( VirtualPath, typeof( T ) )
            : new T();
    }

    #endregion
}

This example could be useful in a site with a single ASPX that hosts multiple ASCXs as its “pages” (maybe one that uses the inbuilt SiteMap as a mapping mechanism between public URLs and ASCXs).  For more traditional sites, your GetHttpHandler would return separate page instances based on the RequestContext it’s provided with (RequestContext includes the routing details extracted from the URL; MVC would create a Controller at this point).

Routes are usually registered in the Application_Start handler in Global.asax.  Here’s a simple example based on the “single ASPX / multiple ASCX” approach that passes several routes to a single page (MyPage.aspx):

protected void Application_Start( object sender, EventArgs e )
{
    RegisterRoutes( RouteTable.Routes );
}

public static void RegisterRoutes( RouteCollection routes )
{
    // Note: Change the URL to "{controller}.mvc/{action}/{id}" to enable
    //       automatic support on IIS6 and IIS7 classic mode

    var routeHandler = new WebFormRouteHandler<Page>( "~/MyPage.aspx" );

    routes.Add( new Route( "{page}", routeHandler ) );
    routes.Add( new Route( "AccountServices/{page}", routeHandler ) );
    routes.Add( new Route( "Default.aspx", routeHandler ) );
}

Phil Haack has a post that covers some security implications of this approach.  Like Phil suggests, the ‘insecure’ behavior might be exactly what you want.  You could prevent direct URL access to your ASPX’s (using ASP.NET’s existing mechanisms) and consider them just resources to be used by your IRouteHandler.

Also note that Phil includes a mechanism for passing the RequestContext to your page (just define and implement the IRoutablePage interface).

→ 8 CommentsCategories: .NET

Silverlight 2 - 2D Physics revisited

March 6, 2008 · 12 Comments

It’s awesome that Silverlight 2 [beta 1] is now with us; the world just became a far cooler place :)  It can’t all be good of course; sadly my earlier Silverlight 1.1 demos no longer work :(

Fortunately it took almost no effort to get things moving again.  If you’ve got Silverlight 2, you can try the updated demo here (or click the image).  There’s also a new “heads will roll” feature for your viewing pleasure.  Source code coming soon…

 image

You might notice objects occasionally roll behind each other (BulletX is a 3D physics engine; I’m probably missing a constraint), or you might get kicked to a blank page…  They’re my bugs, not Silverlight’s :)  I’ll update here when they’re fixed.

→ 12 CommentsCategories: .NET

WPF animated GIF and Javascript filmroll

February 29, 2008 · 2 Comments

I made a few improvements to my SkinBuilder utility (I’m using it daily and it’s great!).  You can now add these attributes to a <Snapshot>:

  • Top, Left, Right, Bottom - Snapshot position relative to container edges (otherwise defaults to top left).
  • Width, Height - Snapshot width and height (defaults to container size if known).
  • RenderDpi - The DPI (Dots Per Inch) to render at.
  • Dpi - The DPI of the snapshot (this may influence the final width and height; defaults to 96 if omitted).
  • Quality - Compression quality level for JPEGs (0 to 100; defaults to 100).

Additionally the <Group> element supports position attributes (Top, Left, Right, Bottom) and a new OutputPath attribute, which lets you set a relative base path for all contained Snapshots.

The most interesting new attributes are RenderDpi and Dpi.  The following examples show a rotating 3D Kaxaml logo as an animated GIF and a Javascript-driven “filmstrip”, both rendered at 300 dpi and scaled down to 96 dpi (effectively anti-aliasing the result - something WPF 3D can’t otherwise do when rendering to a bitmap):

Javascript-driven filmstrip (and here’s the image it’s using).

Kaxaml_repeat

Note - I passed the animated GIF through a freeware utility called Beneton Movie GIF so I could enable the “repeat forever” flag.  The Javascript example just manipulates the CSS backgroundPosition property on a timer event…

Let me know if you generate any cool WPF 3D animation GIFs or filmstrips! :)  If they’re really REALLY cool I’ll post them here!

→ 2 CommentsCategories: .NET

WordPress "Snap Preview"

February 20, 2008 · No Comments

You’ll be pleased to know I’ve finally switched off my annoying “Snap Preview” that WordPress.com enables by default.  FYI here’s how you do it.

→ No CommentsCategories: .NET

WPF Skinning your Websites - Source code now available!

February 18, 2008 · 5 Comments

UPDATE: Now allows more positioning options for Groups and Snapshots (Left, Top, Right, Bottom, Width, Height - all optional).

UPDATE 2: You can now specify rendering and capture DPI values; if you render a 3D scene at a higher DPI (say 300) you’ll get anti-aliased images.  Note you don’t need to do this for 2D content.

You can download the source code for my “SkinBuilder” utility right here.

There have been some enhancements since it was originally posted.  Here’s a typical configuration file (called “SkinBuilder.xml” in my example):

<?xml version="1.0" encoding="utf-8" ?>
<sb:SkinBuilder
    xmlns:sb="http://www.chriscavanagh.com/SkinBuilder"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns :x ="http://schemas.microsoft.com/winfx/2006/xaml">

    <sb:Scene>

        <sb:Xaml Source="SkinBuilder.xaml"/>

        <sb:Snapshot Left="0" Top="1" Width="1" Height="173" Filename="background_top_gradient.png" />

        <sb:Group Element="mainPage">

            <sb:Snapshot Left="0" Top="0" Width="14" Height="164" Filename="page_header_lft.png" />
            <sb:Snapshot Left="14" Top="0" Width="748" Height="164" Filename="page_header_ctr.png" />
            <sb:Snapshot Right="0" Top="0" Width="14" Height="164" Filename="page_header_rt.png" />

            <sb:Snapshot Left="0" Top="170" Width="14" Height="1" Filename="main_content_bkgd_lft.png" />
            <sb:Snapshot Left="0" Top="170" Height="1" Filename="main_content_bkgd.png" />
            <sb:Snapshot Right="0" Top="170" Width="14" Height="1" Filename="main_content_bkgd_rt.png" />

            <sb:Snapshot Element="rotatingTest" Storyboard="rotation" Frames="20" Filename="animated-loader.gif" />
            <sb:Snapshot Element="rotatingTest" Storyboard="rotation" Frames="5" Filmstrip="true" Filename="animated-loader-filmstrip.jpg" />

            <sb:Snapshot Left="0" Bottom="0" Height="29" Filename="copyright_bar.png" />

        </sb:Group>

        <sb:Snapshot Filename="Full.jpg" />
        <sb:Snapshot Filename="Full.png" />
        <sb:Snapshot Filename="Full.gif" />

    </sb:Scene>

</sb:SkinBuilder>

There can be multiple <Scene> elements in the configuration file, each one having a XAML reference (or inline XAML content) and any number of <Snapshot> and <Group> elements.  All snapshot origin co-ordinates (Left, Top, Right, Bottom) are optional and relative to their containing groups.  Size values (Width, Height) are optional; where possible they’ll be determined from the container.

The ‘Element’ attribute makes co-ordinates relative to the position of a named XAML element.  In the example above, two snapshots are taken of the “rotatingText” element; because no offset or size is specified, the bounds of the XAML element are used.  If the ‘Element’ attribute is applied to a group, all child snapshots and groups will be relative to it.

If the ‘Storyboard’ attribute is applied to a snapshot, the named WPF storyboard will be recorded.  If the ‘Frames’ attribute is omitted, only the last frame will be captured; otherwise it’ll capture the specified number of frames (including the first and last frame).  By default it will attempt to pass all frames to the BitmapEncoder, but this will only work for formats that support multiple frames (GIF).  Applying the ‘Filmstrip’ (boolean) attribute will generate a single image containing all the frames stacked vertically.  This can be used with CSS’s background-offset property for mouseover effects etc.

In my earlier post I mentioned how your XAML could contain simple data binding expressions; in the sample project I showed how arbitrary properties could be bound to values in an external configuration file.  You could include the configuration file in an ASP.NET project and run SkinBuilder as a post-build step to allow instant re-skinning of a site.  Check out these “themes” I created by single-value tweaks the SiteSpecification.xml file:

Full - Blue Full - Pink Full - Purple Full - Yellow

Finally, sorry for the very brief documentation!  Let me know if I’ve left any obvious holes and I’ll update as necessary :)

→ 5 CommentsCategories: .NET

WPF Skinning your Websites

February 15, 2008 · 6 Comments

UPDATE 2: Now able to create “filmstrip” images from WPF Storyboards; some basic documentation available here.

UPDATE: Now able to create animated GIFs from WPF Storyboards.

I’ve written a cool little utility that lets you skin websites with WPF / XAML.  All you need to do is define a XAML scene and specify the rectangular regions you need snapshots of.  Each is saved to its own file (as PNG, JPEG or GIF).

Once you’ve got the files, just set them as background images for appropriately positioned HTML elements :)

Some nice benefits are:

  • You can use any WPF content, including 3D.
  • You get edge anti-aliasing for free (see comment below).
  • You can build scenes with multiple layers; gradient fills, alpha blends etc.  If your graphic assets have transparency (PNG files for example) you can do some very nice compositing.  Your graphic designers may soon be twiddling their thumbs…
  • You can design your scene in Blend, Kaxaml, … (insert tool of choice).
  • Rounded corners!  A few CornerRadius attributes and you never need cringe at AJAX Control Toolkit’s blocky attempt again.
  • Browser independent; you can save images as PNG, JPEG or GIF.  It’s your choice whether you include transparency in them or not (IE6 can’t apply transparency in PNGs but IE7 can).  You can compose your scene using all the transparency you like, but slice the result into JPEGs or GIFs that’ll work everywhere :)
  • You can include data-binding expressions; a nice example of this is keeping primary site colors in a separate configuration file, giving developers a disturbing amount of control (don’t forget you can manipulate colors with OpacityMasks etc to produce varying shades).
  • Simple WPF Storyboards can be recorded as animated GIFs or “filmstrip” images (the animated frames are vertically spaced in a single image).
  • It’s a command-line utility and is happy with relative paths.  This makes it great for calling from a post-build step in Visual Studio.
  • It’s mainly in its own assembly; you could use it in other applications, or use it as a custom build tool.
  • It’s free!  Source code will be available soon :)

Now for the bad news:

  • 3D content isn’t anti-aliased.  This is simply because WPF 3D expects the graphics hardware to do its 3D anti-aliasing, and it only does that when it’s sent directly to the screen.  One solution is to create the RenderTargetBitmap with a much higher DPI (say 300), then downsample it later.  I’ll probably make the DPI configurable in a future update. 
  • I’ve found some properties don’t work with binding expressions (for example the color steps of a LinearGradientFill).  However the same properties work fine in Kaxaml, Blend etc.  This might just be a bug in my code; I’ll post an update if I find a solution.  As usual there are workarounds; instead of a LinearGradientFill you could use several solid fills (with binding) and apply static OpacityMasks with LinearGradientFill.  If that statement made no sense, let me know and I’ll try to describe it better :) (also let me know if you have a solution).
  • Although it can create animated GIFs, currently they only play once (no repeat).  However, it’d be quite easy to add a reference to NGif to re-encode the GIF with the relevant metadata (could do it all through streams; no intermediate files needed).

Finally the goodies :)  You can download the utility here.  It includes some sample configuration files to play with (and shows binding to values in a separate XML file).  Extract the files to a folder and type this:

SkinBuilder SkinBuilder.xml

It’ll create around 12 image files in the current folder (including one animated GIF and a filmstrip image).  They probably won’t be much use to you directly, but serve as a good example.  Here’s pretty much what the sample page looks like:

Full

But that’s not all!  You can also get the source code right here :)

I’ve not created an installer yet; I could say this is so I don’t burden you with anything unnecessary, but clearly it’s just laziness :)

Enjoy!

→ 6 CommentsCategories: .NET

XAML Loading Animation

February 11, 2008 · No Comments

Here’s a very simple XAML ‘loading’ animation you might find useful:

<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns :x ="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="1"
        Height="1"
        >

    <Canvas.RenderTransform>
        <TransformGroup>

            <RotateTransform x:Name="angle" Angle="0" CenterX="0.5" CenterY="0.5"/>

            <!-- Ideally remove the translation and scale from here
                 and let the container apply them instead -->

            <TranslateTransform X="-0.5" Y="-0.5"/>
            <ScaleTransform ScaleX="100" ScaleY="100"/>

        </TransformGroup>
    </Canvas.RenderTransform>

    <Canvas.Triggers>
        <EventTrigger RoutedEvent="Canvas.Loaded">
            <BeginStoryboard>
                <Storyboard x:Name="rotation">
                    <DoubleAnimation To="1" Duration="0:0:1"
                                                    Storyboard.TargetName="content"
                                                    Storyboard.TargetProperty="Opacity"/>
                    <DoubleAnimation From="0" To="359" Duration="0:0:3" RepeatBehavior="Forever"
                                                    Storyboard.TargetName="angle"
                                                    Storyboard.TargetProperty="Angle"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Canvas.Triggers>

    <Canvas Name="content" Opacity="0">

        <Path Width="1" Height="1" Stretch="Fill" Stroke="Green" StrokeThickness="0.1" StrokeStartLineCap="Round">
            <Path.Data>
                <PathGeometry>
                    <PathFigure StartPoint="1,0">
                        <ArcSegment Point="0,-1" RotationAngle="90" SweepDirection="Clockwise" IsLargeArc="True" Size="1,1"/>
                    </PathFigure>
                </PathGeometry>
            </Path.Data>
        </Path>

        <Path Canvas.Left="0.49" Canvas.Top="-0.05" Width="0.2" Height="0.2" Stretch="Fill" Fill="Green">
            <Path.Data>
                <PathGeometry>
                    <PathFigure StartPoint="0,-1.1">
                        <LineSegment Point="0.1,-1" />
                        <LineSegment Point="0,-0.9" />
                    </PathFigure>
                </PathGeometry>
            </Path.Data>
        </Path>

    </Canvas>

</Canvas>

You can see it in action here.

→ No CommentsCategories: .NET

Custom Collection Initializers

February 11, 2008 · No Comments

You might already know that .NET 3.5 supports inline collection initialization like this:

var romanNumerals = new Dictionary<int, string>
{
    { 1000, "M" },
    { 900, "CM" },
    { 500, "D" },
    { 400, "CD" },
    { 100, "C" },
    { 90, "XC" },
    { 50, "L" },
    { 40, "XL" },
    { 10, "X" },
    { 9, "IX" },
    { 5, "V" },
    { 4, "IV" },
    { 1, "I" }
};

This is described nicely by Mads Torgersen here.  You can initialize custom collections in the same way; all you need to do is provide an ‘Add’ method (see Mads’ post if you’re curious why they don’t just rely on ICollection<T>).  Here’s an example of how it could be used:

public static class NumberConversion
{
    private class KeyValueList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>
    {
        public void Add( TKey key, TValue value )
        {
            Add( new KeyValuePair<TKey, TValue>( key, value ) );
        }
    }

    private static KeyValueList<int, string> numerals = new KeyValueList<int, string>
    {
        { 1000, "M" },
        { 900, "CM" },
        { 500, "D" },
        { 400, "CD" },
        { 100, "C" },
        { 90, "XC" },
        { 50, "L" },
        { 40, "XL" },
        { 10, "X" },
        { 9, "IX" },
        { 5, "V" },
        { 4, "IV" },
        { 1, "I" }
    };

    public static string ToRoman( this int number )
    {
        var roman = new StringBuilder();

        foreach ( var numeral in numerals )
        {
            while ( number >= numeral.Key )
            {
                roman.Append( numeral.Value );
                number -= numeral.Key;
            }
        }

        return roman.ToString();
    }
}

This could be extended to include any number of parameters (not just key / value pairs).  Additionally, the initialization rows don’t all need to hit the same ‘Add’ method; you can use as many overloads as you like :)

→ No CommentsCategories: .NET