Sunday, April 19, 2020

Refactoring a Legacy .Net/C# - Replace Service Locator with Dependency Injection (Autofac) - Without breaking old code


I recently had the opportunity to add Dependency Injection into a 25yr old .Net Application. Now, I'm sure your saying to yourself, ".Net hasn't been around 25 yrs!"... well this application started life with C++/MFC (consisting of a few hundred CDialogs). Then, 15 years ago, it was halfway ported to C#/Winforms keeping most all Dialogs as CLI/MFC with some re-done in C#.

During this port, a home brew Inversion of Control (IoC) was created. This used the service locator (SL) pattern - basically, you ask it for an interface/type/service and it returns to you one that was registered to the system. Based off the framework's built-in IServiceProvider class. Now, this class doesn't do a whole lot, basically just provides a GetService(Type) method

There are many articles on pros and cons of DI vs SL supporting one or the other. But, I believe today's view is that SL is an anti-pattern (one example, Wikipedia page) because it hides you from knowing what dependencies are needed by the class, and hopefully they are registered with the system properly when calling the class. Although, pretty much all IoC's supporting injection also support manually resolving a reference - some times, you just have to do things not pretty 😀.

With the SL system in our app, I've found that Unit Testing is always extremely very tedious, and error prone. Partly because of the design of our system, also because you do not know what dependencies all the classes require - so mocking them is error prone. I can say passing all needed interfaces as part of a constructor certainly makes unit test setup easier. And during actual application runtime, have the IoC system inject all the services and manage lifetimes of shared resources is great.

So, my first goal was to find a modern, open source (having code is great when a tech becomes no longer popular/supported) IoC/DI platform for .Net. My second goal, was being able to have both the existing SL and the new DI system peacefully coexist. Needed to not break thousands of lines of code leading to runtime crashes trying to resolve dependencies.

After a bit of research, settled on Autofac. It had nice syntax, plenty of flexibility, and checked all the boxes.

Having old SL types resolve in new system (for both DI and SL)

Autofac supports numerous ways to register types into its registry. In this case, I already had a SL that could be use to find types, so the best way to get Autofac to see these types was to use RegisterSource builder method. Now, old resolver services can be Injected when Autofac creates services. Any types registered to Autofac are not found in older resolver (intentionally - moving away from it). And all existing code works without change. Take a look at the code below:

 

Tuesday, April 14, 2020

Retrospective

It has been a few years since I've had any kind of blog (10yrs+). The last info posted was really about OIS work. That has since been released to other maintainers.

Been an interesting and busy decade: raising two children - as well as a couple dogs (and several fish) - learning guitar, growing professionally, purchasing a house, a few road trips, and mostly enjoying life.

Has also been quite some time since I have contributed anything substantial to Open Source - though, I do make use of many tools, projects, Python/Nuget/NPM/etc modules, frameworks - every single day in my day job. Looking to get back into the area of contributing to Open Source as well as perhaps helping aspiring developers get started.

Looking to start small, for now, as time permits. Am looking to contribute back by writing various software articles on topics that have great interest to me or things that I have had to spend time researching and have a solution for that could save others time (topics such as business software, game dev, automation, python, dotnet core, etc).

With the recent turn in world events - that is both scary and unsettling - both in terms of family and friends' health, as well as everybody else's health - please stay safe out there! But also in terms of the economic health and everybody's financial future. Though, while on lock down in the Golden State, definitely will make full use of the time provided to get back in the game.

WinForms DataGridView with Appium/WinAppDriver (Python)

I recently spent some time trying to get the DataGridView of Winforms working (well enough) with Appium. The exposed properties (visible via...