Use T4 code generation to add INotifyPropertyChanged to ADO.Net Data Services (Astoria) Entities

By Rob on Thursday, March 26, 2009

3 Comments

Filed Under: .Net

The current version of ADO.Net Data Services (Astoria) for Silverlight generates some extremely Plain Old CLR Objects. As Shawn Wildermuth notes, you dont even get INotifyPropertyChanged support. You might need this if you want to databind directly to your Astoria entities, but if you’re doing serious Silverlight work, it pays to wrap your entities up in a ViewModel. Even if you’re doing this, having INotifyPropertyChanged support can really help - for example, instead of saving every single entity on your model, you only need to fire the ones that change. For example:

entity.PropertyChanged += (sender, e) => dataContext.UpdateObject(sender);

Pretty soon, this functionality will be built into Astoria. In the meantime, however, it’s possible to add this functionality thanks to the partial methods in the web reference-generated entity. When you add an Astoria web reference to a silverlight project, the two most interesting things that get added (expand the service reference to see these files) are:

Reference.cs

This is the C# file that contains all of the code relating to the service reference. Look inside and you will see your DataContext and all of your Entities. Note that your entities don’t fire property changed events, but they do define partial methods:

        
    public string City
    {
        get
        {
            return this._City;
        }
        set
        {
            this.OnCityChanging(value);
            this._City = value;
            this.OnCityChanged();
        }
    }
    private string _City;
    partial void OnCityChanging(string value);
    partial void OnCityChanged();

service.edmx

This is an XML file that defines, among other things, each of the entities in your service reference:

      <EntityType Name="Address">
        <Key>
          <PropertyRef Name="ID" />
        </Key>
        <Property Name="ID" Type="Edm.Int32" Nullable="false" />
        <Property Name="Line1" Type="Edm.String" Nullable="true" />
        <Property Name="Line2" Type="Edm.String" Nullable="true" />
        <Property Name="City" Type="Edm.String" Nullable="true" />
        <Property Name="Country" Type="Edm.String" Nullable="true" />
      </EntityType>

This XML file serves as the perfect source for our data generation template!

DataServiceINotifyPropertyChanged

If you’re not familiar with T4 code generation and it’s integration into visual studio, now would be a good time to go and read Oleg Sych’s blog - he covers EVERYTHING. Or you could just go ahead and incorporate my template into your Silverlight project - it works on my machine! 

In order to make the namespace of the generated file match the namespace of your service classes, you need to put this template into a top level folder that matches the name of your service reference. The template will use that directory name to find the edmx file in question:

T4 Template

 

Basically, the template loops over all the entities in the edmx, generates a partial class (which will match the service entities), then loops over all the properties and generated a partial method implementation. Easy?

Download the template file here. You might have to change the extension from txt to tt…

Visualising Data with Dot (Part 2 of 4)

By Rob on Wednesday, March 11, 2009

0 Comments

Filed Under: Dot

Welcome back to my four part series on Dot. In this installment, I go deeper on some of the options available regarding layout of Dot graphs.

Part 2: More Dot layout

I’m not sure that I can add value beyond what’s already available in the documentation - its simple, clear and concise. What I will do, however, is call out the things that I found most useful:

Colours, fonts and shapes (oh my?)

You have full control over the following layout attributes:

You could imagine modifying the sql that I demonstrated in part 1 to also select out some colour / formatting attributes into the nodes and edges. Another options is to generate your Dot code in an application layer - since ruby, C# or java are more expressive with SQL it’s a bit easier to generate some really interesting graphs.

HyperDot: URLs and Tooltips

Did you know that Dot can generate more than just image files? The Dot syntax supports adding tooltips and URLs into nodes, edges, and even arrowheads. However, there’s no way for this kind of information to be embedded into a gif, png or jpeg. Currently, the output formats that will let you see these are:

  • SVG, which is natively supported by all browsers except for the most important one, is a web-aware xml based vector format (that is soon to be superseded by XAML). In firefox, for example, you could be viewing a graph that will hyperlink you to the appropriate web page when you click on an item on the graph. 
  • HTML ImageMaps are elements that you can use to tack urls and tooltips onto specific areas of an image in a webpage. If you run Dot twice against the same piece of Dot code (but with different output formats), you can create the imagemap code that corresponds perfectly to the pixels drawn on the image. In Part 4, I will be talking further about how to achieve this in an ASP.Net web server. This functionality replicates what SVG provides you (without the pretty vector scaling, but with superb browser compatibility).  

Personally, I am hoping that someone will champion the Silverlight cause and write a native XAML output format for Dot :). I have experimented with a couple of SVG to XAML converters, both XSLT files, but neither of them get the layout just right.

Next in this series: how to call into Dot from a .Net web server to dynamically generate server side images.

Getting started with iPhone development

By Rob on Sunday, December 28, 2008

3 Comments

Filed Under: How To

My wife and I have recently been trying to build a simple game on the iPhone. Neither of us have tried to do any Mac development before, so it was a little bit of a challenge just working out where to start. Here’s some tips on where to go if you’re a beginner like us.

You will need:

  • A computer running the latest version of OSX (like a Mac)
  • XCode (the Apple IDE) installed on your OSX (This comes on the OSX install CDs, but not usually on the Mac itself)
  • Some internet (such as the one you’re using to read this blog)
  • An iPhone or iPod touch (although you can get quite far just using the simulator)
  • The iPhone SDK. Once you install this, XCode will be able to create iPhone projects. It also comes with a simulator and all sorts of performance testing tools. You’ll need to register as an iPhone developer before you can download this (or a number of other things I’m linking to), but you don’t have to fork out $99 until you want to deploy your app to an iPhone.

Apple have 11 introductory videos available on the iPhone development homepage. The first few I would recommend as mandatory, the others you should watch if they look interesting.

These links will help you to learn Objective C (The language you’ll be developing in):

One blog that I’ve found very useful is Mobile Orchard

The most important thing that I recommend doing is downloading Apple’s sample code and stepping through that. Playing with some sample code and seeing what changes are effected was probably what taught us the most. There’s a gallery of UIElements to browse through the different controls that apple provide, as well as examples of using the more complex input hardware that the iPhone provides, like GPS and the accelerometers.

Please leave a comment if you’ve got any further suggestions - I’ll add them to the list!

Visualising Data with Dot (Part 1 of 4)

By Rob on Friday, November 14, 2008

4 Comments

Filed Under: Dot

Welcome to part one of a four part series on getting some sweet visualisations of workflows, using the open source digraph tool “Dot”. This first post will be about dot’s DSL (which rocks), and how to generate it. Part two will look at some advanced styling and layout. Parts 3 and 4 will be about ways to publish this data over the Internet (Dot is a command line tool).

Dot’s input language is very simple. Here’s an example of a digraph generated by dot:

 

And the code to create this graph was:

digraph G{ //declare a digraph, and give it a name of “G”
    node[fontname=arial]; //sets the default font for all nodes
    bismuth212->thallium208[label="36%"]; //create a labelled edge
    bismuth212->polonium212[label="64%"];
    thallium208->lead208; //create an unlabelled edge
    polonium212->lead208;
    lead208[color=gray] //set the colour for the (already declared) lead 208 node
}

You can also give labels to nodes - the following code creates exactly the same graph:

digraph G{
    node[fontname=arial];

    1[label=bismuth212]
    2[label=thallium208]
    3[label=polonium212]
    4[label=lead208,color=gray]

    1->2[label="36%"];
    1->3[label="64%"];
    2->4;
    3->4;
}

You can get more information about the Dot language at the graphviz site.

I have recently started working on a project that involves a simple workflow. This workflow is modelled in my database. I’ve simplified it a bit, but here’s my schema:

 image

And here’s my data:

State Transition
ID    Name
1    Start
2    Write test
3    Run test (red stage)
4    Write function
5    Run test (green stage)
6    Refactor
7    Run test (refactor stage)
8    Finish
ID    FromStateID    ToStateID    Description
2    1    2   
3    2    3   
4    3    2    Passed
5    3    4    Failed
6    4    5   
7    5    6    Passed
8    5    4    Failed
9    6    7   
10    7    8    Passed
11    7    4    Failed

 

Not that easy to follow, huh? And this is a very simple example.

However, if we run the following (simple) SQL:

 

DECLARE @crlf varchar(2)
SET @crlf = char(13)+char(10)

DECLARE @s varchar(max)
SET @s = '  node[fontname=arial];'+@crlf

SELECT @s=@s+'  '
    +convert(varchar,ID)
    +'[label="'+Name+'"];'
    +@crlf
FROM State

SELECT @s=@s+'  '
    +convert(varchar,FromStateID)
    +'->'+convert(varchar,ToStateID)
    +'[label="'+Description+'"];'
    +@crlf
FROM Transition

SELECT 'digraph G{'+@crlf+@s+'}'

we’ll get the following output:

digraph G{

  node[fontname=arial];

  1[label="Start"];

  2[label="Write test"];

  3[label="Run test (red stage)"];

  4[label="Write function"];

  5[label="Run test (green stage)"];

  6[label="Refactor"];

  7[label="Run test (refactor stage)"];

  8[label="Finish"];

  1->2[label=""];

  2->3[label=""];

  3->2[label="Passed"];

  3->4[label="Failed"];

  4->5[label=""];

  5->6[label="Passed"];

  5->4[label="Failed"];

  6->7[label=""];

  7->8[label="Passed"];

  7->4[label="Failed"];

}

Which we can run through the dot tool:

C:\Program Files\Graphviz 2.21\bin>dot -Tgif -ooutput.gif

output

It’s not pretty (yet), but it’s so much easier to follow than looking at numbers. Hopefully I’ve got you thinking about how you could rewrite that SQL statement to work against your own database tables.

I’ll be posting a guide to styling and laying out this Dot diagram soon - stay tuned!

How to fix a dzproj file when DeepZoom Composer has mangled your CompositionNode’s Ids

By Rob on Wednesday, October 8, 2008

1 Comment

Filed Under: How To

Warning: if you’re not into building deepzoom systems, stop reading. This post will BORE YOU. Was the title not a good enough indication?

Ok good, they’re gone!

The current release of the deep zoom composer has a little bug. Ok - it has a few bugs, but I hate this one the most. You close your DeepZoom project(*.dzproj), you open your project, and viola - your images have rearranged themselves (or just disappeared). The first thing to worry about is: have you moved your files? Deepzoom projects store file references as absolute paths, which is ridiculous, but not the problem I was having.

Tori talks about this problem on the “known issues page” for the composer.

I don’t know what causes it (language settings were mentioned on that thread - I’m using en-NZ), but if you look inside the dzproj file itself, the Ids of all the composition nodes are all wrong.

More like “Deep Zoom Confounder”!

Im sure theres a fix coming, but if you’re as desperate as me, then what you’ve got to do is this:

1) put :<filename> on the end of each image’s tag

2) run the following code across your dzproj file:

using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;

class Program
{
    static void Main(string[] args)
    {
        var file = string.Join(" ", args);

        XDocument d = XDocument.Load(file);

        var images = from i in d.Descendants("Image")
                     select Path.GetFileName(i.Element("File").Value);

        var imageList = images.ToList();

        var map = from e in d.Descendants("CompositionNode")
                  let tag = e.Attribute("Tag")
                  where tag != null
                  let fileName = tag.Value.Split(':').Last()
                  where images.Contains(fileName)
                  select new
                  {
                      Node = e,
                      NewId = imageList.IndexOf(fileName)
                  };

        foreach (var v in map)
        {
            v.Node.SetAttributeValue("Id", v.NewId);
        }

        d.Save(file);
        Console.Out.WriteLine("Press any key to continue");
        Console.ReadKey();
    }
}

This code will read in the xml, build a list of all the correct image ids, then update the ids of all your composition. Its not easy, but it’s a workaround!

Build yourself a portable Dependency Injection container

By Rob on Tuesday, September 30, 2008

0 Comments

Filed Under: .Net

It’s been too long since I promised to post this. But it’s worth it, I promise you. If you just want to grab the code, it’s at the bottom of this post.

What we have here is another do it yourself dependency injection container. I release it to you, dear world, free of charge, warranty or care.

Pros:

  • You can paste the code straight into your project - no DLL dependencies (easy to deploy, get approved, source control)
  • It won’t bulk up your silverlight application
  • It performs super-fast if you’re using it to resolve singletons
  • It can do lots of the things that the “real” DI containers can do (named parameters, value parameters, lifestyle choices)
  • It’s got a fluent interface
Cons
  • There’s a bunch of stuff that the real containers can do that mine can’t (consider this DIY container a “gateway drug”). That said, I seem to have covered three of Oren’s four basic requirements, and i think it’s pretty easy to use…
  • If you are doing a lot of transient resolves (say per each page request) you will find reflection is just too slow.
  • This version depends on LINQ and lambdas, so it’s VS 2008 only.

the tests:

[TestClass]
public class DemoContainerTest
{
    [TestMethod]
    public void NamedRegistration()
    {
        Container c = new Container();
        c.Register<IMathNode, Zero>("zero");
        IMathNode m = c.Resolve<IMathNode>("zero");
        Assert.AreEqual(0, m.Calculate());
    }

    [TestMethod]
    public void AnonymousRegistration()
    {
        Container c = new Container();
        c.Register<IMathNode, Zero>();
        IMathNode m = c.Resolve<IMathNode>();
        Assert.AreEqual(0, m.Calculate());
    }

    [TestMethod]
    public void AnonymousSubDependency()
    {
        Container c = new Container();
        c.Register<IMathNode, Zero>();
        c.Register<IFormatter, MathFormatter>();
        IFormatter m = c.Resolve<IFormatter>();
        Assert.AreEqual("$0.00", m.Format("C2"));
    }

    [TestMethod]
    public void WithValue()
    {
        Container c = new Container();
        c.Register<IMathNode, Number>("five").WithValue("number", 5);
        int i = c.Resolve<IMathNode>("five").Calculate();
        Assert.AreEqual(5, i);
    }

    [TestMethod]
    public void NamedSubDependency()
    {
        Container c = new Container();
        c.Register<IMathNode, Number>("five").WithValue("number", 5);
        c.Register<IMathNode, Number>("six").WithValue("number", 6);
        c.Register<IMathNode, Add>("add").WithDependency("m1", "five").WithDependency("m2", "six");
        int i = c.Resolve<IMathNode>("add").Calculate();
        Assert.AreEqual(11, i);
    }

    [TestMethod]
    public void NamedSubDependencyOutOfOrder()
    {

        Container c = new Container();
        c.Register<IMathNode, Add>("add").WithDependency("m1", "five").WithDependency("m2", "six");
        c.Register<IMathNode, Number>("five").WithValue("number", 5);
        c.Register<IMathNode, Number>("six").WithValue("number", 6);
        int i = c.Resolve<IMathNode>("add").Calculate();
        Assert.AreEqual(11, i);
    }

    [TestMethod]
    public void Singleton()
    {
        Container c = new Container();
        c.Register<IMathNode, Zero>().AsSingleton();
        Assert.AreSame(c.Resolve<IMathNode>(), c.Resolve<IMathNode>());
    }

    [TestMethod]
    public void NonSingleton()
    {
        Container c = new Container();
        c.Register<IMathNode, Zero>();
        Assert.AreNotSame(c.Resolve<IMathNode>(), c.Resolve<IMathNode>());
    }

    public interface IFormatter
    {
        string Format(string format);
    }

    public class MathFormatter : IFormatter
    {
        private readonly IMathNode math;

        public MathFormatter(IMathNode math)
        {
            this.math = math;
        }

        public string Format(string format)
        {
            return math.Calculate().ToString(format);
        }
    }

    public interface IMathNode
    {
        int Calculate();
    }

    public class Zero : IMathNode
    {
        public int Calculate()
        {
            return 0;
        }
    }

    public class Number : IMathNode
    {
        private int number;

        public Number(int number)
        {
            this.number = number;
        }

        public int Calculate()
        {
            return number;
        }
    }

    public class Add : IMathNode
    {
        private IMathNode m1, m2;

        public Add(IMathNode m1, IMathNode m2)
        {
            this.m1 = m1;
            this.m2 = m2;
        }

        public int Calculate()
        {
            return m1.Calculate() + m2.Calculate();
        }
    }

}

The container:

The way this bad boy works is by storing dictionary of services as “Func<object>”s. These are keyed by name, which is usually provided by the Resolve method. If the parameterless overload of resolve is used, then the service name is looked up in the dictionary serviceNames. This simply stores the first  ever registration of a service type’s name. If the nameless Register method is used, then a random name is generated.

Whenever you register a component, you get back a “dependency manager” object. That object lets you specify further configuration on your component via a fluent interface. It contains most of the logic for resolving an object, and manages the parent container’s Func<object> for resolving that dependency.

public class Container
{
    protected readonly Dictionary<string, Func<object>> services = new Dictionary<string, Func<object>>();
    protected readonly Dictionary<Type, string> serviceNames = new Dictionary<Type, string>();

    public DependencyManager Register<S, C>() where C : S
    {
        return Register<S, C>(Guid.NewGuid().ToString());
    }

    public DependencyManager Register<S, C>(string name) where C : S
    {
        if (!serviceNames.ContainsKey(typeof(S)))
        {
            serviceNames[typeof(S)] = name;
        }
        return new DependencyManager(this, name, typeof(C));
    }

    public T Resolve<T>(string name) where T : class
    {
        return (T)services[name]();
    }

    public T Resolve<T>() where T : class
    {
        return Resolve<T>(serviceNames[typeof(T)]);
    }

    public class DependencyManager
    {
        private readonly Container container;
        private readonly Dictionary<string, Func<object>> args;
        private readonly string name;

        internal DependencyManager(Container container, string name, Type type)
        {
            this.container = container;
            this.name = name;

            ConstructorInfo c = type.GetConstructors().First();
            args = c.GetParameters()
                .ToDictionary<ParameterInfo, string, Func<object>>(
                x => x.Name,
                x => (() => container.services[container.serviceNames[x.ParameterType]]())
                );

            container.services[name] = () => c.Invoke(args.Values.Select(x => x()).ToArray());
        }

        public DependencyManager AsSingleton()
        {
            object value = null;
            Func<object> service = container.services[name];
            container.services[name] = () => value ?? (value = service());
            return this;
        }

        public DependencyManager WithDependency(string parameter, string component)
        {
            args[parameter] = () => container.services[component]();
            return this;
        }

        public DependencyManager WithValue(string parameter, object value)
        {
            args[parameter] = () => value;
            return this;
        }
    }
}

How to get your iPhone on WiFi when your proxy uses NTLM (thanks to NTLMAPS)

By Rob on Tuesday, September 30, 2008

2 Comments

Filed Under: How To

I have been struggling to get my iPhone working against my corporate ISA proxy server. Once I had connected to WiFi, Safari would continually prompt me for my domain user name and password, and none of the apps would work (maybe because they didn’t know how to prompt me for credentials).

After a bit of poking around with fiddler, telnet, and all sorts of settings, I was certain that the problem was our ISA Proxy server’s NTLM authentication.

NTLM is an authentication mechanism from Microsoft. Microsoft’s ISA Proxy Server uses NTLM to be able to tell which active directory user is attempting to access the internet.

If you’re surfing with Internet Explorer, it picks up your username directly from your login, and you might not even realise that IE is authenticating you. If you’re using firefox, you might get prompted the first time you go on the internet. As far as I can tell, Google Chrome prompts you each time you launch it.

If you’re trying to get online with an iPhone, you’re not so lucky. Safari will prompt you for credentials every time you change domains (actually, I’m pretty impressed that it can authenticate at all - nice work Apple, don’t give up!). This gets tiresome. Whats more, anything else that wants to use the internet from your iPhone has no chance.

iPhone and ISA don’t play nicely

So how do we get around this? It’s not easy. It has the potential to let other people leech your personal bandwidth and get you into trouble, if you don’t do it right. But I HAD to get online, so i started writing my own proxy server that would “chain” to ISA. It would be capable of hiding the NTLM authentication from whatever system was using it as a proxy, and then providing a preconfigured username and password to ISA “up” the chain. In order to keep my login safe from other people who could just use my proxy server, I would have locked down which IP addresses could use my proxy server.

As it turns out, someone’s already built an “NTLM Authorization Proxy Server”, and thoughtfully called it “NTLMAPS“. It’s written in python, and it works perfectly. It even has a feature to lock down IP addresses, which I strongly recommend you use.

NTLMAPS hides ISA’s nastiness from the iPhone

So how to get started? I installed NTLMAPS on my workstation - you’ll need administrative rights.

  1. Install Python from http://www.python.org/download/
  2. Unzip the NTLMAPS release from https://sourceforge.net/project/showfiles.php?group_id=69259&package_id=68110&release_id=388621
  3. Edit the server.cfg file. You will need to change the following keys
    • PARENT_PROXY - your ISA proxy server
    • PARENT_PROXY_PORT - your ISA proxy port
    • ALLOW_EXTERNAL_CLIENTS - set this to 1 to allow yourr iphone to connect
    • FRIENDLY_IPS - put your iPhone’s current wifi IP here unless you want to let everyone on your account! You’ll have to change this a lot.
    • NT_DOMAIN
    • USER
    • PASSWORD - you can leave this blank if you want - every time you start the server it will prompt you.
  4. Edit the batch file so that it points to the correct python.exe
  5. Launch the batch file. You’ll now have the NTLMAPS proxy server up & running. It will tell you the hostname and the port. If you’ve got a firewall going, and you’re lucky, the firewall will ask if you want to unblock that port.
  6. Make sure that whatever firewall you’ve got installed allows incoming connections to NTLMAPS
  7. Setup your iPhone to use your own computer as a proxy. You can do this in settings>general>network>wifi>your current wifi network. You can turn authentication off, but the server and the port (under manual proxy) should be what ntlmaps have told you to use.

There! you should be good to go. You can make sure your iPhone is getting its internet through wifi by temporarily changing your cellular data gateway to something incorrect. Google maps, the app store, weather, they should all start working once you’ve done this, as long as NTLMAPS is running.

Let me know how it goes!

Super-Easy String to Anything

By Rob on Wednesday, September 10, 2008

1 Comment

Filed Under: .Net

I don’t think I’ve seen a single project without some form of string parsing: int.Parse(txtName.Text), anyone?.

Here’s a cool way to take a string and parse it to whatever you want, enum, double, bool, it works on anything that’s both IConvertible and a struct (ok I lied about “anything”). It’s an extension method, but could just be a library call if that pleases you (or your compiler) more.

 

public static T? As<T>(this string s) where T : struct, IConvertible
{
    try
    {
        Type type = typeof(T);
        bool isEnum = typeof(Enum).IsAssignableFrom(type);
        return (T)(isEnum
            ? Enum.Parse(type, s, true)
            : Convert.ChangeType(s, type));
    }
    catch
    {
        return null;
    }
}

Note that it just returns null if the parse fails - this actually ends up being really simple to use:

  • If you KNOW the parse shouldn’t fail, you just call .Value - which will give you an exception if the parse somehow did fail (this is a good thing)
  • If you want to see if the parse failed, you can check the .HasValue property
  • If you want to provide a fallback value, you can just use the ?? operator


Here are the TDD tests for the code, to give you idea of how flexible this is:


[TestMethod]
public void StringAsInt()
{
    Assert.AreEqual(5, "5".As<int>());
    Assert.AreEqual(25, "25".As<int>());
    Assert.AreEqual(null, "foobar".As<int>());
}

[TestMethod]
public void StringAsDouble()
{
    Assert.AreEqual(5.5, "5.5".As<double>());
    Assert.AreEqual(-25.2, "-25.2".As<double>());
    Assert.AreEqual(null, "foobar".As<double>());
}

[TestMethod]
public void StringAsBool()
{
    Assert.AreEqual(true, "true".As<bool>());
    Assert.AreEqual(false, "false".As<bool>());
    Assert.AreEqual(null, "foobar".As<bool>());
}

[TestMethod]
public void StringParseEnum()
{
    Assert.AreEqual(ContactPreference.Email, "Email".As<ContactPreference>());
    Assert.AreEqual(null, "Schmemail".As<ContactPreference>());
    Assert.AreEqual(null, ((string)null).As<ContactPreference>());
    Assert.AreEqual(ContactPreference.MobilePhone, "MobilePhone".As<ContactPreference>());
}
enum ContactPreference
{
    Email,
    MobilePhone
}

Enjoy! - Rob

Building Dependable code with Dependency Injection - Slides & Source

By Rob on Tuesday, September 2, 2008

4 Comments

Filed Under: .Net, Testing

Here are my slides and the source code to the TDD & DI talk I gave at CodeCamp Auckland 2008. My intent with the talk was to explain how TDD can be really good, and how DI can make TDD easier.

If you weren’t at my talk and have any questions - I’m in the market for more comments.

I’ve got one more link to add, these podcasts were what actually inspired my subject: http://channel9.msdn.com/shows/ARCast+with+Ron+Jacobs/ARCastnet-Presenter-First-Pattern-Part-1/

Here is my source code (perfectly commented), and here are my slides

Stay tuned for a bigger (50 line) do-it-yourself DI container that would be useful in production.

Best Codecamp Evar

By Rob on Sunday, August 31, 2008

2 Comments

Filed Under: .Net, Me

Wow - just attended the best codecamp ever. It’s gotten me so excited about silverlight, wpf and asp mvc. Jonas, who’s girlfriend is a silverlight designer, has some really great insights into how to do some funky silverlight stuff, go read his blog. I was also pretty impressed by Scott’s speaking style - he was a LOT funnier than I expected.

The fact that I got to speak wasn’t what made the day so great for me. No - it was the content of the other speakers and having such interesting conversations with everyone else who came. The people that turn up to these community things are the ones who really care about what they do.

My slides & source will go up here very soon I promise! I just have one thing to ask you guys: If you came to my talk, I’d love to get some feedback about how my presentation went. One of my colleagues told me I need to walk around a lot more - so thats some good advice for me to take on board. But I want to grow up to be a fantastic presenter one day, so please, leave me a comment or send me an email. All criticism will be gratefully, gracefully received. Unless you weren’t actually there.