Reputation: 79
The given function returns a KPI value, first it checks its cache, then it performs its logic, caches the result and returns a value, handling a failure condition.
How am I best to re-use the caching, error handling logic. What I essentially want to create is a function that just performs the necessary logic with boiler plate code abstracted away and re-used across multiple similar functions.
public static int CurrentEmployees()
{
if (HttpRuntime.Cache["CurrentEmployees"] == null)
{
try
{
int CurrentEmployees = Employee.Load().Count(x => x.DateFinished == null && !x.Contractor && x.DateStarted < DateTime.Now);
HttpRuntime.Cache.Insert("CurrentEmployees", CurrentEmployees, null, DateTime.Now.AddMinutes(20), new TimeSpan(0, 10, 0));
return CurrentEmployees;
}
catch(Exception e)
{
//TODO: Report this
return -1;
}
}
else
return (int)HttpRuntime.Cache["CurrentEmployees"];
}
As the boilerplate code is wrapped around the logic it is difficult for me to simply push these into other function calls.
Upvotes: 1
Views: 212
Reputation: 171
Agree with answer from @DLeh but I would write it like this:
public static class HelperFunctions
{
public static Func<T> Cache<T>(this Func<T> inner, string cacheName)
{
return () =>
{
if (HttpRuntime.Cache[cacheName] == null)
{
var result = inner();
HttpRuntime.Cache.Insert(cacheName, inner(), null, DateTime.Now.AddMinutes(20), new TimeSpan(0, 10, 0));
return result;
}
return (T)HttpRuntime.Cache[cacheName];
};
}
public static Func<T> OnError<T>(this Func<T> inner, Func<Exception, T> onError)
{
return () =>
{
try
{
return inner();
}
catch (Exception e)
{
return onError(e);
}
};
}
}
Usage:
public static class Employees
{
public static int CurrentEmployees()
{
return (new Func<int>(() => Employee.Load().Count(x => x.DateFinished == null && !x.Contractor && x.DateStarted < DateTime.Now)))
.Cache("CurrentEmployees")
.OnError(e => -1)
();//TODO: log?
}
}
This way we separate caching logic from error handling (following single responsibility principle) and are able to reuse/compose each separately. So when you add another function like this you won't have to change Caching function.
Upvotes: 0
Reputation: 24395
Here's how you could create a generic method to cache whatever you want and reuse this logic.
public static T Cache<T>(string key, Func<T> loadFunction, Func<T> errorHandler)
{
if (HttpRuntime.Cache[key] == null)
{
try
{
T value = loadFunction();
HttpRuntime.Cache.Insert(key, value , null, DateTime.Now.AddMinutes(20), new TimeSpan(0, 10, 0));
return value;
}
catch(Exception e)
{
//TODO: Report this
return errorHandler();
}
}
else
return (T)HttpRuntime.Cache[key];
}
Usage:
public static int CurrentEmployees()
{
return Cache<int>("CurrentEmployees",
() => Employee.Load().Count(x => x.DateFinished == null && !x.Contractor && x.DateStarted < DateTime.Now),
() => -1);
}
Upvotes: 3