public class CacheController
{
public IMemoryCache _memoryCache {get; set;}
public string getCacheMethodOne(string token)
{
string cacheValue = null;
string cacheKey = null;
if (!_memoryCache.TryGetValue<string>("123456", out cacheValue))
{
cacheValue = token;
cacheKey = "123456";
var cacheEntryOptions = new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromMinutes(2));
_memoryCache.Set<string>("123456", cacheValue, cacheEntryOptions);
}
return cacheKey;
}
}
Problem with this line of code:
string otp = new
CacheController().getCacheMethodOne(ClientJsonOtp.ToString());
throws exception.
Object reference not set to an instance of an object.
Should i create new instances of IMemorycahce.
If i do so, will it affect the cache. as it may lose the previous cache instance.
try
{
var finalResult = result.Content.ReadAsStringAsync().Result;
var ClientJsonOtp = JsonConvert.DeserializeObject(finalResult);
string otp = new CacheController().getCacheMethodOne(ClientJsonOtp.ToString());
return Json(ClientJsonOtp, JsonRequestBehavior.AllowGet);
}
You need to create one, at least once. Otherwise it will always be null.
You can do that when you call the empty constructor:
public CacheController()
{
this._memoryCache = new // whatever memory cache you choose;
}
You can even better inject it somewhere using dependency injection. The place depends on application type.
But best of all, try to have only once cache. Each time you create one you lose the previous, so you will either try the singleton pattern, or inject using a single instance configuration and let the DI container handle the rest.
An example for the singleton implementation: here
You can access by using:
Cache.Instance.Read(//what)
Here is the cache implementation
using System;
using System.Configuration;
using System.Runtime.Caching;
namespace Client.Project.HelperClasses
{
/// <summary>
/// Thread Safe Singleton Cache Class
/// </summary>
public sealed class Cache
{
private static volatile Cache instance; // Locks var until assignment is complete for double safety
private static MemoryCache memoryCache;
private static object syncRoot = new Object();
private static string settingMemoryCacheName;
private static double settingCacheExpirationTimeInMinutes;
private Cache() { }
/// <summary>
/// Singleton Cache Instance
/// </summary>
public static Cache Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
InitializeInstance();
}
}
}
return instance;
}
}
private static void InitializeInstance()
{
var appSettings = ConfigurationManager.AppSettings;
settingMemoryCacheName = appSettings["MemoryCacheName"];
if (settingMemoryCacheName == null)
throw new Exception("Please enter a name for the cache in app.config, under 'MemoryCacheName'");
if (! Double.TryParse(appSettings["CacheExpirationTimeInMinutes"], out settingCacheExpirationTimeInMinutes))
throw new Exception("Please enter how many minutes the cache should be kept in app.config, under 'CacheExpirationTimeInMinutes'");
instance = new Cache();
memoryCache = new MemoryCache(settingMemoryCacheName);
}
/// <summary>
/// Writes Key Value Pair to Cache
/// </summary>
/// <param name="Key">Key to associate Value with in Cache</param>
/// <param name="Value">Value to be stored in Cache associated with Key</param>
public void Write(string Key, object Value)
{
memoryCache.Add(Key, Value, DateTimeOffset.Now.AddMinutes(settingCacheExpirationTimeInMinutes));
}
/// <summary>
/// Returns Value stored in Cache
/// </summary>
/// <param name="Key"></param>
/// <returns>Value stored in cache</returns>
public object Read(string Key)
{
return memoryCache.Get(Key);
}
/// <summary>
/// Returns Value stored in Cache, null if non existent
/// </summary>
/// <param name="Key"></param>
/// <returns>Value stored in cache</returns>
public object TryRead(string Key)
{
try
{
return memoryCache.Get(Key);
}
catch (Exception)
{
return null;
}
}
}
}
Related
So, I'm trying to wrap my head around Microsoft's Dataflow library. I've built a very simple pipeline consisting of just two blocks:
var start = new TransformBlock<Foo, Bar>();
var end = new ActionBlock<Bar>();
start.LinkTo(end);
Now I can asynchronously process Foo instances by calling:
start.SendAsync(new Foo());
What I do not understand is how to do the processing synchronously, when needed. I thought that waiting on SendAsync would be enough:
start.SendAsync(new Foo()).Wait();
But apparently it returns as soon as item is accepted by first processor in pipeline, and not when item is fully processed. So is there a way to wait until given item was processed by last (end) block? Apart from passing a WaitHandle through entire pipeline.
In short that's not supported out of the box in data flow. Essentially what you need to do is to tag the data so you can retrieve it when processing is done. I've written up a way to do this that let's the consumer await a Job as it gets processed by the pipeline. The only concession to pipeline design is that each block take a KeyValuePair<Guid, T>. This is the basic JobManager and the post I wrote about it. Note the code in the post is a bit dated and needs some updates but it should get you in the right direction.
namespace ConcurrentFlows.DataflowJobs {
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
/// <summary>
/// A generic interface defining that:
/// for a specified input type => an awaitable result is produced.
/// </summary>
/// <typeparam name="TInput">The type of data to process.</typeparam>
/// <typeparam name="TOutput">The type of data the consumer expects back.</typeparam>
public interface IJobManager<TInput, TOutput> {
Task<TOutput> SubmitRequest(TInput data);
}
/// <summary>
/// A TPL-Dataflow based job manager.
/// </summary>
/// <typeparam name="TInput">The type of data to process.</typeparam>
/// <typeparam name="TOutput">The type of data the consumer expects back.</typeparam>
public class DataflowJobManager<TInput, TOutput> : IJobManager<TInput, TOutput> {
/// <summary>
/// It is anticipated that jobHandler is an injected
/// singleton instance of a Dataflow based 'calculator', though this implementation
/// does not depend on it being a singleton.
/// </summary>
/// <param name="jobHandler">A singleton Dataflow block through which all jobs are processed.</param>
public DataflowJobManager(IPropagatorBlock<KeyValuePair<Guid, TInput>, KeyValuePair<Guid, TOutput>> jobHandler) {
if (jobHandler == null) { throw new ArgumentException("Argument cannot be null.", "jobHandler"); }
this.JobHandler = JobHandler;
if (!alreadyLinked) {
JobHandler.LinkTo(ResultHandler, new DataflowLinkOptions() { PropagateCompletion = true });
alreadyLinked = true;
}
}
private static bool alreadyLinked = false;
/// <summary>
/// Submits the request to the JobHandler and asynchronously awaits the result.
/// </summary>
/// <param name="data">The input data to be processd.</param>
/// <returns></returns>
public async Task<TOutput> SubmitRequest(TInput data) {
var taggedData = TagInputData(data);
var job = CreateJob(taggedData);
Jobs.TryAdd(job.Key, job.Value);
await JobHandler.SendAsync(taggedData);
return await job.Value.Task;
}
private static ConcurrentDictionary<Guid, TaskCompletionSource<TOutput>> Jobs {
get;
} = new ConcurrentDictionary<Guid, TaskCompletionSource<TOutput>>();
private static ExecutionDataflowBlockOptions Options {
get;
} = GetResultHandlerOptions();
private static ITargetBlock<KeyValuePair<Guid, TOutput>> ResultHandler {
get;
} = CreateReplyHandler(Options);
private IPropagatorBlock<KeyValuePair<Guid, TInput>, KeyValuePair<Guid, TOutput>> JobHandler {
get;
}
private KeyValuePair<Guid, TInput> TagInputData(TInput data) {
var id = Guid.NewGuid();
return new KeyValuePair<Guid, TInput>(id, data);
}
private KeyValuePair<Guid, TaskCompletionSource<TOutput>> CreateJob(KeyValuePair<Guid, TInput> taggedData) {
var id = taggedData.Key;
var jobCompletionSource = new TaskCompletionSource<TOutput>();
return new KeyValuePair<Guid, TaskCompletionSource<TOutput>>(id, jobCompletionSource);
}
private static ExecutionDataflowBlockOptions GetResultHandlerOptions() {
return new ExecutionDataflowBlockOptions() {
MaxDegreeOfParallelism = Environment.ProcessorCount,
BoundedCapacity = 1000
};
}
private static ITargetBlock<KeyValuePair<Guid, TOutput>> CreateReplyHandler(ExecutionDataflowBlockOptions options) {
return new ActionBlock<KeyValuePair<Guid, TOutput>>((result) => {
RecieveOutput(result);
}, options);
}
private static void RecieveOutput(KeyValuePair<Guid, TOutput> result) {
var jobId = result.Key;
TaskCompletionSource<TOutput> jobCompletionSource;
if (!Jobs.TryRemove(jobId, out jobCompletionSource)) {
throw new InvalidOperationException($"The jobId: {jobId} was not found.");
}
var resultValue = result.Value;
jobCompletionSource.SetResult(resultValue);
}
}
}
I ended up using the following pipeline:
var start = new TransformBlock<FooBar, FooBar>(...);
var end = new ActionBlock<FooBar>(item => item.Complete());
start.LinkTo(end);
var input = new FooBar {Input = new Foo()};
start.SendAsync(input);
input.Task.Wait();
Where
class FooBar
{
public Foo Input { get; set; }
public Bar Result { get; set; }
public Task<Bar> Task { get { return _taskSource.Task; } }
public void Complete()
{
_taskSource.SetResult(Result);
}
private TaskCompletionSource<Bar> _taskSource = new TaskCompletionSource<Bar>();
}
Less than ideal, but it works.
I'm trying to apply some behavior using a home grown type of "aspect", really a .net Attribute. I have a base class (BankingServiceBase) that reflects on itself at startup to see what "aspects" are applied to it. It then can execute custom behavior before or after operations. I'm using Autofac as my IOC container. I'm trying to apply the PropertiesAutowired method to the aspect's registration. In the below sample code I want Autofac to inject an ILog instance to my aspect/attribute. It isn't doing that however. My guess is that when I call GetCustomAttributes, it's creating a new instance instead of getting the registered instance from Autofac. Thoughts? Here is some usable sample code to display the problem:
internal class Program
{
private static void Main()
{
var builder = new ContainerBuilder();
builder
.RegisterType<ConsoleLog>()
.As<ILog>();
builder
.RegisterType<BankingService>()
.As<IBankingService>();
builder
.RegisterType<LogTransfer>()
.As<LogTransfer>()
.PropertiesAutowired();
var container = builder.Build();
var bankingService = container.Resolve<IBankingService>();
bankingService.Transfer("ACT 1", "ACT 2", 180);
System.Console.ReadKey();
}
public interface IBankingService
{
void Transfer(string from, string to, decimal amount);
}
public interface ILog
{
void LogMessage(string message);
}
public class ConsoleLog : ILog
{
public void LogMessage(string message)
{
System.Console.WriteLine(message);
}
}
[AttributeUsage(AttributeTargets.Class)]
public abstract class BankingServiceAspect : Attribute
{
public virtual void PreTransfer(string from, string to, decimal amount)
{
}
public virtual void PostTransfer(bool success)
{
}
}
public class LogTransfer : BankingServiceAspect
{
// Note: this is never getting set from Autofac!
public ILog Log { get; set; }
public override void PreTransfer(string from, string to, decimal amount)
{
Log.LogMessage(string.Format("About to transfer from {0}, to {1}, for amount {2}", from, to, amount));
}
public override void PostTransfer(bool success)
{
Log.LogMessage(success ? "Transfer completed!" : "Transfer failed!");
}
}
public abstract class BankingServiceBase : IBankingService
{
private readonly List<BankingServiceAspect> aspects;
protected BankingServiceBase()
{
// Note: My guess is that this "GetCustomAttributes" is happening before the IOC dependency map is built.
aspects =
GetType().GetCustomAttributes(typeof (BankingServiceAspect), true).Cast<BankingServiceAspect>().
ToList();
}
void IBankingService.Transfer(string from, string to, decimal amount)
{
aspects.ForEach(a => a.PreTransfer(from, to, amount));
try
{
Transfer(from, to, amount);
aspects.ForEach(a => a.PostTransfer(true));
}
catch (Exception)
{
aspects.ForEach(a => a.PostTransfer(false));
}
}
public abstract void Transfer(string from, string to, decimal amount);
}
[LogTransfer]
public class BankingService : BankingServiceBase
{
public override void Transfer(string from, string to, decimal amount)
{
// Simulate some latency..
Thread.Sleep(1000);
}
}
}
You're correct that GetCustomAttributes doesn't resolve the custom attributes via Autofac - if you think about it, how could FCL code such as GetCustomAttributes know about Autofac? The custom attributes are actually retrieved from assembly metadata, so they never go through Autofac's resolution process and therefore your registration code is never used.
What you can do is to inject the services into the attribute instance yourself. Begin with the code in Oliver's answer to generate the list of aspect attributes. However, before returning the list, you can process each attribute and inject services into any dependent fields and properties. I have a class called AttributedDependencyInjector, which I use via an extension method. It uses reflection to scan for fields and properties that are decorated with the InjectDependencyAttribute and then set the value of those properties. There's rather a lot of code to cope with various scenarios, but here it is.
The attribute class:
/// <summary>
/// Attribute that signals that a dependency should be injected.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public sealed class InjectDependencyAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref = "InjectDependencyAttribute" /> class.
/// </summary>
public InjectDependencyAttribute()
{
this.PreserveExistingValue = false;
}
/// <summary>
/// Gets or sets a value indicating whether to preserve an existing non-null value.
/// </summary>
/// <value>
/// <c>true</c> if the injector should preserve an existing value; otherwise, <c>false</c>.
/// </value>
public bool PreserveExistingValue { get; set; }
}
The injector class:
public class AttributedDependencyInjector
{
/// <summary>
/// The component context.
/// </summary>
private readonly IComponentContext context;
/// <summary>
/// Initializes a new instance of the <see cref="AttributedDependencyInjector"/> class.
/// </summary>
/// <param name="context">The context.</param>
public AttributedDependencyInjector(IComponentContext context)
{
this.context = context;
}
/// <summary>
/// Injects dependencies into an instance.
/// </summary>
/// <param name="instance">The instance.</param>
public void InjectDependencies(object instance)
{
this.InjectAttributedFields(instance);
this.InjectAttributedProperties(instance);
}
/// <summary>
/// Gets the injectable fields.
/// </summary>
/// <param name="instanceType">
/// Type of the instance.
/// </param>
/// <param name="injectableFields">
/// The injectable fields.
/// </param>
private static void GetInjectableFields(
Type instanceType, ICollection<Tuple<FieldInfo, InjectDependencyAttribute>> injectableFields)
{
const BindingFlags BindingsFlag =
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
IEnumerable<FieldInfo> fields = instanceType.GetFields(BindingsFlag);
// fields
foreach (FieldInfo field in fields)
{
Type fieldType = field.FieldType;
if (fieldType.IsValueType)
{
continue;
}
// Check if it has an InjectDependencyAttribute
var attribute = field.GetAttribute<InjectDependencyAttribute>(false);
if (attribute == null)
{
continue;
}
var info = new Tuple<FieldInfo, InjectDependencyAttribute>(field, attribute);
injectableFields.Add(info);
}
}
/// <summary>
/// Gets the injectable properties.
/// </summary>
/// <param name="instanceType">
/// Type of the instance.
/// </param>
/// <param name="injectableProperties">
/// A list into which are appended any injectable properties.
/// </param>
private static void GetInjectableProperties(
Type instanceType, ICollection<Tuple<PropertyInfo, InjectDependencyAttribute>> injectableProperties)
{
// properties
foreach (var property in instanceType.GetProperties(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
Type propertyType = property.PropertyType;
// Can't inject value types
if (propertyType.IsValueType)
{
continue;
}
// Can't inject non-writeable properties
if (!property.CanWrite)
{
continue;
}
// Check if it has an InjectDependencyAttribute
var attribute = property.GetAttribute<InjectDependencyAttribute>(false);
if (attribute == null)
{
continue;
}
// If set to preserve existing value, we must be able to read it!
if (attribute.PreserveExistingValue && !property.CanRead)
{
throw new BoneheadedException("Can't preserve an existing value if it is unreadable");
}
var info = new Tuple<PropertyInfo, InjectDependencyAttribute>(property, attribute);
injectableProperties.Add(info);
}
}
/// <summary>
/// Determines whether the <paramref name="propertyType"/> can be resolved in the specified context.
/// </summary>
/// <param name="propertyType">
/// Type of the property.
/// </param>
/// <returns>
/// <c>true</c> if <see cref="context"/> can resolve the specified property type; otherwise, <c>false</c>.
/// </returns>
private bool CanResolve(Type propertyType)
{
return this.context.IsRegistered(propertyType) || propertyType.IsAssignableFrom(typeof(ILog));
}
/// <summary>
/// Injects dependencies into the instance's fields.
/// </summary>
/// <param name="instance">
/// The instance.
/// </param>
private void InjectAttributedFields(object instance)
{
Type instanceType = instance.GetType();
// We can't get information about the private members of base classes through reflecting a subclass,
// so we must walk up the inheritance hierarchy and reflect at each level
var injectableFields = new List<Tuple<FieldInfo, InjectDependencyAttribute>>();
var type = instanceType;
while (type != null)
{
GetInjectableFields(type, injectableFields);
type = type.BaseType;
}
// fields
foreach (var fieldDetails in injectableFields)
{
var field = fieldDetails.Item1;
var attribute = fieldDetails.Item2;
if (!this.CanResolve(field.FieldType))
{
continue;
}
// Check to preserve existing value
if (attribute.PreserveExistingValue && (field.GetValue(instance) != null))
{
continue;
}
object fieldValue = this.Resolve(field.FieldType, instanceType);
field.SetValue(instance, fieldValue);
}
}
/// <summary>
/// Injects dependencies into the instance's properties.
/// </summary>
/// <param name="instance">
/// The instance.
/// </param>
private void InjectAttributedProperties(object instance)
{
Type instanceType = instance.GetType();
// We can't get information about the private members of base classes through reflecting a subclass,
// so we must walk up the inheritance bierarchy and reflect at each level
var injectableProperties = new List<Tuple<PropertyInfo, InjectDependencyAttribute>>();
var type = instanceType;
while (type != typeof(object))
{
Debug.Assert(type != null, "type != null");
GetInjectableProperties(type, injectableProperties);
type = type.BaseType;
}
// Process the list and inject properties as appropriate
foreach (var details in injectableProperties)
{
var property = details.Item1;
var attribute = details.Item2;
// Check to preserve existing value
if (attribute.PreserveExistingValue && (property.GetValue(instance, null) != null))
{
continue;
}
var propertyValue = this.Resolve(property.PropertyType, instanceType);
property.SetValue(instance, propertyValue, null);
}
}
/// <summary>
/// Resolves the specified <paramref name="propertyType"/> within the context.
/// </summary>
/// <param name="propertyType">
/// Type of the property that is being injected.
/// </param>
/// <param name="instanceType">
/// Type of the object that is being injected.
/// </param>
/// <returns>
/// The object instance to inject into the property value.
/// </returns>
private object Resolve(Type propertyType, Type instanceType)
{
if (propertyType.IsAssignableFrom(typeof(ILog)))
{
return LogManager.GetLogger(instanceType);
}
return this.context.Resolve(propertyType);
}
}
The extension method:
public static class RegistrationExtensions
{
/// <summary>
/// Injects dependencies into the instance's properties and fields.
/// </summary>
/// <param name="context">
/// The component context.
/// </param>
/// <param name="instance">
/// The instance into which to inject dependencies.
/// </param>
public static void InjectDependencies(this IComponentContext context, object instance)
{
Enforce.ArgumentNotNull(context, "context");
Enforce.ArgumentNotNull(instance, "instance");
var injector = new AttributedDependencyInjector(context);
injector.InjectDependencies(instance);
}
}
Try to implement a lazy loading of the aspects
private readonly List<BankingServiceAspect> _aspects;
private List<BankingServiceAspect> Aspects
{
get
{
if (_aspects == null) {
_aspects = GetType()
.GetCustomAttributes(typeof(BankingServiceAspect), true)
.Cast<BankingServiceAspect>()
.ToList();
}
return _aspects;
}
}
Then use it like this
Aspects.ForEach(a => a.PreTransfer(from, to, amount));
...
I need to cache a generic list so I dont have to query the databse multiple times. In a web application I would just add it to the httpcontext.current.cache . What is the proper way to cache objects in console applications?
Keep it as instance member of the containing class. In web app you can't do this since page class's object is recreated on every request.
However .NET 4.0 also has MemoryCache class for this purpose.
In a class-level variable. Presumably, in the main method of your console app you instantiate at least one object of some sort. In this object's class, you declare a class-level variable (a List<String> or whatever) in which you cache whatever needs caching.
Here is a very simple cache class I use in consoles that has self clean up and easy implementation.
The Usage:
return Cache.Get("MyCacheKey", 30, () => { return new Model.Guide().ChannelListings.BuildChannelList(); });
The Class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
namespace MyAppNamespace
{
public static class Cache
{
private static Timer cleanupTimer = new Timer() { AutoReset = true, Enabled = true, Interval = 60000 };
private static readonly Dictionary<string, CacheItem> internalCache = new Dictionary<string, CacheItem>();
static Cache()
{
cleanupTimer.Elapsed += Clean;
cleanupTimer.Start();
}
private static void Clean(object sender, ElapsedEventArgs e)
{
internalCache.Keys.ToList().ForEach(x => { try { if (internalCache[x].ExpireTime <= e.SignalTime) { Remove(x); } } catch (Exception) { /*swallow it*/ } });
}
public static T Get<T>(string key, int expiresMinutes, Func<T> refreshFunction)
{
if (internalCache.ContainsKey(key) && internalCache[key].ExpireTime > DateTime.Now)
{
return (T)internalCache[key].Item;
}
var result = refreshFunction();
Set(key, result, expiresMinutes);
return result;
}
public static void Set(string key, object item, int expiresMinutes)
{
Remove(key);
internalCache.Add(key, new CacheItem(item, expiresMinutes));
}
public static void Remove(string key)
{
if (internalCache.ContainsKey(key))
{
internalCache.Remove(key);
}
}
private struct CacheItem
{
public CacheItem(object item, int expiresMinutes)
: this()
{
Item = item;
ExpireTime = DateTime.Now.AddMinutes(expiresMinutes);
}
public object Item { get; private set; }
public DateTime ExpireTime { get; private set; }
}
}
}
// Consider this psuedo code for using Cache
public DataSet GetMySearchData(string search)
{
// if it is in my cache already (notice search criteria is the cache key)
string cacheKey = "Search " + search;
if (Cache[cacheKey] != null)
{
return (DataSet)(Cache[cacheKey]);
}
else
{
DataSet result = yourDAL.DoSearch(search);
Cache[cacheKey].Insert(result); // There are more params needed here...
return result;
}
}
Ref: How do I cache a dataset to stop round trips to db?
You might be able to just use a simple Dictionary. The thing that makes the Cache so special in the web environment is that it persists and is scoped in such a way that many users can access it. In a console app, you don't have those issues. If your needs are simple enough, the dictionary or similar structures can be used to quickly lookup values you pull out of a database.
There a many ways to implement caches, depending of what exactly you are doing. Usually you will be using a dictionary to hold cached values. Here is my simple implementation of a cache, which caches values only for a limited time:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CySoft.Collections
{
public class Cache<TKey,TValue>
{
private readonly Dictionary<TKey, CacheItem> _cache = new Dictionary<TKey, CacheItem>();
private TimeSpan _maxCachingTime;
/// <summary>
/// Creates a cache which holds the cached values for an infinite time.
/// </summary>
public Cache()
: this(TimeSpan.MaxValue)
{
}
/// <summary>
/// Creates a cache which holds the cached values for a limited time only.
/// </summary>
/// <param name="maxCachingTime">Maximum time for which the a value is to be hold in the cache.</param>
public Cache(TimeSpan maxCachingTime)
{
_maxCachingTime = maxCachingTime;
}
/// <summary>
/// Tries to get a value from the cache. If the cache contains the value and the maximum caching time is
/// not exceeded (if any is defined), then the cached value is returned, else a new value is created.
/// </summary>
/// <param name="key">Key of the value to get.</param>
/// <param name="createValue">Function creating a new value.</param>
/// <returns>A cached or a new value.</returns>
public TValue Get(TKey key, Func<TValue> createValue)
{
CacheItem cacheItem;
if (_cache.TryGetValue(key, out cacheItem) && (DateTime.Now - cacheItem.CacheTime) <= _maxCachingTime) {
return cacheItem.Item;
}
TValue value = createValue();
_cache[key] = new CacheItem(value);
return value;
}
private struct CacheItem
{
public CacheItem(TValue item)
: this()
{
Item = item;
CacheTime = DateTime.Now;
}
public TValue Item { get; private set; }
public DateTime CacheTime { get; private set; }
}
}
}
You can pass a lambda expression to the Get method, which retrieves values from a db for instance.
Use Singleton Pattern.
http://msdn.microsoft.com/en-us/library/ff650316.aspx
I have an ASP.NET MVC project in which the model is managed through .NET entities and it seems that some times it loses the connection, but this happens only on stored procedures.
I get the following error:
Execution of the command requires an open and available connection. The connection's current state is broken.
Why is this happening?
Code
public ObjectResult<Categories> GetCategoriesStructure() {
return ObjectContext.getCategoriesStructure();
}
var catss = GetCategoriesStructure().ToList();
this exception occurs when I am trying to assign the List to catss variable
Object Context Instantiation
public abstract class ObjectContextManager {
/// <summary>
/// Returns a reference to an ObjectContext instance.
/// </summary>
public abstract TObjectContext GetObjectContext<TObjectContext>()
where TObjectContext : ObjectContext, new();
}
public abstract class BaseDAO<TObjectContext, TEntity> : IBaseDAO<TObjectContext, TEntity>
where TObjectContext : System.Data.Objects.ObjectContext, new()
where TEntity : System.Data.Objects.DataClasses.EntityObject {
private ObjectContextManager _objectContextManager;
/// <summary>
/// Returns the current ObjectContextManager instance. Encapsulated the
/// _objectContextManager field to show it as an association on the class diagram.
/// </summary>
private ObjectContextManager ObjectContextManager {
get { return _objectContextManager; }
set { _objectContextManager = value; }
}
/// <summary>
/// Returns an ObjectContext object.
/// </summary>
protected internal TObjectContext ObjectContext {
get {
if (ObjectContextManager == null)
this.InstantiateObjectContextManager();
return ObjectContextManager.GetObjectContext<TObjectContext>();
}
}
/// <summary>
/// Default constructor.
/// </summary>
public BaseDAO() { }
/// <summary>
/// Instantiates a new ObjectContextManager based on application configuration settings.
/// </summary>
private void InstantiateObjectContextManager() {
/* Retrieve ObjectContextManager configuration settings: */
Hashtable ocManagerConfiguration = ConfigurationManager.GetSection("ObjectContextManagement.ObjectContext") as Hashtable;
if (ocManagerConfiguration != null && ocManagerConfiguration.ContainsKey("managerType")) {
string managerTypeName = ocManagerConfiguration["managerType"] as string;
if (string.IsNullOrEmpty(managerTypeName))
throw new ConfigurationErrorsException("The managerType attribute is empty.");
else
managerTypeName = managerTypeName.Trim().ToLower();
try {
/* Try to create a type based on it's name: */
Assembly frameworkAssembly = Assembly.GetAssembly(typeof(ObjectContextManager));
Type managerType = frameworkAssembly.GetType(managerTypeName, true, true);
/* Try to create a new instance of the specified ObjectContextManager type: */
this.ObjectContextManager = Activator.CreateInstance(managerType) as ObjectContextManager;
} catch (Exception e) {
throw new ConfigurationErrorsException("The managerType specified in the configuration is not valid.", e);
}
} else
throw new ConfigurationErrorsException("ObjectContext tag or its managerType attribute is missing in the configuration.");
}
/// <summary>
/// Persists all changes to the underlying datastore.
/// </summary>
public void SaveAllObjectChanges() {
this.ObjectContext.SaveChanges();
}
/// <summary>
/// Adds a new entity object to the context.
/// </summary>
/// <param name="newObject">A new object.</param>
public virtual void Add(TEntity newObject) {
this.ObjectContext.AddObject(newObject.GetType().Name, newObject);
}
/// <summary>
/// Deletes an entity object.
/// </summary>
/// <param name="obsoleteObject">An obsolete object.</param>
public virtual void Delete(TEntity obsoleteObject) {
this.ObjectContext.DeleteObject(obsoleteObject);
}
public void Detach(TEntity obsoleteObject) {
this.ObjectContext.Detach(obsoleteObject);
}
/// <summary>
/// Updates the changed entity object to the context.
/// </summary>
/// <param name="newObject">A new object.</param>
public virtual void Update(TEntity newObject) {
ObjectContext.ApplyPropertyChanges(newObject.GetType().Name, newObject);
ObjectContext.Refresh(RefreshMode.ClientWins, newObject);
}
public virtual TEntity LoadByKey(String propertyName, Object keyValue) {
IEnumerable<KeyValuePair<string, object>> entityKeyValues =
new KeyValuePair<string, object>[] {
new KeyValuePair<string, object>(propertyName, keyValue) };
// Create the key for a specific SalesOrderHeader object.
EntityKey key = new EntityKey(this.ObjectContext.GetType().Name + "." + typeof(TEntity).Name, entityKeyValues);
return (TEntity)this.ObjectContext.GetObjectByKey(key);
}
#region IBaseDAO<TObjectContext,TEntity> Members
public bool validation(TEntity newObject) {
return newObject.GetType().Name.ToString() == "Int32";
}
#endregion
}
Without knowing how you are instantiating your ObjectContext, I'll throw something in the answer bucket here.
This is how I do my Entity Framework commands and connections (for small simple projects at least):
using (MyEntities context = new MyEntities())
{
return context.getCategoriesStructure();
}
You can also optionally pass in a connection string when instantiating your context (if not, it will use the one in your app.config):
new MyEntities("...connection string...")
If this does not help your issue, please help us understand your code a little better by posting how you are creating your ObjectContext. You could at least attempt to do it this way to see if it works; that will tell you whether it is an issue with your connection string or not.
I'm building an app in .NET and C#, and I'd like to cache some of the results by using attributes/annotations instead of explicit code in the method.
I'd like a method signature that looks a bit like this:
[Cache, timeToLive=60]
String getName(string id, string location)
It should make a hash based on the inputs, and use that as the key for the result.
Naturally, there'd be some config file telling it how to actually put in memcached, local dictionary or something.
Do you know of such a framework?
I'd even be interested in one for Java as well
With CacheHandler in Microsoft Enterprise Library you can easily achieve this.
For instance:
[CacheHandler(0, 30, 0)]
public Object GetData(Object input)
{
}
would make all calls to that method cached for 30 minutes. All invocations gets a unique cache-key based on the input data and method name so if you call the method twice with different input it doesn't get cached but if you call it >1 times within the timout interval with the same input then the method only gets executed once.
I've added some extra features to Microsoft's code:
My modified version looks like this:
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Web.UI;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace Middleware.Cache
{
/// <summary>
/// An <see cref="ICallHandler"/> that implements caching of the return values of
/// methods. This handler stores the return value in the ASP.NET cache or the Items object of the current request.
/// </summary>
[ConfigurationElementType(typeof (CacheHandler)), Synchronization]
public class CacheHandler : ICallHandler
{
/// <summary>
/// The default expiration time for the cached entries: 5 minutes
/// </summary>
public static readonly TimeSpan DefaultExpirationTime = new TimeSpan(0, 5, 0);
private readonly object cachedData;
private readonly DefaultCacheKeyGenerator keyGenerator;
private readonly bool storeOnlyForThisRequest = true;
private TimeSpan expirationTime;
private GetNextHandlerDelegate getNext;
private IMethodInvocation input;
public CacheHandler(TimeSpan expirationTime, bool storeOnlyForThisRequest)
{
keyGenerator = new DefaultCacheKeyGenerator();
this.expirationTime = expirationTime;
this.storeOnlyForThisRequest = storeOnlyForThisRequest;
}
/// <summary>
/// This constructor is used when we wrap cached data in a CacheHandler so that
/// we can reload the object after it has been removed from the cache.
/// </summary>
/// <param name="expirationTime"></param>
/// <param name="storeOnlyForThisRequest"></param>
/// <param name="input"></param>
/// <param name="getNext"></param>
/// <param name="cachedData"></param>
public CacheHandler(TimeSpan expirationTime, bool storeOnlyForThisRequest,
IMethodInvocation input, GetNextHandlerDelegate getNext,
object cachedData)
: this(expirationTime, storeOnlyForThisRequest)
{
this.input = input;
this.getNext = getNext;
this.cachedData = cachedData;
}
/// <summary>
/// Gets or sets the expiration time for cache data.
/// </summary>
/// <value>The expiration time.</value>
public TimeSpan ExpirationTime
{
get { return expirationTime; }
set { expirationTime = value; }
}
#region ICallHandler Members
/// <summary>
/// Implements the caching behavior of this handler.
/// </summary>
/// <param name="input"><see cref="IMethodInvocation"/> object describing the current call.</param>
/// <param name="getNext">delegate used to get the next handler in the current pipeline.</param>
/// <returns>Return value from target method, or cached result if previous inputs have been seen.</returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
lock (input.MethodBase)
{
this.input = input;
this.getNext = getNext;
return loadUsingCache();
}
}
public int Order
{
get { return 0; }
set { }
}
#endregion
private IMethodReturn loadUsingCache()
{
//We need to synchronize calls to the CacheHandler on method level
//to prevent duplicate calls to methods that could be cached.
lock (input.MethodBase)
{
if (TargetMethodReturnsVoid(input) || HttpContext.Current == null)
{
return getNext()(input, getNext);
}
var inputs = new object[input.Inputs.Count];
for (int i = 0; i < inputs.Length; ++i)
{
inputs[i] = input.Inputs[i];
}
string cacheKey = keyGenerator.CreateCacheKey(input.MethodBase, inputs);
object cachedResult = getCachedResult(cacheKey);
if (cachedResult == null)
{
var stopWatch = Stopwatch.StartNew();
var realReturn = getNext()(input, getNext);
stopWatch.Stop();
if (realReturn.Exception == null && realReturn.ReturnValue != null)
{
AddToCache(cacheKey, realReturn.ReturnValue);
}
return realReturn;
}
var cachedReturn = input.CreateMethodReturn(cachedResult, input.Arguments);
return cachedReturn;
}
}
private object getCachedResult(string cacheKey)
{
//When the method uses input that is not serializable
//we cannot create a cache key and can therefore not
//cache the data.
if (cacheKey == null)
{
return null;
}
object cachedValue = !storeOnlyForThisRequest ? HttpRuntime.Cache.Get(cacheKey) : HttpContext.Current.Items[cacheKey];
var cachedValueCast = cachedValue as CacheHandler;
if (cachedValueCast != null)
{
//This is an object that is reloaded when it is being removed.
//It is therefore wrapped in a CacheHandler-object and we must
//unwrap it before returning it.
return cachedValueCast.cachedData;
}
return cachedValue;
}
private static bool TargetMethodReturnsVoid(IMethodInvocation input)
{
var targetMethod = input.MethodBase as MethodInfo;
return targetMethod != null && targetMethod.ReturnType == typeof (void);
}
private void AddToCache(string key, object valueToCache)
{
if (key == null)
{
//When the method uses input that is not serializable
//we cannot create a cache key and can therefore not
//cache the data.
return;
}
if (!storeOnlyForThisRequest)
{
HttpRuntime.Cache.Insert(
key,
valueToCache,
null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
expirationTime,
CacheItemPriority.Normal, null);
}
else
{
HttpContext.Current.Items[key] = valueToCache;
}
}
}
/// <summary>
/// This interface describes classes that can be used to generate cache key strings
/// for the <see cref="CacheHandler"/>.
/// </summary>
public interface ICacheKeyGenerator
{
/// <summary>
/// Creates a cache key for the given method and set of input arguments.
/// </summary>
/// <param name="method">Method being called.</param>
/// <param name="inputs">Input arguments.</param>
/// <returns>A (hopefully) unique string to be used as a cache key.</returns>
string CreateCacheKey(MethodBase method, object[] inputs);
}
/// <summary>
/// The default <see cref="ICacheKeyGenerator"/> used by the <see cref="CacheHandler"/>.
/// </summary>
public class DefaultCacheKeyGenerator : ICacheKeyGenerator
{
private readonly LosFormatter serializer = new LosFormatter(false, "");
#region ICacheKeyGenerator Members
/// <summary>
/// Create a cache key for the given method and set of input arguments.
/// </summary>
/// <param name="method">Method being called.</param>
/// <param name="inputs">Input arguments.</param>
/// <returns>A (hopefully) unique string to be used as a cache key.</returns>
public string CreateCacheKey(MethodBase method, params object[] inputs)
{
try
{
var sb = new StringBuilder();
if (method.DeclaringType != null)
{
sb.Append(method.DeclaringType.FullName);
}
sb.Append(':');
sb.Append(method.Name);
TextWriter writer = new StringWriter(sb);
if (inputs != null)
{
foreach (var input in inputs)
{
sb.Append(':');
if (input != null)
{
//Diffrerent instances of DateTime which represents the same value
//sometimes serialize differently due to some internal variables which are different.
//We therefore serialize it using Ticks instead. instead.
var inputDateTime = input as DateTime?;
if (inputDateTime.HasValue)
{
sb.Append(inputDateTime.Value.Ticks);
}
else
{
//Serialize the input and write it to the key StringBuilder.
serializer.Serialize(writer, input);
}
}
}
}
return sb.ToString();
}
catch
{
//Something went wrong when generating the key (probably an input-value was not serializble.
//Return a null key.
return null;
}
}
#endregion
}
}
Microsoft deserves most credit for this code. We've only added stuff like caching at request level instead of across requests (more useful than you might think) and fixed some bugs (e.g. equal DateTime-objects serializing to different values).
To do exactly what you are describing, i.e. writing
public class MyClass {
[Cache, timeToLive=60]
string getName(string id, string location){
return ExpensiveCall(id, location);
}
}
// ...
MyClass c = new MyClass();
string name = c.getName("id", "location");
string name_again = c.getName("id", "location");
and having only one invocation of the expensive call and without needing to wrap the class with some other code (f.x. CacheHandler<MyClass> c = new CacheHandler<MyClass>(new MyClass());) you need to look into an Aspect Oriented Programming framework. Those usually work by rewriting the byte-code, so you need to add another step to your compilation process - but you gain a lot of power in the process. There are many AOP-frameworks, but PostSharp for .NET and AspectJ are among the most popular. You can easily Google how to use those to add the caching-aspect you want.