RSS
 

Archive for September, 2008

Build yourself a portable Dependency Injection container

30 Sep

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;
        }
    }
}
 
2 Comments

Posted in .Net

 

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

30 Sep

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!

 
8 Comments

Posted in How To

 

Super-Easy String to Anything

10 Sep

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

 
2 Comments

Posted in .Net

 

Building Dependable code with Dependency Injection – Slides & Source

02 Sep

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.

 
4 Comments

Posted in .Net, Testing