How to create method extensions but inject into them with IoC
-
Hi all Here is my conundrum: I have a helper class/function that says if a date is a working day. It does this by reading in the holidays from the database and checking the date against weekends, and then holidays. It holds the holidays in a dictionary keyed by date for quick lookup and caching. It is passed an interface to a holiday repository in the ctor and everything is injected via Castle Windsor ctor injection from a root entity. It needs to be an in-memory cache and readily accessible as it is used a lot. So far so good. How would you go about making this a static extension method to DateTime? (Since you can’t inject to static classes…) The basic problem is, can you pass stuff into an extension method using CW? Or am I stuck with injection all the way and no statics, and therefore no extension methods? I came up with a hack that uses a collection in the static helper class, and gets set with the holiday cache beforehand, but it just seemed a bit klunky... Thanks in advance for any ideas...
-
Hi all Here is my conundrum: I have a helper class/function that says if a date is a working day. It does this by reading in the holidays from the database and checking the date against weekends, and then holidays. It holds the holidays in a dictionary keyed by date for quick lookup and caching. It is passed an interface to a holiday repository in the ctor and everything is injected via Castle Windsor ctor injection from a root entity. It needs to be an in-memory cache and readily accessible as it is used a lot. So far so good. How would you go about making this a static extension method to DateTime? (Since you can’t inject to static classes…) The basic problem is, can you pass stuff into an extension method using CW? Or am I stuck with injection all the way and no statics, and therefore no extension methods? I came up with a hack that uses a collection in the static helper class, and gets set with the holiday cache beforehand, but it just seemed a bit klunky... Thanks in advance for any ideas...
Uh, am I missing something obvious?
public static bool IsWorkingDay(this DateTime dt){
// whatever
return false; // I'm on CP, of course I'm not working :)
}permits
bool shouldIBeWorking = DateTime.Now.IsWorkingDay();
(Is it possible to have extension properties? I don't think so, right?) This is completely independent of dependency injection and as long as the extension method is visible in the place you're trying to use it (i.e. in the same assembly, or a referenced assembly, and you have a using statement for the class that defines it) it should work anywhere.
-
Uh, am I missing something obvious?
public static bool IsWorkingDay(this DateTime dt){
// whatever
return false; // I'm on CP, of course I'm not working :)
}permits
bool shouldIBeWorking = DateTime.Now.IsWorkingDay();
(Is it possible to have extension properties? I don't think so, right?) This is completely independent of dependency injection and as long as the extension method is visible in the place you're trying to use it (i.e. in the same assembly, or a referenced assembly, and you have a using statement for the class that defines it) it should work anywhere.
I'll try again with an example: Here is the current naive implementation:
public static class DateExtension { static readonly Dictionary<DateTime, Holiday> Dict; static DateExtension() { Dict = new Dictionary<DateTime, Holiday>(); } public static void SetHoliday(Holiday holidayToAdd) { Dict.Add(holidayToAdd.Date, holidayToAdd); } public static bool IsWorkingDay(this DateTime dateToCheck) { if (dateToCheck.DayOfWeek == DayOfWeek.Saturday || dateToCheck.DayOfWeek == DayOfWeek.Sunday) { return false; } return !Dict.ContainsKey(dateToCheck); } } /// <summary> /// This is the Holiday entity pulled from DB using NH or similar... /// </summary> public class Holiday { public virtual DateTime Date { get; set; } public virtual string Description { get; set; } }
To use this, you have to stuff the DateExtension with the holidays first
Holiday hol = new Holiday {Date = new DateTime(2012, 1, 2), Description = "NYD 2012"};
DateExtension.SetHoliday(hol);So you would use it like this:
DateTime dt = new DateTime(2012, 1, 2);
Debug.Assert(!dt.IsWorkingDay());
dt = dt.AddDays(1);
Debug.Assert(dt.IsWorkingDay());Now, the question is about, how can I nicely get CW to instantiate the holidays into the static extension, without doing something like this:
var holRep = _container.Resolve<IHolidayRepository>();
DateExtension.SetAllHolidays(holRep.All());In other words, can anyone think of a way to do this automatically within CW by simply registering the static class DateExtension in CW and have it inject the repository for me? Thx
-
I'll try again with an example: Here is the current naive implementation:
public static class DateExtension { static readonly Dictionary<DateTime, Holiday> Dict; static DateExtension() { Dict = new Dictionary<DateTime, Holiday>(); } public static void SetHoliday(Holiday holidayToAdd) { Dict.Add(holidayToAdd.Date, holidayToAdd); } public static bool IsWorkingDay(this DateTime dateToCheck) { if (dateToCheck.DayOfWeek == DayOfWeek.Saturday || dateToCheck.DayOfWeek == DayOfWeek.Sunday) { return false; } return !Dict.ContainsKey(dateToCheck); } } /// <summary> /// This is the Holiday entity pulled from DB using NH or similar... /// </summary> public class Holiday { public virtual DateTime Date { get; set; } public virtual string Description { get; set; } }
To use this, you have to stuff the DateExtension with the holidays first
Holiday hol = new Holiday {Date = new DateTime(2012, 1, 2), Description = "NYD 2012"};
DateExtension.SetHoliday(hol);So you would use it like this:
DateTime dt = new DateTime(2012, 1, 2);
Debug.Assert(!dt.IsWorkingDay());
dt = dt.AddDays(1);
Debug.Assert(dt.IsWorkingDay());Now, the question is about, how can I nicely get CW to instantiate the holidays into the static extension, without doing something like this:
var holRep = _container.Resolve<IHolidayRepository>();
DateExtension.SetAllHolidays(holRep.All());In other words, can anyone think of a way to do this automatically within CW by simply registering the static class DateExtension in CW and have it inject the repository for me? Thx
Ah, okay, now I see the problem. The easiest way is to register in reverse, i.e. pass a container to the extension class:
static class DateExtensions {
static IUnityContainer container;
static HolidayHandler handler;public static void RegisterHolidayHandler(IUnityContainer container){
container.Register<HolidayHandler, HolidayHandler>();
this.container = container;
}public static bool IsHoliday(){
if(handler == null) handler = container.Resolve<HolidayHandler>();
// etc
}class HolidayHandler {
internal List<Holidays> holidays;
public HolidayHandler(EntityContext context){
holidays = context.GetHolidays();
// or however your lookup classes work
// EntityContext can be got from IoC
}
}
}If you want some syntactic tidyness then of course RegisterHolidayHandler can itself be an extension method. If you don't want to have a dependency on the dependency injection framework here (and I don't think you do, really), you need to give the extension class a property (of type IHolidayHandler or something) and explicitly assign an instance of a subclass which is populated by IoC. This is essentially 'loading the holidays' but with the mechanics of it abstracted and hidden away. That is pretty much what you say you don't want to do. I can't think of a clever way without having to do, at least,
DateExtensions.HolidayRepository = _container.Resolve<IHolidayRepository>();
-
Ah, okay, now I see the problem. The easiest way is to register in reverse, i.e. pass a container to the extension class:
static class DateExtensions {
static IUnityContainer container;
static HolidayHandler handler;public static void RegisterHolidayHandler(IUnityContainer container){
container.Register<HolidayHandler, HolidayHandler>();
this.container = container;
}public static bool IsHoliday(){
if(handler == null) handler = container.Resolve<HolidayHandler>();
// etc
}class HolidayHandler {
internal List<Holidays> holidays;
public HolidayHandler(EntityContext context){
holidays = context.GetHolidays();
// or however your lookup classes work
// EntityContext can be got from IoC
}
}
}If you want some syntactic tidyness then of course RegisterHolidayHandler can itself be an extension method. If you don't want to have a dependency on the dependency injection framework here (and I don't think you do, really), you need to give the extension class a property (of type IHolidayHandler or something) and explicitly assign an instance of a subclass which is populated by IoC. This is essentially 'loading the holidays' but with the mechanics of it abstracted and hidden away. That is pretty much what you say you don't want to do. I can't think of a clever way without having to do, at least,
DateExtensions.HolidayRepository = _container.Resolve<IHolidayRepository>();
Thanks BobJanova. Isn't passing around a reference to the container an anti-pattern? Anyway, I'm specifically trying to avoid directly calling resolve against any repositories, as I want all the plumbing to be automatic through ctor/field injection. Which you can't (apparently) do with statics, and CW. Hmmm.... Rgds
-
Thanks BobJanova. Isn't passing around a reference to the container an anti-pattern? Anyway, I'm specifically trying to avoid directly calling resolve against any repositories, as I want all the plumbing to be automatic through ctor/field injection. Which you can't (apparently) do with statics, and CW. Hmmm.... Rgds
Yes, I suspect it is, which is why I suggest doing it the other way. I'm pretty sure you can't do property/field injection on a static because there is no point at which an instance of it is created by the container and passed to something else. Obviously you can't do constructor parameter injection. Personally I don't like dependency injection much and consider the whole field something of an anti-pattern so perhaps I'm not the ideal person to be trying to help you ;)