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
In the first article I have
shown you the Persistable
base class.
In this artcicle I'm going to cover the usage of the Persistable
to implement the XML membership
store.
The purpose of XML membership store is to define the membership data which have to be persisted and
how to be persisted.
The XML membership store implementation involves next classes: XmlUser
, XmlUserStore
and XmlUserStore.SynchronizedStore
.
XmlUser
XmlUser
just defines the data to be persisted per user:
<summary>
public class XmlUser {
public Guid UserKey = Guid.Empty;
public string UserName = string.Empty;
public string Password = string.Empty;
public string PasswordSalt = string.Empty;
public string Email = string.Empty;
public string PasswordQuestion = string.Empty;
public string PasswordAnswer = string.Empty;
public string Comment;
public DateTime CreationDate = DateTime.Now;
public DateTime LastActivityDate = DateTime.MinValue;
public DateTime LastLoginDate = DateTime.MinValue;
public DateTime LastPasswordChangeDate = DateTime.MinValue;
public DateTime LastLockoutDate = DateTime.MaxValue;
public bool IsApproved = true;
public bool IsLockedOut = false;
}
XmlUserStore
XmlUserStore implements Persistable and defines the persistance of all users to XML file:
public partial class XmlUserStore : Persistable<List> {
#region Properties /////////////////////////////////////////////////////////////
public virtual List Users {
get { return base.Value ?? (base.Value = new List()); }
}
#endregion
#region Construct //////////////////////////////////////////////////////////////
public XmlUserStore(string fileName)
: base(fileName) {
}
protected XmlUserStore()
: base(null) {
}
#endregion
#region Methods /////////////////////////////////////////////////////////////////
public virtual XmlUser GetUserByEmail(string email) {
List users = this.Users;
return (users != null)
? users.Find(delegate(XmlUser user) { return string.Equals(email, user.Email); })
: null;
}
public virtual XmlUser GetUserByKey(Guid key) {
List users = this.Users;
return (users != null)
? users.Find(delegate(XmlUser user) { return (user.UserKey.CompareTo(key) == 0); })
: null;
}
public virtual XmlUser GetUserByName(string name) {
List users = this.Users;
return (users != null)
? users.Find(delegate(XmlUser user) { return string.Equals(name, user.UserName); })
: null;
}
#endregion
}
XmlUserStore.SynchronizedStore
SynchronizedStore is a private nested synchronized implementation of XmlUserStore:
public partial class XmlUserStore {
class SynchronizedStore : XmlUserStore {
#region Fields /////////////////////////////////////////////////////////////////
object _root;
XmlUserStore _store;
#endregion
#region Properties /////////////////////////////////////////////////////////////
protected override bool IsEmpty {
get {
lock (_root) {
return _store.IsEmpty;
}
}
}
public override bool IsSynchronized {
get {
return true;
}
}
public override object SyncRoot {
get {
return _root;
}
}
public override List Users {
get {
lock (_root) {
return _store.Users;
}
}
}
protected override List Value {
get {
lock (_root) {
return _store.Value;
}
}
set {
lock (_root) {
_store.Value = value;
}
}
}
#endregion
#region Construct //////////////////////////////////////////////////////////////
internal SynchronizedStore(XmlUserStore store) {
_store = store;
_root = _store.SyncRoot;
}
#endregion
#region Methods /////////////////////////////////////////////////////////////////
public override bool Delete() {
lock (_root) {
return _store.Delete();
}
}
public override XmlUser GetUserByEmail(string email) {
lock (_root) {
return _store.GetUserByEmail(email);
}
}
public override XmlUser GetUserByKey(Guid key) {
lock (_root) {
return _store.GetUserByKey(key);
}
}
public override XmlUser GetUserByName(string name) {
lock (_root) {
return _store.GetUserByName(name);
}
}
public override List Load() {
lock (_root) {
return _store.Load();
}
}
public override void Save() {
lock (_root) {
_store.Save();
}
}
#endregion
}
}
Synchronized XmlUserStore
Now when we have a synchronized implementation of XmlUser store, we just have to provide the ability
to synchronize every instance of XmlUserStore.
The standard pattern to acheave that, is to add a static method Synchronized to the class with argument
the instance which have to be synchronized:
#region Static Methods //////////////////////////////////////////////////////////
[HostProtection(SecurityAction.LinkDemand, Synchronization = true)]
public static XmlUserStore Synchronized(XmlUserStore store) {
if (store == null)
throw new ArgumentNullException("store");
return new SynchronizedStore(store);
}
#endregion
Points of Interest
You can find ASP.NET XmlProviders project and all the source code at
http://codeplex.com/aspnetxmlproviders
History
- 30.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.