|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionThe built-in ASP.NET Membership, Roles, Profile providers fits into many Web site use-cases, but not all. The obvious solution was to implement ASP.NET Membership, Role, Profile providers base on XML file storages. In this series I'll go through the steps of my implementation of ASP.NET XmlProviders. BackgroundThis ASP.NET Xml Providers pack is an evolution of examples, articles and samples of code which I have packed and improved for the needs of some of the projects I was working on. The Persistable base classThis article is about the base class for all XML storage classes. Here is the source code of Persistable class: /// <summary>
/// Generic class for a perssitable object.
/// Encapsulates the logic to load/save data from/to the filesystem.
/// To speed up the acces, caching is used.
/// </summary>
/// <typeparam name="T">class or struct with all the data-fields that must be persisted</typeparam>
public class Persistable<T> where T : new() {
#region Static Fields ///////////////////////////////////////////////////////////
public static readonly TimeSpan DefaultSlidingExpiration = TimeSpan.FromMinutes(30);
#endregion
#region Fields /////////////////////////////////////////////////////////////////
string _fileName;
ReaderWriterLock _lock = new ReaderWriterLock();
XmlSerializer _serializer;
TimeSpan _slidingExpiration;
[NonSerialized]
object _syncRoot;
T _value;
#endregion
#region Properties /////////////////////////////////////////////////////////////
/// <summary>
/// Gets a value indicating whether this instance is empty.
/// </summary>
/// <value><c>true</c> if this instance is empty; otherwise, <c>false</c>.</value>
protected virtual bool IsEmpty {
get {
return (_value == null || (_value is ICollection && (_value as ICollection).Count == 0));
}
}
/// <summary>
/// Gets a value indicating whether this instance is synchronized.
/// </summary>
/// <value>
/// <c>true</c> if this instance is synchronized; otherwise, <c>false</c>.
/// </value>
public virtual bool IsSynchronized {
get {
return false;
}
}
/// <summary>
/// Gets the sync root.
/// </summary>
/// <value>The sync root.</value>
public virtual object SyncRoot {
get {
if (_syncRoot == null)
Interlocked.CompareExchange(ref this._syncRoot, new object(), null);
return _syncRoot;
}
}
/// <summary>
/// Gets or sets the data.
/// </summary>
/// <value>The data.</value>
protected virtual T Value {
get {
if (IsEmpty) Load();
return _value;
}
set { _value = value; }
}
#endregion
#region Construct //////////////////////////////////////////////////////////////
/// <summary>
/// Creates a instance of Persistable. Also creates a instance of T
/// </summary>
protected Persistable(string fileName, TimeSpan cacheSlidingExpiration) {
_fileName = fileName;
_serializer = new XmlSerializer(typeof(T));
_slidingExpiration = cacheSlidingExpiration;
}
/// <summary>
///
/// </summary>
/// <param name="fileName"></param>
protected Persistable(string fileName)
: this(fileName, DefaultSlidingExpiration) {
}
#endregion
#region Methods /////////////////////////////////////////////////////////////////
/// <summary>
/// Deletes the data from the cache and filesystem
/// </summary>
/// <returns></returns>
public virtual bool Delete() {
bool success = true;
_lock.AcquireWriterLock(Timeout.Infinite);
try {
if (File.Exists(_fileName)) {
try {
File.Delete(_fileName);
}
catch { success = false; }
}
}
finally {
_lock.ReleaseWriterLock();
}
return success;
}
/// <summary>
/// Loads the data from the filesystem. For deserialization a XmlSeralizer is used.
/// </summary>
public virtual T Load() {
_lock.AcquireReaderLock(Timeout.Infinite);
try {
if (System.IO.File.Exists(_fileName)) {
using (FileStream reader = File.Open(_fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
_value = (T)_serializer.Deserialize(reader);
}
}
AddFileNotifier();
}
catch (Exception ex) {
throw new Exception(
string.Format("Unable to load persitable object from file {0}", _fileName), ex);
}
finally {
_lock.ReleaseReaderLock();
}
return _value;
}
/// <summary>
/// Persists the data back to the filesystem
/// </summary>
/// <param name="fileName">Name of the file.</param>
public virtual void Save() {
if (!IsEmpty) {
_lock.AcquireWriterLock(Timeout.Infinite);
try {
string directory = Path.GetDirectoryName(_fileName);
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);
T value = _value;
using (FileStream writer = File.Create(_fileName)) {
_serializer.Serialize(writer, value);
}
}
catch (Exception ex) {
throw new Exception(
string.Format("Unable to save persitable object to file {0}", _fileName), ex);
}
finally {
_lock.ReleaseWriterLock();
}
}
}
#region - Cache -
/// <summary>
///
/// </summary>
/// <param name="value"></param>
void AddFileNotifier() {
HttpRuntime.Cache.Insert(_fileName, new object(), new CacheDependency(_fileName),
Cache.NoAbsoluteExpiration, _slidingExpiration, CacheItemPriority.Normal, new CacheItemRemovedCallback(OnFileChanged));
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="reason"></param>
void OnFileChanged(string key, object value, CacheItemRemovedReason reason) {
// invalidate value
if (key == _fileName) _value = default(T);
}
#endregion
#endregion
}
Points of InterestYou can find ASP.NET XmlProviders project and all the source code at http://codeplex.com/aspnetxmlproviders History
|
|||||||||||||||||||||||||||||||||||