Tuesday, 24 February 2009

Static links for aspx pages in 20 lines of code

Still using WebForms? Sick of magic string URLs that break when you move you ASPX pages around? Try this! I've created a class called UrlFor<TSomePage>. It examines the page class and figures out the URL by making a few assumptions about your aspx pages (the aspx file has the same name as the class, the namespaces match the folder structure, that kind of thing...)

public class UrlFor<TAspxPage>
    where TAspxPage : Page
    private static string baseUrl = typeof(TAspxPage).FullName.Substring("YourAppBaseNamespace".Length).Replace('.', '/') + ".aspx";

    public Dictionary<string, string> QueryString = new Dictionary<string, string>();

    public UrlFor<TAspxPage> Set<TValue>(Expression<Func<TAspxPage, TValue>> getProp, TValue value)
    {
        this.QueryString[((MemberExpression)getProp.Body).Member.Name] = value.ToString();
        return this;
    }
    public override string ToString()
    {
        var qs = String.Join("&", this.QueryString.Select(pair =] pair.Key + "=" + HttpUtility.UrlEncode(pair.Value)).ToArray());
        return baseUrl + (qs.Length ] 0 ? ("?" + qs) : String.Empty);
    }
}
anyway, it lets you write things like this in your code:
[%= new UrlFor<Meetings.Details>().Set(d => d.WorkspaceId, 1).Set(d => d.MeetingId, 2) %>
where Meeting.Details is a Page class with a property on it called MeetingId and one called WorkspaceId. This generates a url like
/Meetings/Details.aspx?WorkspaceId=1&MeetingId=2
Of course your pages may not have properties that correspond to the querystring parameters, but you can always write an extension like
public static class UrlForExt
{
    public static UrlFor<T> SetWorkspaceId<T>(this UrlFor<T> url, int value)
        where T:WorkspacePage
    {
        url.QueryString["workspaceid"] = value.ToString();
        return url;
    }
}
and get the same effect by writing something like
new UrlFor<Default>().SetWorkspaceId(1)
Neat huh!? Use this to build your links and you can rename and move your pages to your hearts content!

Submit this story to DotNetKicks

Monday, 9 February 2009

MigrationScriptGenerator

Hi all, I thought I'd give you all a heads up on a new tool I've written for keeping your database schema in sync with your development schema
Basically its a tool for generating SQL scripts for changes (using Open DBDiff), with errors if you do a change that might lose data. It creates a script to you to review. If your changes are non destructive, then it just makes the change script for you.
Its pretty alpha at the moment, but seems functional enough for development work. Check out the sample project - it's hooked up with Fluent NHibernate. Try changing some of the entity classes and rebuilding, and have a look in the /Sql folder at the generated scripts.
You can find it at http://code.google.com/p/migrationscriptgenerator/

Submit this story to DotNetKicks

Sunday, 18 January 2009

Automatically serializing value objects using Fluent NHibernate

After reading James Gregory's posts on Fluent NHibernate (in particular http://blog.jagregory.com/2009/01/11/fluent-nhibernate-auto-mapping-type-conventions/) I had a quick play and came up with this.

It's very cool how FNH will generate your database for you, but sometimes you want to have a value object instead of an entity, so I have created a generic class you can use which will serialize an object into a field automatically, so add something like this to your FNH conventions.

.WithConvention(c => c.AddTypeConvention(new AutoTypeConvention<LatLng>()))

So now my class

public class Venue
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual LatLng Location { get; set; }
}

Will have the following SQL generated for it by FNH/SchemaExport

create table [Venue] (
  Id INT IDENTITY NOT NULL,
   Location NVARCHAR(MAX) null,
   Name NVARCHAR(100) null,
   primary key (Id)
)

The LatLng object will be serialized into the NVARCHAR(MAX) column automatically. Neato! Warning - you should only do this with immutable types (I think) and you might want to use a version tolerant serialization strategy in case the definition of your value type changes from the version serialized in the db. I've provided an XML serializer implementation, feel free to change it!

You can get the code from here (apologies for the file hosting)

UPDATE: The xml serializer is a bit broken - get the latest from http://refactormycode.com/codes/710-polymorphic-xml-serializer#refactor_144121

Submit this story to DotNetKicks

Monday, 27 October 2008

Announcing SimpleScriptRunner - a very basic migrations tool

Just thought I'd share a very basic tool called SimpleScriptRunner. Its basically just something for running a directory of numbered SQL scripts against a SQL Server database for migrations, using the syntax

SimpleScriptRunner.exe <server> <database> <path to sql scripts>
I like to call it from a post build event in a VS project like so:
SimpleScriptRunner .\sqlexpress $(SolutionName)Db $(ProjectPath) 
If the database doesn't already exist, it will create it. The scripts are run in numerical order (you need to call them something like 0001 - First script.sql), and any scripts that have been already executed against the database are skipped*. 
I had been using MigratorDotNet for my migrations, and its probably a better tool as it can target databases other than SQL Server, but if you're using a lot of MS SQL Server, you might find this handy.
You can find it here on google code.
*actually if you modify the most recent script, it will re-execute it. This is a good thing when you are developing.

Submit this story to DotNetKicks

Monday, 14 July 2008

LinqtoDBMLRunner improvements

I've made a couple of improvements. Generally you want to make a couple of changes to an element in the xml file once you've selected it. The Apply extension method allows you to chain changes together so you don't need to keep reselecting objects e.g.

root.Table("People")
    .Apply(table => table.Member = "Persons")
    .Apply(table => table.Type
                        .Apply(type => type.Name = "Person")
    );

The next improvement is a method to automatically recognise single table inheritance from the database, if, of course, you stick to the convention.

Image you have a table defined with the following SQL. The underscores in the column names are used to indicate that the column should belong to a subclass.

CREATE TABLE [dbo].[Device](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [DeviceType] [int] NOT NULL,
    [Mouse_NumberOfButtons] [int] NULL,
    [Keyboard_NumberOfKeys] [int] NULL,
    [Keyboard_WirelessKeyboard_Frequency] [decimal](19, 5) NULL,
)

You can then add the line below to your DbmlRunner script

root.ExtrapolateSubclasses();

This will rearrange your Dbml mappings to give the correct inheritance, as in the diagram below

DbmlMappings

This lets you very quickly and easily add new subclasses without having to do any real dbml scripting. A word of warning. It generates the inheritance modifier value for the subclass based on the order the columns appear in the system. If you remove a subclass and its columns once you have data in the system, you'll probably want to manually script the inheritance modifier values yourself. I might make it run off a named enum in the future, theres an idea...

Submit this story to DotNetKicks

Tuesday, 3 June 2008

Try-catching in a single line of code

Do you like reducing your line count at the expense of readability to others? Then you'll like this!

public static class FuncExtensions { public static TResult Catch<TExc, TResult>(this Func<TResult> func, Func<TExc, TResult> handleException) where TExc : Exception { try { return func(); } catch (TExc ex) { return handleException(ex); } } }

This lets you write things like:

int x = new Func<int>(DoSomething).Catch((NullReferenceException e) => -1);
instead of
int y; try { y = DoSomething(); } catch (NullReferenceException ex) { y = -1; }


You can of course write overloads for Funcs that take more than one parameter.

Edit: I've written a version that lets you chain catches but I'm not sure if its better or not...

int x = new Func<int>(DoSomething) .Catch((NullReferenceException e) => -1) .Catch((NotImplementedException ex) => -2)();

Submit this story to DotNetKicks

Monday, 2 June 2008

storing ViewState in memcached - the ultimate post

The HttpModule for storing memcached in the ViewState is dead - I discovered that you can far more easily intercept ViewState using a custom PageAdapter. Please go to http://code.google.com/p/memcached-viewstate/ for frictionless memcached viewstate goodness! Hopefully this is the end of the matter :)

Submit this story to DotNetKicks