I am using a cache item as described by https://blog.falafel.com/working-system-runtime-caching-memorycache/
However I need to develop a number of implementations of this class which use different tables within the ConsentDataContext item.
This class is a static, so I either need to change it to a singleton and then inherit from an abstract with GetItem and AddOrGetExisting methods defined. Or create two separate classes and use reflection to return the correct instance.
What would be the best way of solving this problem?
Implementation 1
public static class Consent1Cache
{
private static MemoryCache _cache = new MemoryCache("ConsentType1Cache");
public static object GetItem(string key)
{
return AddOrGetExisting(key, () => InitItem(key));
}
private static T AddOrGetExisting<T>(string key, Func<T> valueFactory)
{
var newValue = new Lazy<T>(valueFactory);
var oldValue = _cache.AddOrGetExisting(key, newValue, new CacheItemPolicy()) as Lazy<T>;
try
{
return (oldValue ?? newValue).Value;
}
catch
{
// Handle cached lazy exception by evicting from cache.
_cache.Remove(key);
throw;
}
}
public static string InitItem(string consentNumber)
{
using (DLL.ConsentDataContext db = new DLL.ConsentDataContext())
{
return db.vw_ConsentType1.Where(x => x.ConsentNumber == consentNumber).Select(c => c.ConsentNumber + " - " + c.Proposal).FirstOrDefault();
};
}
}
Implementation 2
public static class Consent2Cache
{
private static MemoryCache _cache = new MemoryCache("ConsentType2Cache");
public static object GetItem(string key)
{
return AddOrGetExisting(key, () => InitItem(key));
}
private static T AddOrGetExisting<T>(string key, Func<T> valueFactory)
{
var newValue = new Lazy<T>(valueFactory);
var oldValue = _cache.AddOrGetExisting(key, newValue, new CacheItemPolicy()) as Lazy<T>;
try
{
return (oldValue ?? newValue).Value;
}
catch
{
// Handle cached lazy exception by evicting from cache.
_cache.Remove(key);
throw;
}
}
public static string InitItem(string consentNumber)
{
using (DLL.ConsentDataContext db = new DLL.ConsentDataContext())
{
return db.vw_ConsentType2.Where(x => x.ConsentNumber == consentNumber).Select(c => c.ConsentNumber + " - " + c.Proposal).FirstOrDefault();
};
}
}
Related
I have an ASP.NET Core Project ( Aspect-Oriented ) with In-Memory Cache and I use IMemoryCache interface for it.
I want to convert this to Redis caching...
But I noticed that In-Memory caching with IMemoryCache can keep data as "object" type.
public void Add(string key, object data, int duration)
{
_cache.Set(key, data, TimeSpan.FromMinutes(duration));
}
And when I get the value, it can bring it as object...
public object Get(string key)
{
var keyValue = _cache.Get(key); //Get method returns as string
return keyValue;
}
SO , I can get the value from cache as the type of it and return it...
And when I convert it to RedisCacheManager ;
public static string ToJson(this object value)
{
var aa = JsonConvert.SerializeObject(value, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
return aa;
}
SET
public void Set(string key, object value, int duration)
{
var k = value.ToJson();
_client.GetDatabase().StringSet(key, k, TimeSpan.FromMinutes(duration));
}
GET
public object Get(string key)
{
var keyValue = _client.GetDatabase().StringGet(key); //returns as "RedisValue" type
return keyValue;
}
this returns as "RedisValue"
and while using In-Memory cache with IMemoryCache, value returns as object and would be cast to its own type (for example as "List-Product" or "List-Category" ....)
So I wasn't touching anything in that process but when I use Redis, value returns as RedisValue then it returns this value
SO I GOT AN ERROR about Casting the value to whatever I need , But I use Interceptor and don't specify the type of it..
public class CacheAspect : MethodInterception
{
private int _duration;
private IRedisCacheService _cacheManager;
public CacheAspect(int duration = 60)//Default
{
_duration = duration;
_cacheManager = ServiceTool.ServiceProvider.GetService<IRedisCacheService>();
}
public override void Intercept(IInvocation invocation)
{
var methodName = string.Format($"{invocation.Method.ReflectedType.FullName}.{invocation.Method.Name}");
var arguments = invocation.Arguments.ToList();
var key = $"{methodName}({string.Join(",", arguments.Select(x => x != null ? JsonConvert.SerializeObject(x, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }) : "<Null>"))})";
if (_cacheManager.IsAdd(key))
{
var cacheValue = _cacheManager.Get(key); //returns as object
return;
}
invocation.Proceed();
_cacheManager.Set(key, invocation.ReturnValue, _duration);
}
}
Is there ANYONE who has encountered with this situation or what can I do to deal with this ??
I have solved this problem by using Generic class "RedisCacheAspect"
public class RedisCacheAspect<T> : MethodInterception where T : class
{
private int _duration;
private IRedisCacheManager _cacheManager;
public RedisCacheAspect(int duration = 60)
{
_duration = duration;
_cacheManager = ServiceTool.ServiceProvider.GetService<IRedisCacheManager>();
}
public async override void Intercept(IInvocation invocation)
{
var methodName = string.Format($"{invocation.Method.ReflectedType.Name}.{invocation.Method.Name}");
var arguments = invocation.Arguments.ToList();
var key = $"{methodName}({string.Join(",", arguments.Select(x => x != null ? JsonConvert.SerializeObject(x) : "<Null>"))})";
if (_cacheManager.KeyExists(key))
{
var cacheValue = _cacheManager.Get(key);
var data = JsonConvert.DeserializeObject<T>(cacheValue, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
var isAsync = invocation.Method.IsReturnTask();
if (isAsync)
{
var returnValue = Task.FromResult(data);
invocation.ReturnValue = returnValue;
}
else
invocation.ReturnValue = data;
return;
}
invocation.Proceed();
var method = invocation.MethodInvocationTarget;
var isAsync2 = method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null;
if (isAsync2 && typeof(Task).IsAssignableFrom(method.ReturnType))
{
var cacheValue = await InterceptAsync((dynamic)invocation.ReturnValue);
_cacheManager.Set(key, cacheValue, _duration);
}
else
_cacheManager.Set(key, invocation.ReturnValue, _duration);
}
private static async Task InterceptAsync(Task task)
{
await task.ConfigureAwait(false);
// do the continuation work for Task...
}
private static async Task<T> InterceptAsync<T>(Task<T> task)
{
T result = await task.ConfigureAwait(false);
// do the continuation work for Task<T>...
return result;
}
}
With this class, you can use it as an attribute on a method like this;
Data : DataResult<List<CategoryDto<<
[RedisCacheAspect<DataResult<List<CategoryDto<<>(duration: 60)]
As you see I use DataResult, but you shouldn't use an Interface while caching a value. This gives you an error because Deserializing an object from Redis cache has be to be mapped to an object that you specify and interfaces cannot be mapped.
An example to RedisCacheManager;
public class RedisCacheManager : IRedisCacheManager, IDisposable
{
private readonly ConnectionMultiplexer _client;
private const string RedisDbName = "RedisCache1:";
private readonly string _connectionString;
private readonly ConfigurationOptions _configurationOptions;
public RedisCacheManager(IConfiguration configuration)
{
_connectionString = configuration.GetSection("RedisConfiguration:ConnectionString")?.Value;
var connectionStrings = _connectionString.Split(",");
_configurationOptions = new ConfigurationOptions()
{
//EndPoints = { aa.ToString() },
AbortOnConnectFail = false,
AsyncTimeout = 10000,
ConnectTimeout = 10000,
KeepAlive = 180
//ServiceName = ServiceName, AllowAdmin = true
};
foreach (var item in connectionStrings)
{
_configurationOptions.EndPoints.Add(item);
}
_client = ConnectionMultiplexer.Connect(_configurationOptions);
}
public IDatabase GetDatabase()
{
return _client.GetDatabase();
}
public T Get<T>(string key) where T : class
{
string value = _client.GetDatabase().StringGet(RedisDbName + key);
return value.ToObject<T>();
}
public async Task<T> GetAsync<T>(string key) where T : class
{
string value = await _client.GetDatabase().StringGetAsync(RedisDbName + key);
return value.ToObject<T>();
}
}
I have implemented custom lifetime provider in order to have singleton DB context per job in hangfire. The problem in code below is that created instances are not being released.
My question is: Why ReleaseObject method is not called?
public class JobContextLifetimeProvider : TinyIoCContainer.ITinyIoCObjectLifetimeProvider
{
private static readonly ConcurrentDictionary<string, object> Locator = new ConcurrentDictionary<string, object>();
public object GetObject()
{
var key = JobContext.JobId;
return Locator.ContainsKey(key) ? Locator[key] : null;
}
public void SetObject(object value)
{
var key = JobContext.JobId;
Locator[key] = value;
if (value is IDataContext)
{
Debug.WriteLine("Created data context {0}", value.GetHashCode());
}
}
public void ReleaseObject()
{
var item = GetObject() as IDisposable;
if (item != null)
{
item.Dispose();
SetObject(null);
}
}
}
I've read some stuff about the ExpandoObject, and that I can expand it with properties,fields,methods.
//that's how to add a property to an ExpandoObject.
dynamic x = new ExpandoObject();
x.NewProp = string.Empty;
But sometimes, it could be handy to add a property with some "extra-code".
class sample
{
// a sample field.
public string sampleString{get;set}
// a sample property with some "extra code"
private string s;
public string sampleExtraString
{
get{return s;}
set{s=value;Console.WriteLine(s);}
}
}
Now my question is, how can I add a property to the ExpandoObject that will execute my Console.WriteLine(s); for example on set.
ExpandoObject implements INotifyPropertyChanged, as explained here
(at the bottom of the page)
((INotifyPropertyChanged)x).PropertyChanged +=
new PropertyChangedEventHandler(Expando_PropertyChanged);
x.NewProp = string.Empty;
private static void Expando_PropertyChanged(object sender,
PropertyChangedEventArgs e)
{
Console.WriteLine("{0} has changed.", e.PropertyName);
}
I think a better approach would be using DynamicObject which you can intercept the calls for methods and properties.
This is a simple example, a more robust one would not use reflection to perform set/get operations on the property but rather using reflection.Emit or any compiled operation strategy.
public class Sample
{
public string SampleExtraString { get; set; }
}
public class Factory
{
public class ExtraPropertyObject<T> : DynamicObject
{
private readonly T instance = default(T);
private readonly Type instanceType = null;
public ExtraPropertyObject(T instance) {
this.instance = instance;
instanceType = instance.GetType();
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
PropertyInfo prop = null;
if (binder.Name.Equals("SampleExtraString")) {
Console.WriteLine(value);
}
prop = instanceType.GetProperty(binder.Name);
if (prop != null) {
try {
prop.SetValue(instance, value);
return true;
}
catch (Exception ex) {
}
}
return false;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
var prop = instanceType.GetProperty(binder.Name);
if (prop != null) {
try {
result = prop.GetValue(instance);
return true;
}
catch (Exception ex) {
}
}
result = null;
return false;
}
}
public static dynamic CreateInstance<TInstance>() where TInstance : class, new() {
return new ExtraPropertyObject<TInstance>(new TInstance());
}
public static dynamic CreateInstance<TInstance>(TInstance instance) {
return new ExtraPropertyObject<TInstance>(instance);
}
}
class Program
{
static void Main(string[] args) {
var instance = Factory.CreateInstance<Sample>();
instance.SampleExtraString = "value";
Console.WriteLine("Get Operation: {0}", instance.SampleExtraString);
}
}
I have created an architecture in my C# code which does exactly what I want, but seems it would be very difficult to maintain in the long-run and am hoping there's a design pattern / better architecture I could be pointed towards.
I have created an object Test which, again, does exactly what I need perfectly which has the following structure:
class Test
{
public static Dictionary<string, Func<Test, object>> MethodDictionary;
public double Var1;
public double Var2;
private Lazy<object> _test1;
public object Test1 { get { return _test1.Value; } }
private Lazy<object> _test2;
public object Test2 { get { return _test2.Value; } }
public Test()
{
_test1 = new Lazy<object>(() => MethodDictionary["Test1"](this), true);
_test2 = new Lazy<object>(() => MethodDictionary["Test2"](this), true);
}
}
What this allows me to do is, at run-time to assign a dictionary of functions to my Test object and the 2 properties Test1 & Test2 will use the functions loaded into it to return values.
The implementation looking somewhat as follows:
class Program
{
static void Main(string[] args)
{
Dictionary<string, Func<Test, object>> MethodDictionary = new Dictionary<string,Func<Test,object>>();
MethodDictionary.Add("Test1", TestMethod1);
MethodDictionary.Add("Test2", TestMethod2);
Test.MethodDictionary = MethodDictionary;
var x = new Test() { Var1 = 20, Var2 = 30 };
Console.WriteLine(x.Test1.ToString());
Console.WriteLine(x.Test2.ToString());
Console.ReadKey();
}
private static object TestMethod1(Test t)
{ return t.Var1 + t.Var2; }
private static object TestMethod2(Test t)
{ return t.Var1 - t.Var2; }
}
And it works great and has proven very efficient for large sets of Test objects.
My challenge is that if I ever want to add in a new method to my Test class, I need to add in the:
private Lazy<object> _myNewMethod;
public object MyNewMethod { get { return _myNewMethod.Value; } }
Update the constuctor with the key to look for in the dictionary
And, although that is pretty simple, I'd love to have a 1-line add-in (maybe some form of custom object) or have the properties read directly form the dictionary without any need for defining them at all.
Any ideas? ANY help would be great!!!
Thanks!!!
One of the ways in which you could achieve your desired behavior, is to use something that resembles a miniature IoC framework for field injection, tuned to your specific use case.
To make things easier, allow less typing in your concrete classes and make things type-safe, we introduce the LazyField type:
public class LazyField<T>
{
private static readonly Lazy<T> Default = new Lazy<T>();
private readonly Lazy<T> _lazy;
public LazyField() : this(Default) { }
public LazyField(Lazy<T> lazy)
{
_lazy = lazy;
}
public override string ToString()
{
return _lazy.Value.ToString();
}
public static implicit operator T(LazyField<T> instance)
{
return instance._lazy.Value;
}
}
Furthermore, we define an abstract base class, that ensures that these fields will be created at construction time:
public abstract class AbstractLazyFieldHolder
{
protected AbstractLazyFieldHolder()
{
LazyFields.BuildUp(this); // ensures fields are populated.
}
}
Skipping for a moment how this is achieved (explained further below), this allows the following way of defining your Test class:
public class Test : AbstractLazyFieldHolder
{
public double Var1;
public double Var2;
public readonly LazyField<double> Test1;
public readonly LazyField<double> Test2;
}
Note that these fields are immutable, initialized in the constructor. Now, for your usage example, the below snippet shows the "new way" of doing this:
LazyFields.Configure<Test>()
// We can use a type-safe lambda
.SetProvider(x => x.Test1, inst => inst.Var1 + inst.Var2)
// Or the field name.
.SetProvider("Test2", TestMethod2);
var x = new Test() { Var1 = 20, Var2 = 30 };
Console.WriteLine(x.Test1);
double test2Val = x.Test2; // type-safe conversion
Console.WriteLine(test2Val);
// Output:
// 50
// -10
The class below provides the services that support the configuration and injection of these field value.
public static class LazyFields
{
private static readonly ConcurrentDictionary<Type, IBuildUp> _registry = new ConcurrentDictionary<Type,IBuildUp>();
public interface IConfigureType<T> where T : class
{
IConfigureType<T> SetProvider<FT>(string fieldName, Func<T, FT> provider);
IConfigureType<T> SetProvider<F, FT>(Expression<Func<T, F>> fieldExpression, Func<T, FT> provider) where F : LazyField<FT>;
}
public static void BuildUp(object instance)
{
System.Diagnostics.Debug.Assert(instance != null);
var builder = _registry.GetOrAdd(instance.GetType(), BuildInitializer);
builder.BuildUp(instance);
}
public static IConfigureType<T> Configure<T>() where T : class
{
return (IConfigureType<T>)_registry.GetOrAdd(typeof(T), BuildInitializer);
}
private interface IBuildUp
{
void BuildUp(object instance);
}
private class TypeCfg<T> : IBuildUp, IConfigureType<T> where T : class
{
private readonly List<FieldInfo> _fields;
private readonly Dictionary<string, Action<T>> _initializers;
public TypeCfg()
{
_fields = typeof(T)
.GetFields(BindingFlags.Instance | BindingFlags.Public)
.Where(IsLazyField)
.ToList();
_initializers = _fields.ToDictionary(x => x.Name, BuildDefaultSetter);
}
public IConfigureType<T> SetProvider<FT>(string fieldName, Func<T,FT> provider)
{
var pi = _fields.First(x => x.Name == fieldName);
_initializers[fieldName] = BuildSetter<FT>(pi, provider);
return this;
}
public IConfigureType<T> SetProvider<F,FT>(Expression<Func<T,F>> fieldExpression, Func<T,FT> provider)
where F : LazyField<FT>
{
return SetProvider((fieldExpression.Body as MemberExpression).Member.Name, provider);
}
public void BuildUp(object instance)
{
var typedInstance = (T)instance;
foreach (var initializer in _initializers.Values)
initializer(typedInstance);
}
private bool IsLazyField(FieldInfo fi)
{
return fi.FieldType.IsGenericType && fi.FieldType.GetGenericTypeDefinition() == typeof(LazyField<>);
}
private Action<T> BuildDefaultSetter(FieldInfo fi)
{
var itemType = fi.FieldType.GetGenericArguments()[0];
var defValue = Activator.CreateInstance(typeof(LazyField<>).MakeGenericType(itemType));
return (inst) => fi.SetValue(inst, defValue);
}
private Action<T> BuildSetter<FT>(FieldInfo fi, Func<T, FT> provider)
{
return (inst) => fi.SetValue(inst, new LazyField<FT>(new Lazy<FT>(() => provider(inst))));
}
}
private static IBuildUp BuildInitializer(Type targetType)
{
return (IBuildUp)Activator.CreateInstance(typeof(TypeCfg<>).MakeGenericType(targetType));
}
}
Look at library https://github.com/ekonbenefits/impromptu-interface.
With it and using DynamicObject i wrote sample code that shows how to simplify adding new methods:
public class Methods
{
public Methods()
{
MethodDictionary = new Dictionary<string, Func<ITest, object>>();
LazyObjects = new Dictionary<string, Lazy<object>>();
}
public Dictionary<string, Func<ITest, object>> MethodDictionary { get; private set; }
public Dictionary<string, Lazy<object>> LazyObjects { get; private set; }
}
public class Proxy : DynamicObject
{
Methods _methods;
public Proxy()
{
_methods = new Methods();
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = _methods.LazyObjects[binder.Name].Value;
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_methods.MethodDictionary[binder.Name] = (Func<ITest, object>)value;
_methods.LazyObjects[binder.Name] = new Lazy<object>(() => _methods.MethodDictionary[binder.Name](this.ActLike<ITest>()), true);
return true;
}
}
//now you can add new methods by add single method to interface
public interface ITest
{
object Test1 { get; set; }
object Test2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var x = new Proxy().ActLike<ITest>();
x.Test1 = new Func<ITest, object>((y) => "Test1");
x.Test2 = new Func<ITest, object>((y) => "Test2");
Console.WriteLine(x.Test1);
Console.WriteLine(x.Test2);
}
}
I don't know what you are trying to do, but I think you can use a simpler approach like this:
class Test
{
public static Dictionary<string, Func<Test, object>> MethodDictionary;
public double Var1;
public double Var2;
}
Calling the function is simple:
static void Main(string[] args)
{
Dictionary<string, Func<Test, object>> MethodDictionary = new Dictionary<string,Func<Test,object>>();
MethodDictionary.Add("Test1", TestMethod1);
MethodDictionary.Add("Test2", TestMethod2);
Test.MethodDictionary = MethodDictionary;
var x = new Test() { Var1 = 20, Var2 = 30 };
Console.WriteLine(Test.MethodDictionary["Test1"](x).ToString());
Console.WriteLine(Test.MethodDictionary["Test2"](x).ToString());
Console.ReadKey();
}
I have such a class:
public static class CacheManager
{
static object lockObject = new object();
static MemcachedClient CacheObject
{
get
{
if (!MemcachedClient.Exists(Settings.Default
.CacheInstanceName))
{
MemcachedClient.Setup(Settings.Default
.CacheInstanceName,
new string[] {Settings.Default
.CacheHostAddress});
}
//
//
return MemcachedClient.GetInstance(Settings
.Default.CacheInstanceName);
}
}
public static List<TData> Get<TData>(string key, Func<List<int>> getListCallback,
Func<int, TData> getItemCallback) where TData : class
{
var result = new List<TData>();
//
//
var list = CacheObject.Get(key);
if (list == null)
{
lock (lockObject)
{
list = CacheObject.Get(key);
if (list == null)
{
list = getListCallback();
CacheObject.Set(key, list);
//
//
foreach (var id in (List<int>)list)
{
var item = getItemCallback(id);
result.Add(item);
CacheObject.Set(string.Concat(key, id), item);
}
}
}
}
else
{
foreach (var id in (List<int>)list)
{
var itemKey = string.Concat(key, id);
//
//
var item = CacheObject.Get(itemKey);
if (item == null)
{
lock (lockObject)
{
item = CacheObject.Get(itemKey);
if (item == null)
{
item = getItemCallback(id);
CacheObject.Set(itemKey, item);
}
}
}
//
//
result.Add((TData)item);
}
}
//
//
return (List<TData>)result;
}
public static void Remove(string key)
{
CacheObject.Delete(key);
}
}
it is used in classes-repositories:
public class NewsRepository : BaseRepository, IRepository
{
public List<News> FindAll()
{
return CacheManager.Get<News>(key,
() => clientEntities.News.OrderByDescending(n => n.DateCreated).Select(n => n.NewsId).ToList(),
(id) => clientEntities.News.Single(n => n.NewsId == id));
}
}
public class PagesRepository : BaseRepository
{
public List<Page> FindAll()
{
return CacheManager.Get<Page>(key,
() => clientEntities.Pages.OrderBy(p => p.PageId).Select(p => p.PageId).ToList(),
(id) => clientEntities.Pages.Single(p => p.PageId == id));
}
}
my question is: for example NewsRepository didn't find news in cache and got the lock and began to load data but at this moment PagesRepository didn't find pages in cache. will PagesRepository's CacheManager be locked by NewsRepository or (I think so) NewsRepository's CacheManager is another static class and its internal locks do not touch PagesRepository's CacheManager?
A static field of a non-generic type (that is itself not nested in a generic type etc) exists only once, so all the locks will conflict.
If (comments) your aim is to make the lock per-type (from the generic method), then perhaps the best way to do that is:
public static class CacheManager {
static class TypeLock<T> {
public static readonly object SyncLock = new object();
}
...
void SomeGenericMethod<TData>(args) {
...
lock(TypeLock<TData>.SyncLock) {
...
}
...
}
}
Here, SyncLock exists once (and only once) per T, so per TData. This allows you to keep your existing API (where CacheManager is non-generic).
Both will use the same reference to lockObject, and therefore the same lock.