I've decided to develop an example aspect-oriented programming (AOP) framework API to facilitate decoupling from AOP frameworks. For each framework we wish to use for the concrete implementation of a cross-cutting concern, we'd have to develop an adapter. I have posted below the interfaces for such a framework and, since I use Enterprise Library (EntLib) a lot, I've included the relevant adapters as well.
Disclaimer: The code below carries no guarantees-- heck, it may not even work-- so use at your own risk.
public interface INotifyDisposed
{
event EventHandler Disposed;
}
public abstract class ScopeLimitedObject : IDisposable, INotifyDisposed
{
public event EventHandler Disposed = null;
// We provide this version of the property name as it is most common in legacy .NET and applications.
public bool Disposing
{ get { return IsDisposing; } }
protected bool IsDisposing
{ get; private set; }
public bool IsDisposed
{ get; protected set; }
private void RaiseDisposed()
{
var @event = Disposed;
if (@event != null)
@event(this, null);
}
/// <summary>
/// This is the dispose routine you want to normally handle.
/// </summary>
protected virtual void OnDisposeExplicit()
{ }
/// <summary>
/// This is the dispose routine that *typically* originates from garbage collection and where
/// dispose was NEVER called explicitly.
/// </summary>
protected virtual void OnDisposeImplicit()
{ }
/// <summary>
/// This is a dispose routine that is always called, during both implicit and explicit calls to
/// Dispose. WARNING: this method will likely (though not guaranteed) be executed twice,
/// so be careful of the side effects in your own overriding method. You never need to provide
/// an implementation of this method if you adequately provide implementations for both
/// "OnDisposeExplicit" and "OnDisposeImplicit".
/// </summary>
protected virtual void OnDisposeRegardless()
{ }
protected void Dispose(bool isDisposing)
{
if (!(IsDisposed || IsDisposing))
{
IsDisposing = true;
if (isDisposing)
{
IsDisposed = true;
OnDisposeExplicit();
}
else
OnDisposeImplicit();
RaiseDisposed();
}
OnDisposeRegardless();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~ScopeLimitedObject()
{ Dispose(false); }
}
public interface Indexable<TKey, TValue> : IEnumerable<TValue>
{
bool TryGet(TKey key, out TValue value);
TValue this[TKey key]
{ get; }
}
public interface IndexableByName<TEntry> : Indexable<string, TEntry>
{
new bool TryGet(string name, out TEntry entry);
new TEntry this[string name]
{ get; }
}
public interface ExceptionManager
{
/// <summary>
/// For advanced scenarios (suggested you use "Process" over this method): Handles the
/// specified <see cref="Exception"/> object according to the rules configured for <paramref name="policyName"/>.
/// </summary>a
/// <param name="exceptionToHandle">An <see cref="Exception"/> object.</param>
/// <param name="policyName">The name of the policy to handle.</param>
/// <param name="exceptionToThrow">The new <see cref="Exception"/> to throw, if any.</param>
/// <remarks>
/// If a rethrow is recommended and <paramref name="exceptionToThrow"/> is <see langword="null"/>,
/// then the original exception <paramref name="exceptionToHandle"/> should be rethrown; otherwise,
/// the exception returned in <paramref name="exceptionToThrow"/> should be thrown.
/// </remarks>
/// <returns>
/// Whether or not a rethrow is recommended.
/// </returns>
/// <example>
/// The following code shows the usage of the
/// exception handling framework.
/// <code>
/// try
/// {
/// Foo();
/// }
/// catch (Exception e)
/// {
/// Exception exceptionToThrow;
/// if (exceptionManager.HandleException(e, "policy", out exceptionToThrow))
/// {
/// if(exceptionToThrow == null)
/// throw;
/// else
/// throw exceptionToThrow;
/// }
/// }
/// </code>
/// </example>
/// <seealso cref="ExceptionManager.HandleException(Exception, string)"/>
bool HandleException(Exception exceptionToHandle, string policyName, out Exception exceptionToThrow);
/// <summary>
/// For advanced scenarios (suggested you use "Process" over this method): Handles the
/// specified <see cref="Exception"/> object according to the rules configured for <paramref name="policyName"/>.
/// </summary>
/// <param name="exceptionToHandle">An <see cref="Exception"/> object.</param>
/// <param name="policyName">The name of the policy to handle.</param>
/// <returns>
/// Whether or not a rethrow is recommended.
/// </returns>
/// <example>
/// The following code shows the usage of the
/// exception handling framework.
/// <code>
/// try
/// {
/// Foo();
/// }
/// catch (Exception e)
/// {
/// if (exceptionManager.HandleException(e, "policy")) throw;
/// }
/// </code>
/// </example>
/// <seealso cref="ExceptionManager.Process"/>
bool HandleException(Exception exceptionToHandle, string policyName);
/// <summary>
/// Excecutes the supplied delegate <paramref name="action"/> and handles
/// any thrown exception according to the rules configured for <paramref name="policyName"/>.
/// </summary>
/// <param name="action">The delegate to execute.</param>
/// <param name="policyName">The name of the policy to handle.</param>
/// <param name="finallyAction">A delegate to execute as if in a "finally" block.</param>
/// <example>
/// The following code shows one usage of this method.
/// <code>
/// exceptionManager.Process(() => { Foo(); }, "policy", () => { CleanUpResources(); });
/// </code>
/// </example>
/// <seealso cref="ExceptionManager.HandleException(Exception, string)"/>
void Process(Action action, string policyName, Action finallyAction);
/// <summary>
/// Excecutes the supplied delegate <paramref name="action"/> and handles
/// any thrown exception according to the rules configured for <paramref name="policyName"/>.
/// </summary>
/// <param name="action">The delegate to execute.</param>
/// <param name="policyName">The name of the policy to handle.</param>
/// <example>
/// The following code shows one usage of this method.
/// <code>
/// exceptionManager.Process(() => { Foo(); }, "policy");
/// </code>
/// </example>
/// <seealso cref="ExceptionManager.HandleException(Exception, string)"/>
void Process(Action action, string policyName);
/// <summary>
/// Excecutes the supplied delegate <paramref name="action"/> and handles
/// any thrown exception according to the rules configured for the systems default exception policy, ExceptionPolicy.Default
/// (please note that, though calling this method may provide some desired benefit, a well-designed application will
/// make liberal use of well-defined exception policies).
/// </summary>
/// <param name="action">The delegate to execute.</param>
/// <example>
/// The following code shows one usage of this method.
/// <code>
/// exceptionManager.Process(() => { Foo(); });
/// </code>
/// </example>
/// <seealso cref="ExceptionManager.HandleException(Exception, string)"/>
void Process(Action action);
}
public class EntLibBasedExceptionManager : ExceptionManager
{
private readonly EntLibExceptionManager exceptionManager = null;
public bool HandleException(Exception exceptionToHandle, string policyName, out Exception exceptionToThrow)
{ return exceptionManager.HandleException(exceptionToHandle, policyName, out exceptionToThrow); }
public bool HandleException(Exception exceptionToHandle, string policyName)
{ return exceptionManager.HandleException(exceptionToHandle, policyName); }
public void Process(Action action, string policyName, Action finallyAction)
{
try
{ action(); }
catch (Exception ex)
{
var exToThrow = (Exception)null;
if (HandleException(ex, policyName, out exToThrow))
{
if (exToThrow == null)
throw;
else
throw exToThrow;
}
}
finally
{
if (finallyAction != null)
Process(finallyAction, ExceptionPolicy.Default);
}
}
public void Process(Action action, string policyName)
{ Process(action, policyName, null); }
public void Process(Action action)
{ Process(action, ExceptionPolicy.Default); }
public EntLibBasedExceptionManager(EntLibExceptionManager exceptionManager)
{
Guard.AgainstNull(exceptionManager, "exceptionManager");
this.exceptionManager = exceptionManager;
}
}
public abstract class CacheItem
{
public abstract string Key { get; }
public abstract DateTime LastAccessedTime { get; }
public abstract CacheItemPriority ScavengingPriority { get; }
public abstract object Value { get; }
public abstract bool HasExpired();
public abstract void MakeEligibleForScavenging();
public abstract void MakeIneligibleForScavenging();
}
/// <summary>
/// Specifies the item priority levels.
/// </summary>
public enum CacheItemPriority
{
/// <summary>
/// Should never be seen in nature.
/// </summary>
None = 0,
/// <summary>
/// Low priority for scavenging.
/// </summary>
Low = 1,
/// <summary>
/// Normal priority for scavenging.
/// </summary>
Normal,
/// <summary>
/// High priority for scavenging.
/// </summary>
High,
/// <summary>
/// Non-removable priority for scavenging.
/// </summary>
NotRemovable
}
/// <summary>
/// Allows end users to implement their own cache item expiration schema. Should be marked as Serializable.
/// </summary>
public interface CacheItemExpirationPolicy
{
/// <summary>
/// Specifies if item has expired or not.
/// </summary>
/// <returns>Returns true if the item has expired, otherwise false.</returns>
bool HasExpired();
/// <summary>
/// Called to tell the expiration that the CacheItem to which this expiration belongs has been touched by the user
/// </summary>
void Notify();
/// <summary>
/// Called to give the instance the opportunity to initialize itself from information contained in the CacheItem.
/// </summary>
/// <param name="owningCacheItem">CacheItem that owns this expiration policy</param>
void Initialize(CacheItem owningCacheItem);
}
[Serializable]
sealed public class AbsoluteTimeExpirationPolicy : CacheItemExpirationPolicy
{
private DateTime expirationDateTime;
public bool HasExpired()
{ return DateTime.Now.ToUniversalTime().Ticks >= this.expirationDateTime.Ticks; }
public void Notify()
{ }
public void Initialize(CacheItem owningCacheItem)
{ }
public AbsoluteTimeExpirationPolicy(DateTime dateTime)
{
Guard.Against(dateTime, dt => dt <= DateTime.Now, Resources.ConstructedOrProvidedTimeCannotBeLessThanCurrentTime, "dateTime");
this.expirationDateTime = dateTime.ToUniversalTime();
}
public AbsoluteTimeExpirationPolicy(TimeSpan duration) : this(DateTime.Now + duration)
{ }
}
[Serializable]
sealed public class FileDependentExpirationPolicy : CacheItemExpirationPolicy
{
private string dependentFilePath = null;
private DateTime dependentFileLastModifiedTime = default(DateTime);
private static void EnsureFileIsAccessible(string filePath)
{ new FileIOPermission(FileIOPermissionAccess.Read, filePath).Demand(); }
public bool HasExpired()
{
EnsureFileIsAccessible(dependentFilePath);
return !File.Exists(dependentFilePath)
|| (DateTime.Compare(dependentFileLastModifiedTime, File.GetLastWriteTime(dependentFilePath)) != 0);
}
public void Notify()
{ }
public void Initialize(CacheItem owningCacheItem)
{ }
public FileDependentExpirationPolicy(string filePath)
{
Guard.AgainstNullOrEmpty(filePath, "filePath");
EnsureFileIsAccessible(filePath);
Guard.Against(filePath, path => !File.Exists(path), Resources.ProvidedFilePathMustExist, "filePath");
this.dependentFilePath = Path.GetFullPath(filePath);
this.dependentFileLastModifiedTime = File.GetLastWriteTime(filePath);
}
}
[Serializable]
sealed internal class NoExpirationPolicy : CacheItemExpirationPolicy
{
public bool HasExpired()
{ return false; }
public void Notify()
{ }
public void Initialize(CacheItem owningCacheItem)
{ }
}
[Serializable]
sealed internal class SlidingTimeExpirationPolicy : CacheItemExpirationPolicy
{
private DateTime timeLastUsed = default(DateTime);
private TimeSpan maxDurationOfNonUsageBeforeExpiration = default(TimeSpan);
public bool HasExpired()
{ return DateTime.Now.ToUniversalTime().Ticks >= (timeLastUsed.ToUniversalTime().Ticks + maxDurationOfNonUsageBeforeExpiration.Ticks); }
public void Notify()
{ timeLastUsed = DateTime.Now; }
public void Initialize(CacheItem owningCacheItem)
{
Guard.AgainstNull(owningCacheItem, "owningCacheItem");
timeLastUsed = owningCacheItem.LastAccessedTime;
}
public SlidingTimeExpirationPolicy(TimeSpan maxDurationOfNonUsageBeforeExpiration)
{
Guard.Against(
maxDurationOfNonUsageBeforeExpiration,
timeSpan => timeSpan.TotalSeconds < 1,
Resources.MaxDurationOfNonUseBeforeExpirationMustBeGreaterThanOrEqualToOneSecond,
"maxDurationOfNonUsageBeforeExpiration"
);
this.maxDurationOfNonUsageBeforeExpiration = maxDurationOfNonUsageBeforeExpiration;
}
}
public enum CacheItemRemovedReason
{
/// <summary>
/// The item has expired.
/// </summary>
Expired,
/// <summary>
/// The item was manually removed from the cache.
/// </summary>
Removed,
/// <summary>
/// The item was removed by the scavenger because it had a lower priority that any other item in the cache.
/// </summary>
Scavenged,
/// <summary>
/// Reserved. Do not use.
/// </summary>
Unknown = 9999
}
/// <summary>
/// This interface defines the contract that must be implemented to create an object that can be used to refresh
/// an expired item from the cache. The implementing class must be serializable. Care must be taken when implementing
/// this interface not to create an object that maintains too much state about its environment, as all portions of its
/// environment will be serialized as well, creating possibly a huge object graph.
/// </summary>
public interface CacheItemRemovedHandler
{
/// <summary>
/// Called when an item expires from the cache. This method can be used to notify an application that
/// the expiration occured, cause the item to be refetched and refreshed from its original location, or
/// perform any other application-specific action.
/// </summary>
/// <param name="removedKey">Key of item removed from cache. Will never be null.</param>
/// <param name="expiredValue">Value from cache item that was just expired</param>
/// <param name="removalReason">Reason the item was removed from the cache. See <see cref="CacheItemRemovedReason"/></param>
/// <remarks>This method should catch and handle any exceptions thrown during its operation. No exceptions should leak
/// out of it.</remarks>
void OnCacheItemRemoved(string removedKey, object expiredValue, CacheItemRemovedReason removalReason);
}
public interface CacheManager
{
/// <summary>
/// Adds new CacheItem to cache. If another item already exists with the same key, that item is removed before
/// the new item is added. If any failure occurs during this process, the cache will not contain the item being added.
/// </summary>
/// <param name="key">Identifier for this CacheItem</param>
/// <param name="value">Value to be stored in cache. May be null.</param>
/// <param name="scavengingPriority">Specifies the new item's scavenging priority. See <see cref="CacheItemPriority" /> for more information.</param>
/// <param name="cacheItemRemovedHandler">Object provided to allow the cache to handle the removal of an item that has been expired. May be null.</param>
/// <param name="expirations">Param array specifying the expiration policies to be applied to this item. May be null or omitted.</param>
/// <exception cref="ArgumentNullException">Provided key is null</exception>
/// <exception cref="ArgumentException">Provided key is an empty string</exception>
/// <remarks>The CacheManager can be configured to use different storage mechanisms in which to store the CacheItems.
/// Each of these storage mechanisms can throw exceptions particular to their own implementations.</remarks>
void Add(string key, object value, CacheItemPriority scavengingPriority, CacheItemRemovedHandler cacheItemRemovedHandler, params CacheItemExpirationPolicy[] expirations);
/// <summary>
/// Adds new CacheItem to cache. If another item already exists with the same key, that item is removed before
/// the new item is added. If any failure occurs during this process, the cache will not contain the item being added.
/// </summary>
/// <param name="key">Identifier for this CacheItem</param>
/// <param name="value">Value to be stored in cache. May be null.</param>
/// <param name="cacheItemRemovedHandler">Object provided to allow the cache to handle the removal of an item that has been expired. May be null.</param>
/// <param name="expirations">Param array specifying the expiration policies to be applied to this item. May be null or omitted.</param>
/// <exception cref="ArgumentNullException">Provided key is null</exception>
/// <exception cref="ArgumentException">Provided key is an empty string</exception>
/// <remarks>The CacheManager can be configured to use different storage mechanisms in which to store the CacheItems.
/// Each of these storage mechanisms can throw exceptions particular to their own implementations.</remarks>
void Add(string key, object value, CacheItemRemovedHandler cacheItemRemovedHandler, params CacheItemExpirationPolicy[] expirations);
/// <summary>
/// Adds new CacheItem to cache. If another item already exists with the same key, that item is removed before
/// the new item is added. If any failure occurs during this process, the cache will not contain the item being added.
/// </summary>
/// <param name="key">Identifier for this CacheItem</param>
/// <param name="value">Value to be stored in cache. May be null.</param>
/// <param name="scavengingPriority">Specifies the new item's scavenging priority. See <see cref="CacheItemPriority" /> for more information.</param>
/// <param name="expirations">Param array specifying the expiration policies to be applied to this item. May be null or omitted.</param>
/// <exception cref="ArgumentNullException">Provided key is null</exception>
/// <exception cref="ArgumentException">Provided key is an empty string</exception>
/// <remarks>The CacheManager can be configured to use different storage mechanisms in which to store the CacheItems.
/// Each of these storage mechanisms can throw exceptions particular to their own implementations.</remarks>
void Add(string key, object value, CacheItemPriority scavengingPriority, params CacheItemExpirationPolicy[] expirations);
/// <summary>
/// Adds new CacheItem to cache. If another item already exists with the same key, that item is removed before
/// the new item is added. If any failure occurs during this process, the cache will not contain the item being added.
/// </summary>
/// <param name="key">Identifier for this CacheItem</param>
/// <param name="value">Value to be stored in cache. May be null.</param>
/// <param name="expirations">Param array specifying the expiration policies to be applied to this item. May be null or omitted.</param>
/// <exception cref="ArgumentNullException">Provided key is null</exception>
/// <exception cref="ArgumentException">Provided key is an empty string</exception>
/// <remarks>The CacheManager can be configured to use different storage mechanisms in which to store the CacheItems.
/// Each of these storage mechanisms can throw exceptions particular to their own implementations.</remarks>
void Add(string key, object value, params CacheItemExpirationPolicy[] expirations);
/// <summary>
/// Returns true if key refers to item current stored in cache
/// </summary>
/// <param name="key">Key of item to check for</param>
/// <returns>True if item referenced by key is in the cache</returns>
bool Contains(string key);
/// <summary>
/// Returns the number of items currently in the cache.
/// </summary>
int Count { get; }
/// <summary>
/// Removes all items from the cache. If an error occurs during the removal, the cache is left unchanged.
/// </summary>
/// <remarks>The CacheManager can be configured to use different storage mechanisms in which to store the CacheItems.
/// Each of these storage mechanisms can throw exceptions particular to their own implementations.</remarks>
void Flush();
/// <summary>
/// Returns the value associated with the given key.
/// </summary>
/// <param name="key">Key of item to return from cache.</param>
/// <returns>Value stored in cache</returns>
/// <exception cref="ArgumentNullException">Provided key is null</exception>
/// <exception cref="ArgumentException">Provided key is an empty string</exception>
/// <remarks>The CacheManager can be configured to use different storage mechanisms in which to store the CacheItems.
/// Each of these storage mechanisms can throw exceptions particular to their own implementations.</remarks>
T Get<T>(string key);
/// <summary>
/// Tries to return the value associated with the given key.
/// </summary>
/// <param name="key">Key of item to return from cache.</param>
/// <param name="cachedItem">The cached item.</param>
/// <returns>whether or not the key was found</returns>
/// <exception cref="ArgumentNullException">Provided key is null</exception>
/// <exception cref="ArgumentException">Provided key is an empty string</exception>
/// <remarks>The CacheManager can be configured to use different storage mechanisms in which to store the CacheItems.
/// Each of these storage mechanisms can throw exceptions particular to their own implementations.</remarks>
bool TryGet<T>(string key, out T cachedItem);
/// <summary>
/// Removes the given item from the cache. If no item exists with that key, this method does nothing.
/// </summary>
/// <param name="key">Key of item to remove from cache.</param>
/// <exception cref="ArgumentNullException">Provided key is null</exception>
/// <exception cref="ArgumentException">Provided key is an empty string</exception>
/// <remarks>The CacheManager can be configured to use different storage mechanisms in which to store the CacheItems.
/// Each of these storage mechanisms can throw exceptions particular to their own implementations.</remarks>
void Remove(string key);
/// <summary>
/// Returns the item identified by the provided key
/// </summary>
/// <param name="key">Key to retrieve from cache</param>
/// <exception cref="ArgumentNullException">Provided key is null</exception>
/// <exception cref="ArgumentException">Provided key is an empty string</exception>
/// <remarks>The CacheManager can be configured to use different storage mechanisms in which to store the cache items.
/// Each of these storage mechanisms can throw exceptions particular to their own implementations.</remarks>
object this[string key] { get; }
}
public interface CacheManagers
{
CacheManager GetDefault();
CacheManager Get(string name);
}
sealed public class ExtendableCacheItemExpirationPolicyResolver
{ }
public static class CachedItem
{
public static readonly ExtendableCacheItemExpirationPolicyResolver Expires = new ExtendableCacheItemExpirationPolicyResolver();
}
internal static class CacheItemPriorityExtensions
{
public static EntLibCacheItemPriority ToEntLib(this CacheItemPriority priority)
{ return (EntLibCacheItemPriority)((int)priority); }
public static CacheItemPriority ToFramework(this EntLibCacheItemPriority priority)
{ return (CacheItemPriority)((int)priority); }
}
internal static class CacheItemRemovedReasonExtensions
{
public static EntLibCacheItemRemovedReason ToEntLib(this CacheItemRemovedReason reason)
{ return (EntLibCacheItemRemovedReason)((int)reason); }
public static CacheItemRemovedReason ToFramework(this EntLibCacheItemRemovedReason reason)
{ return (CacheItemRemovedReason)((int)reason); }
}
[Serializable]
sealed internal class EntLibCacheItemExpirationWrapper : ICacheItemExpiration
{
private CacheItemExpirationPolicy policy = null;
public bool HasExpired()
{ return policy.HasExpired(); }
public void Initialize(EntLibCacheItem owningCacheItem)
{ policy.Initialize(new EntLibCacheItemWrapper(owningCacheItem)); }
public void Notify()
{ policy.Notify(); }
public EntLibCacheItemExpirationWrapper(CacheItemExpirationPolicy policy)
{
Guard.AgainstNull(policy, "policy");
this.policy = policy;
}
}
[Serializable]
sealed internal class EntLibCacheItemRemovedHandlerWrapper : ICacheItemRefreshAction
{
private CacheItemRemovedHandler removedHandler = null;
public void Refresh(string removedKey, object expiredValue, EntLibCacheItemRemovedReason removalReason)
{ removedHandler.OnCacheItemRemoved(removedKey, expiredValue, removalReason.ToFramework()); }
public EntLibCacheItemRemovedHandlerWrapper(CacheItemRemovedHandler removedHandler)
{
Guard.AgainstNull(removedHandler, "removedHandler");
this.removedHandler = removedHandler;
}
}
sealed internal class EntLibCacheItemWrapper : CacheItem
{
private readonly EntLibCacheItem cacheItem = null;
internal EntLibCacheItem WrappedCacheItem
{ get { return cacheItem; } }
public override string Key
{ get { return cacheItem.Key; } }
public override DateTime LastAccessedTime
{ get { return cacheItem.LastAccessedTime; } }
public override CacheItemPriority ScavengingPriority
{ get { return cacheItem.ScavengingPriority.ToFramework(); } }
public override object Value
{ get { return cacheItem.Value; } }
public override bool HasExpired()
{ return cacheItem.HasExpired(); }
public override void MakeEligibleForScavenging()
{ cacheItem.MakeEligibleForScavenging(); }
public override void MakeIneligibleForScavenging()
{ cacheItem.MakeNotEligibleForScavenging(); }
internal EntLibCacheItemWrapper(EntLibCacheItem cacheItem)
{
Guard.AgainstNull(cacheItem, "cacheItem");
this.cacheItem = cacheItem;
}
}
sealed internal class EntLibCacheManagerAdapter : CacheManager
{
private readonly ICacheManager cacheManager = null;
private readonly ICacheItemExpiration[] EmptyExpirations = new ICacheItemExpiration[] { };
public void Add(string key, object value, CacheItemPriority scavengingPriority, CacheItemRemovedHandler cacheItemRemovedHandler, params CacheItemExpirationPolicy[] expirations)
{
cacheManager.Add(
key,
value,
scavengingPriority.ToEntLib(),
cacheItemRemovedHandler == null ? null : new EntLibCacheItemRemovedHandlerWrapper(cacheItemRemovedHandler),
expirations == null ? EmptyExpirations : expirations.Select(expiration => new EntLibCacheItemExpirationWrapper(expiration)).ToArray()
);
}
public void Add(string key, object value, CacheItemRemovedHandler cacheItemRemovedHandler, params CacheItemExpirationPolicy[] expirations)
{ Add(key, value, CacheItemPriority.Normal, cacheItemRemovedHandler, expirations); }
public void Add(string key, object value, CacheItemPriority scavengingPriority, params CacheItemExpirationPolicy[] expirations)
{ Add(key, value, scavengingPriority, null, expirations); }
public void Add(string key, object value, params CacheItemExpirationPolicy[] expirations)
{ Add(key, value, (CacheItemRemovedHandler) null, expirations); }
public bool Contains(string key)
{ return cacheManager.Contains(key); }
public int Count
{ get { return cacheManager.Count; } }
public void Flush()
{ cacheManager.Flush(); }
public T Get<T>(string key)
{ return (T) cacheManager.GetData(key); }
public bool TryGet<T>(string key, out T cachedItem)
{
var couldOrNot = Contains(key);
cachedItem = couldOrNot ? Get<T>(key) : default(T);
return couldOrNot;
}
public void Remove(string key)
{ cacheManager.Remove(key); }
public object this[string key]
{ get { return cacheManager[key]; } }
public EntLibCacheManagerAdapter(ICacheManager cacheManager)
{ this.cacheManager = cacheManager; }
}
sealed internal class EntLibCacheManagersAdapter : CacheManagers
{
private readonly Components components = null;
public CacheManager GetDefault()
{ return new EntLibCacheManagerAdapter(components.Get<EntLibCacheManager>()); }
public CacheManager Get(string name)
{ return new EntLibCacheManagerAdapter(components.Get<EntLibCacheManager>(name)); }
public EntLibCacheManagersAdapter(Components components)
{
Guard.AgainstNull(components, "components");
this.components = components;
}
}
public interface Logger
{
/// <summary>
/// Writes a new log entry to the default category.
/// </summary>
/// <param name="message">message to log; value from ToString() method from message object.</param>
void Log(object message);
/// <summary>
/// Writes a new log entry to the default category with a dictionary of extended properties
/// </summary>
/// <param name="message">message to log; value from ToString() method from message object.</param>
/// <param name="properties">Dictionary of key/value pairs to log.</param>
void Log(object message, IDictionary<string, object> properties);
/// <summary>
/// Writes a new log entry to a specific collection of categories.
/// </summary>
/// <param name="message">message to log; value from ToString() method from message object.</param>
/// <param name="categories">Category names used to route the log entry to a one or more trace listeners.</param>
void Log(object message, IEnumerable<string> categories);
/// <summary>
/// Writes a new log entry to a specific category.
/// </summary>
/// <param name="message">message to log; value from ToString() method from message object.</param>
/// <param name="category">Category name used to route the log entry to a one or more trace listeners.</param>
void Log(object message, string category);
/// <summary>
/// Write a new log entry to a specific collection of categories with a dictionary of extended properties.
/// </summary>
/// <param name="message">message to log; value from ToString() method from message object.</param>
/// <param name="categories">Category names used to route the log entry to a one or more trace listeners.</param>
/// <param name="properties">Dictionary of key/value pairs to log.</param>
void Log(object message, IEnumerable<string> categories, IDictionary<string, object> properties);
/// <summary>
/// Write a new log entry with a specific collection of categories and priority.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="categories">Category names used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
void Log(object message, IEnumerable<string> categories, int priority);
/// <summary>
/// Write a new log entry to a specific category with a dictionary of extended properties.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="category">Category name used to route the log entry to a one or more trace listeners.</param>
/// <param name="properties">Dictionary of key/value pairs to log.</param>
void Log(object message, string category, IDictionary<string, object> properties);
/// <summary>
/// Write a new log entry with a specific category and priority.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="category">Category name used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
void Log(object message, string category, int priority);
/// <summary>
/// Write a new log entry to with a specific collection of categories, priority and a dictionary of extended properties.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="categories">Category names used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
/// <param name="properties">Dictionary of key/value pairs to log.</param>
void Log(object message, IEnumerable<string> categories, int priority, IDictionary<string, object> properties);
/// <summary>
/// Write a new log entry with a specific collection of categories, priority and event id.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="categories">Category names used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
/// <param name="eventId">Event number or identifier.</param>
void Log(object message, IEnumerable<string> categories, int priority, int eventId);
/// <summary>
/// Write a new log entry to with a specific category, priority and a dictionary of extended properties.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="category">Category name used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
/// <param name="properties">Dictionary of key/value pairs to log.</param>
void Log(object message, string category, int priority, IDictionary<string, object> properties);
/// <summary>
/// Write a new log entry with a specific category, priority and event id.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="category">Category name used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
/// <param name="eventId">Event number or identifier.</param>
void Log(object message, string category, int priority, int eventId);
/// <summary>
/// Write a new log entry with a specific collection of categories, priority, event id and severity.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="categories">Category names used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
/// <param name="eventId">Event number or identifier.</param>
/// <param name="severity">Log entry severity as a System.Diagnostics.TraceEventType enumeration. (Unspecified, Information, Warning or Error).</param>
void Log(object message, IEnumerable<string> categories, int priority, int eventId, TraceEventType severity);
/// <summary>
/// Write a new log entry with a specific category, priority, event id and severity.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="category">Category name used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
/// <param name="eventId">Event number or identifier.</param>
/// <param name="severity">Log entry severity as a System.Diagnostics.TraceEventType enumeration. (Unspecified, Information, Warning or Error).</param>
void Log(object message, string category, int priority, int eventId, TraceEventType severity);
/// <summary>
/// Write a new log entry with a specific collection of categories, priority, event id, severity and title.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="categories">Category names used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
/// <param name="eventId">Event number or identifier.</param>
/// <param name="severity">Log message severity as a System.Diagnostics.TraceEventType enumeration. (Unspecified, Information, Warning or Error).</param>
/// <param name="title">Additional description of the log entry message</param>
void Log(object message, IEnumerable<string> categories, int priority, int eventId, TraceEventType severity, string title);
/// <summary>
/// Write a new log entry with a specific category, priority, event id, severity and title.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="category">Category name used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
/// <param name="eventId">Event number or identifier.</param>
/// <param name="severity">Log message severity as a System.Diagnostics.TraceEventType enumeration. (Unspecified, Information, Warning or Error).</param>
/// <param name="title">Additional description of the log entry message</param>
void Log(object message, string category, int priority, int eventId, TraceEventType severity, string title);
/// <summary>
/// Write a new log entry with a specific category, priority, event Id, severity title and dictionary of extended properties.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="categories">Category names used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
/// <param name="eventId">Event number or identifier.</param>
/// <param name="severity">Log message severity as a System.Diagnostics.TraceEventType enumeration. (Unspecified, Information, Warning or Error).</param>
/// <param name="title">Additional description of the log entry message.</param>
/// <param name="properties">Dictionary of key/value pairs to log.</param>
void Log(object message, IEnumerable<string> categories, int priority, int eventId, TraceEventType severity, string title, IDictionary<string, object> properties);
/// <summary>
/// Write a new log entry with a specific category, priority, event Id, severity title and dictionary of extended properties.
/// </summary>
/// <param name="message">Message body to log. Value from ToString() method from message object.</param>
/// <param name="category">Category name used to route the log entry to a one or more trace listeners.</param>
/// <param name="priority">Only messages must be above the minimum priority are processed.</param>
/// <param name="eventId">Event number or identifier.</param>
/// <param name="severity">Log message severity as a System.Diagnostics.TraceEventType enumeration. (Unspecified, Information, Warning or Error).</param>
/// <param name="title">Additional description of the log entry message.</param>
/// <param name="properties">Dictionary of key/value pairs to log.</param>
void Log(object message, string category, int priority, int eventId, TraceEventType severity, string title, IDictionary<string, object> properties);
}
internal class EntLibLogWriterAdapter : Logger
{
private readonly LogWriter logWriter = null;
public void Log(object message)
{ logWriter.Write(message); }
public void Log(object message, IDictionary<string, object> properties)
{ logWriter.Write(message, properties); }
public void Log(object message, IEnumerable<string> categories)
{ logWriter.Write(message, categories); }
public void Log(object message, string category)
{ logWriter.Write(message, category); }
public void Log(object message, IEnumerable<string> categories, IDictionary<string, object> properties)
{ logWriter.Write(message, categories, properties); }
public void Log(object message, IEnumerable<string> categories, int priority)
{ logWriter.Write(message, categories, priority); }
public void Log(object message, string category, IDictionary<string, object> properties)
{ logWriter.Write(message, category, properties); }
public void Log(object message, string category, int priority)
{ logWriter.Write(message, category, priority); }
public void Log(object message, IEnumerable<string> categories, int priority, IDictionary<string, object> properties)
{ logWriter.Write(message, categories, priority, properties); }
public void Log(object message, IEnumerable<string> categories, int priority, int eventId)
{ logWriter.Write(message, categories, priority, eventId); }
public void Log(object message, string category, int priority, IDictionary<string, object> properties)
{ logWriter.Write(message, category, priority, properties); }
public void Log(object message, string category, int priority, int eventId)
{ logWriter.Write(message, category, priority, eventId); }
public void Log(object message, IEnumerable<string> categories, int priority, int eventId, TraceEventType severity)
{ logWriter.Write(message, categories, priority, eventId, severity); }
public void Log(object message, string category, int priority, int eventId, TraceEventType severity)
{ logWriter.Write(message, category, priority, eventId, severity); }
public void Log(object message, IEnumerable<string> categories, int priority, int eventId, TraceEventType severity, string title)
{ logWriter.Write(message, categories, priority, eventId, severity, title); }
public void Log(object message, string category, int priority, int eventId, TraceEventType severity, string title)
{ logWriter.Write(message, category, priority, eventId, severity, title); }
public void Log(object message, IEnumerable<string> categories, int priority, int eventId, TraceEventType severity, string title, IDictionary<string, object> properties)
{ logWriter.Write(message, categories, priority, eventId, severity, title, properties); }
public void Log(object message, string category, int priority, int eventId, TraceEventType severity, string title, IDictionary<string, object> properties)
{ logWriter.Write(message, category, priority, eventId, severity, title, properties); }
public EntLibLogWriterAdapter(LogWriter logWriter)
{
Guard.AgainstNull(logWriter, "logWriter");
this.logWriter = logWriter;
}
}
[ConfigurationElementType(typeof(CustomTraceListenerData))]
public class DebugTraceListener : CustomTraceListener
{
public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
{
if ((data is LogEntry) && (Formatter != null))
WriteLine(Formatter.Format((LogEntry)data));
else
WriteLine(data.ToString());
}
public override void Write(string message)
{ Debug.Write(message); }
public override void WriteLine(string message)
{ Debug.WriteLine(message); }
}
public interface Authorizer
{
bool IsAuthorizedTo(IPrincipal user, string context);
}
public abstract class PrincipalToken
{ }
public interface PrincipalCache
{
IPrincipal GetPrincipal(PrincipalToken token);
PrincipalToken SavePrincipal(IPrincipal principal);
void SavePrincipal(IPrincipal principal, PrincipalToken token);
void ExpirePrincipal(PrincipalToken token);
}
internal class EntLibPrincipalToken : PrincipalToken
{
internal IToken Token
{ get; private set; }
internal EntLibPrincipalToken(IToken token)
{ Token = token; }
}
sealed internal class EntLibAuthorizationRuleProviderAdapter : Authorizer
{
private readonly IAuthorizationProvider authorizationProvider = null;
private readonly ExceptionManager exceptionManager = null;
public bool IsAuthorizedTo(IPrincipal user, string context)
{
var isAuthorizedOrNot = Settings.Default.UserShouldBeAuthorizedForUnconfiguredAuthorizationContext;
exceptionManager.Process(
() => isAuthorizedOrNot = authorizationProvider.Authorize(user, context),
ExceptionPolicy.AuthorizingUserInContext
);
return isAuthorizedOrNot;
}
public EntLibAuthorizationRuleProviderAdapter(IAuthorizationProvider authorizationProvider, ExceptionManager exceptionManager)
{
Guard.AgainstNull(authorizationProvider, "authorizationProvider");
Guard.AgainstNull(exceptionManager, "exceptionManager");
this.authorizationProvider = authorizationProvider;
this.exceptionManager = exceptionManager;
}
}
sealed internal class EntLibSecurityCacheProviderAdapter : PrincipalCache
{
private ISecurityCacheProvider securityCacheProvider = null;
public IPrincipal GetPrincipal(PrincipalToken token)
{ return securityCacheProvider.GetPrincipal(((EntLibPrincipalToken)token).Token); }
public PrincipalToken SavePrincipal(IPrincipal principal)
{ return new EntLibPrincipalToken(securityCacheProvider.SavePrincipal(principal)); }
public void SavePrincipal(IPrincipal principal, PrincipalToken token)
{ securityCacheProvider.SavePrincipal(principal, ((EntLibPrincipalToken)token).Token); }
public void ExpirePrincipal(PrincipalToken token)
{ securityCacheProvider.ExpirePrincipal(((EntLibPrincipalToken)token).Token); }
public EntLibSecurityCacheProviderAdapter(ISecurityCacheProvider securityCacheProvider)
{ this.securityCacheProvider = securityCacheProvider; }
}
public interface Cryptographer
{
/// <summary>
/// Compares plain text input with a computed hash using the given hash provider instance.
/// </summary>
/// <remarks>
/// Use this method to compare hash values. Since hashes contain a random "salt" value, two seperately generated
/// hashes of the same plain text will result in different values.
/// </remarks>
/// <param name="hashInstance">A hash instance from configuration.</param>
/// <param name="plaintext">The input as a string for which you want to compare the hash to.</param>
/// <param name="hashedText">The hash as a string for which you want to compare the input to.</param>
/// <returns><c>true</c> if plainText hashed is equal to the hashedText. Otherwise, <c>false</c>.</returns>
bool CompareHash(string hashInstance, string plaintext, string hashedText);
/// <overrides>
/// Compares plain text input with a computed hash using the given hash provider instance.
/// </overrides>
/// <summary>
/// Compares plain text input with a computed hash using the given hash provider instance.
/// </summary>
/// <remarks>
/// Use this method to compare hash values. Since hashes may contain a random "salt" value, two seperately generated
/// hashes of the same plain text may result in different values.
/// </remarks>
/// <param name="hashInstance">A hash instance from configuration.</param>
/// <param name="plaintext">The input for which you want to compare the hash to.</param>
/// <param name="hashedText">The hash value for which you want to compare the input to.</param>
/// <returns><c>true</c> if plainText hashed is equal to the hashedText. Otherwise, <c>false</c>.</returns>
bool CompareHash(string hashInstance, byte[] plaintext, byte[] hashedText);
/// <overrides>
/// Computes the hash value of plain text using the given hash provider instance
/// </overrides>
/// <summary>
/// Computes the hash value of plain text using the given hash provider instance
/// </summary>
/// <param name="hashInstance">A hash instance from configuration.</param>
/// <param name="plaintext">The input for which to compute the hash.</param>
/// <returns>The computed hash code.</returns>
byte[] CreateHash(string hashInstance, byte[] plaintext);
/// <summary>
/// Computes the hash value of plain text using the given hash provider instance
/// </summary>
/// <param name="hashInstance">A hash instance from configuration.</param>
/// <param name="plaintext">The input for which to compute the hash.</param>
/// <returns>The computed hash code.</returns>
string CreateHash(string hashInstance, string plaintext);
/// <summary>
/// Decrypts a cipher text using a specified symmetric cryptography provider.
/// </summary>
/// <param name="symmetricInstance">A symmetric instance from configuration.</param>
/// <param name="ciphertext">The cipher text for which you want to decrypt.</param>
/// <returns>The resulting plain text.</returns>
byte[] DecryptSymmetric(string symmetricInstance, byte[] ciphertext);
/// <summary>
/// Decrypts a cipher text using a specified symmetric cryptography provider.
/// </summary>
/// <param name="symmetricInstance">A symmetric instance from configuration.</param>
/// <param name="ciphertextBase64">The cipher text as a base64 encoded string for which you want to decrypt.</param>
/// <returns>The resulting plain text as a string.</returns>
string DecryptSymmetric(string symmetricInstance, string ciphertextBase64);
/// <summary>
/// Encrypts a secret using a specified symmetric cryptography provider.
/// </summary>
/// <param name="symmetricInstance">A symmetric instance from configuration.</param>
/// <param name="plaintext">The input for which you want to encrypt.</param>
/// <returns>The resulting cipher text.</returns>
byte[] EncryptSymmetric(string symmetricInstance, byte[] plaintext);
/// <summary>
/// Encrypts a secret using a specified symmetric cryptography provider.
/// </summary>
/// <param name="symmetricInstance">A symmetric instance from configuration.</param>
/// <param name="plaintext">The input as a base64 encoded string for which you want to encrypt.</param>
/// <returns>The resulting cipher text as a base64 encoded string.</returns>
string EncryptSymmetric(string symmetricInstance, string plaintext);
}
sealed internal class EntLibCryptographyManagerAdapter : Cryptographer
{
private readonly CryptographyManager cryptographyManager = null;
public bool CompareHash(string hashInstance, string plaintext, string hashedText)
{ return cryptographyManager.CompareHash(hashInstance, plaintext, hashedText); }
public bool CompareHash(string hashInstance, byte[] plaintext, byte[] hashedText)
{ return cryptographyManager.CompareHash(hashInstance, plaintext, hashedText); }
public byte[] CreateHash(string hashInstance, byte[] plaintext)
{ return cryptographyManager.CreateHash(hashInstance, plaintext); }
public string CreateHash(string hashInstance, string plaintext)
{ return cryptographyManager.CreateHash(hashInstance, plaintext); }
public byte[] DecryptSymmetric(string symmetricInstance, byte[] ciphertext)
{ return cryptographyManager.DecryptSymmetric(symmetricInstance, ciphertext); }
public string DecryptSymmetric(string symmetricInstance, string ciphertextBase64)
{ return cryptographyManager.DecryptSymmetric(symmetricInstance, ciphertextBase64); }
public byte[] EncryptSymmetric(string symmetricInstance, byte[] plaintext)
{ return cryptographyManager.EncryptSymmetric(symmetricInstance, plaintext); }
public string EncryptSymmetric(string symmetricInstance, string plaintext)
{ return cryptographyManager.EncryptSymmetric(symmetricInstance, plaintext); }
public EntLibCryptographyManagerAdapter(CryptographyManager cryptographyManager)
{ this.cryptographyManager = cryptographyManager; }
}
[ConfigurationElementType(typeof(CustomSymmetricCryptoProviderData))]
public class GeneralPurposeSymmetricCryptoProvider : ISymmetricCryptoProvider
{
private const string key = "!@#$FS3423fwwrt2";
private static readonly byte[] keyAsBytes = UTF8Encoding.UTF8.GetBytes(key);
private readonly AesManaged cryptographer = new AesManaged()
{
Key = keyAsBytes,
IV = keyAsBytes
};
public byte[] Decrypt(byte[] ciphertext)
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, cryptographer.CreateDecryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(ciphertext, 0, ciphertext.Length);
cryptoStream.Flush();
cryptoStream.Close();
return memoryStream.ToArray();
}
}
}
public byte[] Encrypt(byte[] plaintext)
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, cryptographer.CreateEncryptor(), CryptoStreamMode.Write))
{
cryptoStream.Write(plaintext, 0, plaintext.Length);
cryptoStream.FlushFinalBlock();
cryptoStream.Close();
return memoryStream.ToArray();
}
}
}
public GeneralPurposeSymmetricCryptoProvider(NameValueCollection ignored)
{ }
}
sealed public class QueryResultAccessor : ScopeLimitedObject, IEnumerable<QueryResultAccessor.DataRecord>
{
sealed public class DataField
{
public string Name
{ get; private set; }
public object Value
{ get; private set; }
internal DataField(string name, object value)
{
Name = name;
Value = value;
}
}
sealed public class DataRecord : IndexableByName<object>, IEnumerable<DataField>
{
private readonly IDictionary<string, DataField> fields = null;
public bool TryGet(string name, out object entry)
{
var field = (DataField)null;
var couldOrNot = fields.TryGetValue(name, out field);
entry = couldOrNot ? field.Value : null;
return couldOrNot;
}
public object this[string name]
{ get { return fields[name].Value; } }
public IEnumerator<DataField> GetEnumerator()
{ return fields.Values.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator()
{ return GetEnumerator(); }
IEnumerator<object> IEnumerable<object>.GetEnumerator()
{
foreach (var dataField in this)
yield return dataField.Value;
}
internal DataRecord(IDictionary<int, string> fieldNamesByNum, Func<int, object> getFieldValue)
{
var sortedFields = new SortedDictionary<string, DataField>();
var fieldName = (string)null;
var numFields = fieldNamesByNum.Count; // separated out for performance
for (var i = 0; i < numFields; i++)
{
fieldName = fieldNamesByNum[i];
sortedFields[fieldName] = new DataField(fieldName, getFieldValue(i));
}
this.fields = sortedFields;
}
}
private class DataRecordEnumerator : ScopeLimitedObject, IEnumerator<DataRecord>
{
private const int InitialIndex = -1;
private Func<int, DataRecord> tryGetRecord = null;
private IDictionary<int, string> fieldNamesByNum = null;
private int currentIndex = InitialIndex;
public DataRecord Current
{ get; private set; }
object IEnumerator.Current
{ get { return Current; } }
protected override void OnDisposeExplicit()
{
base.OnDisposeExplicit();
tryGetRecord = null;
fieldNamesByNum = null;
}
public bool MoveNext()
{ return (Current = tryGetRecord(++currentIndex)) != null; }
public void Reset()
{ currentIndex = InitialIndex; }
public DataRecordEnumerator(Func<int, DataRecord> tryGetRecord, IDictionary<int, string> fieldNamesByNum)
{
Guard.AgainstNull(tryGetRecord, "tryGetRecord");
Guard.AgainstNull(fieldNamesByNum, "fieldNamesByNum");
this.tryGetRecord = tryGetRecord;
this.fieldNamesByNum = fieldNamesByNum;
}
}
private const int InitialIndex = -1;
private int maxIndexRead = InitialIndex;
private IList<DataRecord> readRecords = new List<DataRecord>();
private IDictionary<int, string> fieldNamesByNum = new SortedDictionary<int, string>();
private IDataReader reader = null;
protected override void OnDisposeExplicit()
{
base.OnDisposeExplicit();
readRecords = null;
fieldNamesByNum = null;
reader.Dispose();
reader = null;
}
public IEnumerator<DataRecord> GetEnumerator()
{ return new DataRecordEnumerator(TryGetRecord, fieldNamesByNum); }
IEnumerator IEnumerable.GetEnumerator()
{ return GetEnumerator(); }
private object GetFieldValue(int fieldNum)
{ return reader[fieldNum]; }
private DataRecord TryGetRecord(int index)
{
var record = (DataRecord)null;
if (index <= maxIndexRead)
record = readRecords[index];
else
{
if (reader.Read())
readRecords.Insert(maxIndexRead = index, record = new DataRecord(fieldNamesByNum, GetFieldValue));
}
return record;
}
public QueryResultAccessor(IDataReader reader)
{
Guard.AgainstNull(reader, "reader");
Guard.Against(reader, r => r.IsClosed, Resources.CannotUtilizeClosedIDataReader, "reader");
this.reader = reader;
var fieldCount = reader.FieldCount; // separated out for performance reasons
for (var i = 0; i < fieldCount; i++)
fieldNamesByNum[i] = reader.GetName(i);
}
}
public interface Database
{
//
// Summary:
// Does this Database object support asynchronous execution?
bool SupportsAsync { get; }
//
// Summary:
// Initiates the asynchronous execution of the storedProcedureName using the
// given parameterValues which will return the number of rows affected.
//
// Parameters:
// storedProcedureName:
// The name of the stored procedure to execute.
//
// parameterValues:
// An array of paramters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// callback:
// The async callback to execute when the result of the operation is available.
// Pass null if you don't want to use a callback.
//
// state:
// Additional state object to pass to the callback.
//
// Returns:
// An System.IAsyncResult that can be used to poll or wait for results, or both;
// this value is also needed when invoking Microsoft.Practices.EnterpriseLibrary.Data.Database.EndExecuteNonQuery(System.IAsyncResult),
// which returns the number of affected records.
IAsyncResult BeginExecuteNonQuery(string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues);
//
// Summary:
// Initiates the asynchronous execution of the storedProcedureName using the
// given parameterValues inside a transaction which will return the number of
// rows affected.
//
// Parameters:
// storedProcedureName:
// The name of the stored procedure to execute.
//
// transaction:
// The System.Data.Common.DbTransaction to execute the command within.
//
// callback:
// The async callback to execute when the result of the operation is available.
// Pass null if you don't want to use a callback.
//
// state:
// Additional state object to pass to the callback.
//
// parameterValues:
// An array of paramters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// An System.IAsyncResult that can be used to poll or wait for results, or both;
// this value is also needed when invoking Microsoft.Practices.EnterpriseLibrary.Data.Database.EndExecuteNonQuery(System.IAsyncResult),
// which returns the number of affected records.
IAsyncResult BeginExecuteNonQuery(DbTransaction transaction, string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues);
//
// Summary:
// Initiates the asynchronous execution of storedProcedureName using the given
// parameterValues which will return a System.Data.IDataReader.
//
// Parameters:
// storedProcedureName:
// The name of the stored procedure to execute.
//
// callback:
// The async callback to execute when the result of the operation is available.
// Pass null if you don't want to use a callback.
//
// state:
// Additional state object to pass to the callback.
//
// parameterValues:
// An array of parameters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// An System.IAsyncResult that can be used to poll or wait for results, or both;
// this value is also needed when invoking Microsoft.Practices.EnterpriseLibrary.Data.Database.EndExecuteReader(System.IAsyncResult),
// which returns the System.Data.IDataReader.
IAsyncResult BeginExecuteReader(string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues);
//
// Summary:
// Initiates the asynchronous execution of storedProcedureName using the given
// parameterValues inside a transaction which will return a System.Data.IDataReader.
//
// Parameters:
// transaction:
// The System.Data.Common.DbTransaction to execute the command within.
//
// storedProcedureName:
// The name of the stored procedure to execute.
//
// callback:
// The async callback to execute when the result of the operation is available.
// Pass null if you don't want to use a callback.
//
// state:
// Additional state object to pass to the callback.
//
// parameterValues:
// An array of parameters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// An System.IAsyncResult that can be used to poll or wait for results, or both;
// this value is also needed when invoking Microsoft.Practices.EnterpriseLibrary.Data.Database.EndExecuteReader(System.IAsyncResult),
// which returns the System.Data.IDataReader.
IAsyncResult BeginExecuteReader(DbTransaction transaction, string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues);
//
// Summary:
// Initiates the asynchronous execution of storedProcedureName using the given
// parameterValues which will return a query result accessor.
//
// Parameters:
// storedProcedureName:
// The name of the stored procedure to execute.
//
// callback:
// The async callback to execute when the result of the operation is available.
// Pass null if you don't want to use a callback.
//
// state:
// Additional state object to pass to the callback.
//
// parameterValues:
// An array of parameters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// An System.IAsyncResult that can be used to poll or wait for results, or both;
// this value is also needed when invoking Microsoft.Practices.EnterpriseLibrary.Data.Database.EndExecuteQuery(System.IAsyncResult),
// which returns the query result accessor.
IAsyncResult BeginExecuteQuery(string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues);
//
// Summary:
// Initiates the asynchronous execution of storedProcedureName using the given
// parameterValues inside a transaction which will return a query result accessor.
//
// Parameters:
// transaction:
// The System.Data.Common.DbTransaction to execute the command within.
//
// storedProcedureName:
// The name of the stored procedure to execute.
//
// callback:
// The async callback to execute when the result of the operation is available.
// Pass null if you don't want to use a callback.
//
// state:
// Additional state object to pass to the callback.
//
// parameterValues:
// An array of parameters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// An System.IAsyncResult that can be used to poll or wait for results, or both;
// this value is also needed when invoking Microsoft.Practices.EnterpriseLibrary.Data.Database.EndExecuteQuery(System.IAsyncResult),
// which returns the query result accessor.
IAsyncResult BeginExecuteQuery(DbTransaction transaction, string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues);
//
// Summary:
// Initiates the asynchronous execution of storedProcedureName using the given
// parameterValues which will return a single value.
//
// Parameters:
// storedProcedureName:
// The name of the stored procedure to execute.
//
// callback:
// The async callback to execute when the result of the operation is available.
// Pass null if you don't want to use a callback.
//
// state:
// Additional state object to pass to the callback.
//
// parameterValues:
// An array of parameters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// An System.IAsyncResult that can be used to poll or wait for results, or both;
// this value is also needed when invoking Microsoft.Practices.EnterpriseLibrary.Data.Database.EndExecuteScalar(System.IAsyncResult),
// which returns the actual result.
IAsyncResult BeginExecuteScalar(string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues);
//
// Summary:
// Initiates the asynchronous execution of storedProcedureName using the given
// parameterValues inside a transaction which will return a single value.
//
// Parameters:
// transaction:
// The System.Data.Common.DbTransaction to execute the command within.
//
// storedProcedureName:
// The name of the stored procedure to execute.
//
// callback:
// The async callback to execute when the result of the operation is available.
// Pass null if you don't want to use a callback.
//
// state:
// Additional state object to pass to the callback.
//
// parameterValues:
// An array of parameters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// An System.IAsyncResult that can be used to poll or wait for results, or both;
// this value is also needed when invoking Microsoft.Practices.EnterpriseLibrary.Data.Database.EndExecuteScalar(System.IAsyncResult),
// which returns the actual result.
IAsyncResult BeginExecuteScalar(DbTransaction transaction, string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues);
//
// Summary:
// Finishes asynchronous execution of a SQL statement, returning the number
// of affected records.
//
// Parameters:
// asyncResult:
// The System.IAsyncResult returned by a call to any overload of Microsoft.Practices.EnterpriseLibrary.Data.Database.BeginExecuteNonQuery(System.Data.Common.DbCommand,System.AsyncCallback,System.Object).
//
// Returns:
// The number of affected records.
int EndExecuteNonQuery(IAsyncResult asyncResult);
//
// Summary:
// Finishes asynchronous execution of a Transact-SQL statement, returning an
// System.Data.IDataReader.
//
// Parameters:
// asyncResult:
// The System.IAsyncResult returned by a call to any overload of BeginExecuteReader.
//
// Returns:
// An System.Data.IDataReader object that can be used to consume the queried
// information.
IDataReader EndExecuteReader(IAsyncResult asyncResult);
//
// Summary:
// Finishes asynchronous execution of a Transact-SQL statement, returning a
// query result accessor.
//
// Parameters:
// asyncResult:
// The System.IAsyncResult returned by a call to any overload of BeginExecuteReader.
//
// Returns:
// A query result accessor that can be used to consume the queried
// information.
QueryResultAccessor EndExecuteQuery(IAsyncResult asyncResult);
//
// Summary:
// Finishes asynchronous execution of a Transact-SQL statement, returning the
// first column of the first row in the result set returned by the query. Extra
// columns or rows are ignored.
//
// Parameters:
// asyncResult:
// The System.IAsyncResult returned by a call to any overload of BeginExecuteScalar.
//
// Returns:
// The value of the first column of the first row in the result set returned
// by the query. If the result didn't have any columns or rows null (Nothing
// in Visual Basic).
object EndExecuteScalar(IAsyncResult asyncResult);
//
// Summary:
// Executes the storedProcedureName using the given parameterValues and returns
// the number of rows affected.
//
// Parameters:
// storedProcedureName:
// The name of the stored procedure to execute.
//
// parameterValues:
// An array of paramters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// The number of rows affected
int ExecuteNonQuery(string storedProcedureName, params object[] parameterValues);
//
// Summary:
// Executes the storedProcedureName using the given parameterValues within a
// transaction and returns the number of rows affected.
//
// Parameters:
// transaction:
// The System.Data.IDbTransaction to execute the command within.
//
// storedProcedureName:
// The name of the stored procedure to execute.
//
// parameterValues:
// An array of parameters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// The number of rows affected.
int ExecuteNonQuery(DbTransaction transaction, string storedProcedureName, params object[] parameterValues);
//
// Summary:
// Executes the storedProcedureName with the given parameterValues and returns
// an System.Data.IDataReader through which the result can be read. It is the
// responsibility of the caller to close the connection and reader when finished.
//
// Parameters:
// storedProcedureName:
// The command that contains the query to execute.
//
// parameterValues:
// An array of paramters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// An System.Data.IDataReader object.
IDataReader ExecuteReader(string storedProcedureName, params object[] parameterValues);
//
// Summary:
// Executes the storedProcedureName with the given parameterValues within the
// given transaction and returns an System.Data.IDataReader through which the
// result can be read. It is the responsibility of the caller to close the
// connection and reader when finished.
//
// Parameters:
// transaction:
// The System.Data.IDbTransaction to execute the command within.
//
// storedProcedureName:
// The command that contains the query to execute.
//
// parameterValues:
// An array of paramters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// An System.Data.IDataReader object.
IDataReader ExecuteReader(DbTransaction transaction, string storedProcedureName, params object[] parameterValues);
//
// Summary:
// Executes the storedProcedureName with the given parameterValues and returns
// the first column of the first row in the result set returned by the query.
// Extra columns or rows are ignored.
//
// Parameters:
// storedProcedureName:
// The stored procedure to execute.
//
// parameterValues:
// An array of paramters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// The first column of the first row in the result set.
object ExecuteScalar(string storedProcedureName, params object[] parameterValues);
//
// Summary:
// Executes the storedProcedureName with the given parameterValues within a
// transaction and returns the first column of the first row in the result set
// returned by the query. Extra columns or rows are ignored.
//
// Parameters:
// transaction:
// The System.Data.IDbTransaction to execute the command within.
//
// storedProcedureName:
// The stored procedure to execute.
//
// parameterValues:
// An array of paramters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// The first column of the first row in the result set.
object ExecuteScalar(DbTransaction transaction, string storedProcedureName, params object[] parameterValues);
//
// Summary:
// Executes the storedProcedureName with the given parameterValues and returns
// a result accessor through which the result can be read. It is the
// responsibility of the caller to close the accessor when finished (using Dispose).
//
// Parameters:
// storedProcedureName:
// The command that contains the query to execute.
//
// parameterValues:
// An array of paramters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// a query result accessor
QueryResultAccessor ExecuteQuery(string storedProcedureName, params object[] parameterValues);
//
// Summary:
// Executes the storedProcedureName with the given parameterValues within the
// given transaction and returns a result accessor through which the
// result can be read. It is the responsibility of the caller to close the
// accessor when finished (using dispose).
//
// Parameters:
// transaction:
// The System.Data.IDbTransaction to execute the command within.
//
// storedProcedureName:
// The command that contains the query to execute.
//
// parameterValues:
// An array of paramters to pass to the stored procedure. The parameter values
// must be in call order as they appear in the stored procedure.
//
// Returns:
// a query result accessor
QueryResultAccessor ExecuteQuery(DbTransaction transaction, string storedProcedureName, params object[] parameterValues);
}
public interface Databases
{
Database GetDefault();
Database Get(string name);
}
sealed internal class EntLibDatabaseAdapter : Database
{
private readonly EntLibDatabase database = null;
public bool SupportsAsync
{ get { return database.SupportsAsync; } }
public IAsyncResult BeginExecuteNonQuery(string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues)
{ return database.BeginExecuteNonQuery(storedProcedureName, callback, state, parameterValues); }
public IAsyncResult BeginExecuteNonQuery(DbTransaction transaction, string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues)
{ return database.BeginExecuteNonQuery(transaction, storedProcedureName, callback, state, parameterValues); }
public IAsyncResult BeginExecuteReader(string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues)
{ return database.BeginExecuteReader(storedProcedureName, callback, state, parameterValues); }
public IAsyncResult BeginExecuteReader(DbTransaction transaction, string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues)
{ return database.BeginExecuteReader(transaction, storedProcedureName, callback, state, parameterValues); }
public IAsyncResult BeginExecuteScalar(string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues)
{ return database.BeginExecuteScalar(storedProcedureName, callback, state, parameterValues); }
public IAsyncResult BeginExecuteScalar(DbTransaction transaction, string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues)
{ return database.BeginExecuteScalar(transaction, storedProcedureName, callback, state, parameterValues); }
public IAsyncResult BeginExecuteQuery(string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues)
{ return BeginExecuteReader(storedProcedureName, callback, state, parameterValues); }
public IAsyncResult BeginExecuteQuery(DbTransaction transaction, string storedProcedureName, AsyncCallback callback, object state, params object[] parameterValues)
{ return BeginExecuteReader(transaction, storedProcedureName, callback, state, parameterValues); }
public int EndExecuteNonQuery(IAsyncResult asyncResult)
{ return database.EndExecuteNonQuery(asyncResult); }
public IDataReader EndExecuteReader(IAsyncResult asyncResult)
{ return database.EndExecuteReader(asyncResult); }
public QueryResultAccessor EndExecuteQuery(IAsyncResult asyncResult)
{ return new QueryResultAccessor(EndExecuteReader(asyncResult)); }
public object EndExecuteScalar(IAsyncResult asyncResult)
{ return database.EndExecuteScalar(asyncResult); }
public int ExecuteNonQuery(string storedProcedureName, params object[] parameterValues)
{ return database.ExecuteNonQuery(storedProcedureName, parameterValues); }
public int ExecuteNonQuery(DbTransaction transaction, string storedProcedureName, params object[] parameterValues)
{ return database.ExecuteNonQuery(transaction, storedProcedureName, parameterValues); }
public IDataReader ExecuteReader(string storedProcedureName, params object[] parameterValues)
{ return database.ExecuteReader(storedProcedureName, parameterValues); }
public IDataReader ExecuteReader(DbTransaction transaction, string storedProcedureName, params object[] parameterValues)
{ return database.ExecuteReader(transaction, storedProcedureName, parameterValues); }
public QueryResultAccessor ExecuteQuery(string storedProcedureName, params object[] parameterValues)
{ return new QueryResultAccessor(ExecuteReader(storedProcedureName, parameterValues)); }
public QueryResultAccessor ExecuteQuery(DbTransaction transaction, string storedProcedureName, params object[] parameterValues)
{ return new QueryResultAccessor(ExecuteReader(transaction, storedProcedureName, parameterValues)); }
public object ExecuteScalar(string storedProcedureName, params object[] parameterValues)
{ return database.ExecuteScalar(storedProcedureName, parameterValues); }
public object ExecuteScalar(DbTransaction transaction, string storedProcedureName, params object[] parameterValues)
{ return database.ExecuteScalar(transaction, storedProcedureName, parameterValues); }
public EntLibDatabaseAdapter(EntLibDatabase database)
{
Guard.AgainstNull(database, "database");
this.database = database;
}
}
sealed internal class EntLibDatabasesAdapter : Databases
{
private readonly Components components = null;
public Database GetDefault()
{ return new EntLibDatabaseAdapter(components.Get<EntLibDatabase>()); }
public Database Get(string name)
{ return new EntLibDatabaseAdapter(components.Get<EntLibDatabase>(name)); }
public EntLibDatabasesAdapter(Components components)
{
Guard.AgainstNull(components, "components");
this.components = components;
}
}