Introduction
The built-in ASP.NET Membership, Roles, Profile providers fits into many Web site use-cases, but not all.
While I was wokring on some of my projects I have experienced the need of having a light ASP.NET providers pack.
Providers that work without database or additional services. Providers that can easy deploy with a Web site under restricted hosting environment.
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.
Background
This 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.
In fact I'm pretty satisfied of using it on my projects, thus I have decided to share it and uploaded on Codeplex.
The Persistable base class
This article is about the base class for all XML storage classes.
First of all this is not invented originally by me.
I grab it from the net, made it generic, did some fixed and prepare it for synchronized usage.
I have implemented a simple, but robust caching in the Persistable class, in order to improve the performance.
In fact I'm using it as a base class in all my projects when I need fast and robust objects' persistance to XML files.
Here is the source code of Persistable class:
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 /////////////////////////////////////////////////////////////
protected virtual bool IsEmpty {
get {
return (_value == null || (_value is ICollection && (_value as ICollection).Count == 0));
}
}
public virtual bool IsSynchronized {
get {
return false;
}
}
public virtual object SyncRoot {
get {
if (_syncRoot == null)
Interlocked.CompareExchange(ref this._syncRoot, new object(), null);
return _syncRoot;
}
}
protected virtual T Value {
get {
if (IsEmpty) Load();
return _value;
}
set { _value = value; }
}
#endregion
#region Construct //////////////////////////////////////////////////////////////
protected Persistable(string fileName, TimeSpan cacheSlidingExpiration) {
_fileName = fileName;
_serializer = new XmlSerializer(typeof(T));
_slidingExpiration = cacheSlidingExpiration;
}
protected Persistable(string fileName)
: this(fileName, DefaultSlidingExpiration) {
}
#endregion
#region Methods /////////////////////////////////////////////////////////////////
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;
}
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;
}
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 -
void AddFileNotifier() {
HttpRuntime.Cache.Insert(_fileName, new object(), new CacheDependency(_fileName),
Cache.NoAbsoluteExpiration, _slidingExpiration, CacheItemPriority.Normal, new CacheItemRemovedCallback(OnFileChanged));
}
void OnFileChanged(string key, object value, CacheItemRemovedReason reason) {
if (key == _fileName) _value = default(T);
}
#endregion
#endregion
}
Points of Interest
You can find ASP.NET XmlProviders project and all the source code at http://codeplex.com/aspnetxmlproviders
History
- 22.Mar.2008 - Initial release
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.