Pages

Friday, December 7, 2012

Poor Man's IOC

Background:


I maintain a white label chat site written in .NET MVC 4 for our company, and
today i was refactoring a standalone dll that contains tons of the RESX files which enable us to decline the site into many different languages.

The twist is that there are many places in the translations where i want to be able to replace entries with variables instead of the usual string translation facilities that RESX files provide.
Welcome to [[Brand]]
Visit [[Domain]]
{0} is not a valid value for {1}
To do this i use T4Resx, which enables me to transform all RESX files into a huge .cs file (then a dll), and can invoke the translations in my .cshtml files with
@Resources.User.Age
bind them to a ViewModel with
[Display(Name = "Age", ResourceType = typeof(Resources.User.Age))]
or print out formatted messages
 @Resources.User.AgeInvalid(33, "ageTextBox")

 public string GetAgeError(int age, string element) {
    return Resources.User.AgeInvalid(age, element);
 }


Problem:


The replacement function i was using resides in another DLL. At the moment i simply added a reference of that DLL to my RESX project and all was fine.

But while i was refactoring, i wanted to add a reference of my RESX project to the DLL that contains the replacement function, because i wanted to start using certain translations on ViewModels and the like.

However when i compiled the project, i got a nice error about circular references, arg !

...of course i should have seen that coming.


Solution:


At first i started thinking, oh god ..now i'm gonna have to add some IOC magic, which implies adding more dependencies to my projects. Nothing against IOC libraries in general, just the fact that i simply hate dependencies.

So i started running around looking at the usual IOC libraries (Ninject, Unity, Windsor, StructureMap ..)  out there, since up to now i never really had the need to resort to any type of IOC in my projects.

While looking at those libraries, it still bothered me to think of having to add extra dependencies because of a stupidly simple replacement function, when it hit me that we have Func<> in .NET !

So after a bit of testing, i came up with the following scenario:


In my RESX project i declare:

public static Func<string, string> GetReplacement = key => key;


And still in the RESX project i now call my replacement function with:

Utilities.GetReplacement("somevalue");


Now as long i don't set up the bindings GetReplacement() will simply return the value that was passed to it. However i can now remove the dependency of the project that was providing me with the original replacement function from my RESX project. And can also add my RESX project to the project i originally wanted to add it to, without getting circular reference errors.


The replacements actually take place on the website, so that's where i will want to setup the bindings for my replacement function. And it couldn't be easier :


In my global.asax, inside Application_Start(), i simply declare the following:

Resources.Utilities.GetReplacement = (c => DBController.Current.GetReplacement(c));

The replacement function inside the RESX project is now bound to another replacement function that can access a Database and return all my replacements.


No IOC library, no dependencies ..and i'm really really happy now :)