Xmlファイルをロール情報のストアとするカスタムロールプロバイダXmlRoleProviderを作成してみます。まず、プロジェクトとしてはカスタムメンバシッププロバイダーを作る。その1(モデル定義) で作成したCustomProviderというソリューションから引き続いて作業を行うことを想定して記載しています。
1. XmlRoleProviderの仕様
今回はRoleProviderで定義されている機能はサポートしたつもりです(MembershipProviderと較べて実装する機能がすくないので)。カスタムメンバシッププロバイダではApplicationNameごとにユーザを管理することはできませんでしたが、今回は管理手法をリファクタリングして、ApplicationNameごとにロールを管理できるようにしています。
実装されている機能一覧はこちら
ロール プロバイダの実装
http://msdn.microsoft.com/ja-jp/library/8fw7xh74.aspx
2.ロール情報のモデル作成
カスタムメンバシッププロバイダと同様にXmlSerializerでドメインモデルをシリアライズするようにします。
2.1 ロールモデルのスキーマ
ロールのモデルのXml表現は次のようなものとしました。rolesをルート要素。子要素roleがひとつのロールを現し、applicationNameがアプリケーション名,nameがロール名を現し、所属するユーザ名がusers要素以下のuser要素のテキストとして列挙されます。
<?xml version="1.0"?>
<roles xmlns="urn:Handcraft.RoleInfoList">
<role xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" applicationName="/" name="Director" xmlns="urn:Handcraft.RoleInfo">
<users>
<user>test</user>
<user>test1</user>
<user>Supe</user>
</users>
</role>
<role xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" applicationName="/" name="SuperRole" xmlns="urn:Handcraft.RoleInfo">
<users>
<user>Supe</user>
</users>
</role>
</roles>
2.2 Roleモデルクラスの作成
CustomProviderクラスライブラリプロジェクトにRoleInfo.csクラスを作成しRoleInfo,RoleInfoListクラスを作成します。以下のように編集します。RoleInfoクラスが一つのロール,RoleInfoクラスがロールの集合を管理するためのクラスです。ロールプロバイダで使用するためのユーティリティーメソッドがいくつか定義されています。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace CustomProvider
{
/// <summary>
/// ロール情報のモデルクラス
/// </summary>
[XmlRoot("role", Namespace = "urn:Handcraft.RoleInfo")]
public class RoleInfo
{
public RoleInfo()
{
ApplicationName = "/";
RoleName = string.Empty;
UserNames = new List<string>();
}
[XmlAttribute("applicationName")]
public string ApplicationName { get; set; }
[XmlAttribute("name")]
public string RoleName { get; set; }
[XmlIgnore]
private List<string> UserNames { get; set; }
[XmlArrayItem(typeof(string), ElementName="user")]
[XmlArray("users")]
public string[] _Users
{
get { return GetAllUserInRole(); }
set
{
RemoveAllUser();
AddUsers(value);
}
}
public void AddUser(string username)
{
UserNames.Add(username);
}
public void RemoveUser(string username)
{
UserNames.Remove(username);
}
public bool ContainUser(string username)
{
return UserNames.Contains(username);
}
public void RemoveAllUser()
{
UserNames.Clear();
}
public void AddUsers(string[] username)
{
foreach (string user in username)
{
AddUser(user);
}
}
public string[] GetAllUserInRole()
{
return UserNames.ToArray();
}
public static RoleInfo CreateRoleInfo(string applicationName, string roleName)
{
RoleInfo r = new RoleInfo { ApplicationName = applicationName, RoleName = roleName };
return r;
}
}
/// <summary>
/// ロールのキークラス
/// </summary>
class RoleKey : IComparable<RoleKey>
{
public string RoleName { get; set; }
public string ApplicationName { get; set; }
public override int GetHashCode()
{
return string.Concat(ApplicationName, RoleName).GetHashCode();
}
public override bool Equals(object obj)
{
if (!(obj is RoleKey))
{
return false;
}
RoleKey o = obj as RoleKey;
return ApplicationName.Equals(o.ApplicationName) && RoleName.Equals(o.RoleName);
}
#region IComparable<RoleKey> Members
public int CompareTo(RoleKey other)
{
int result = ApplicationName.CompareTo(other.ApplicationName);
if (result == 0)
{
return RoleName.CompareTo(other.RoleName);
}
else
{
return result;
}
}
#endregion
}
[XmlRoot("roles", Namespace="urn:Handcraft.RoleInfoList")]
public class RoleInfoList : IXmlSerializable
{
/// <summary>
/// ロール情報を格納するコレクション
/// </summary>
private SortedList<RoleKey, RoleInfo> _roles = new SortedList<RoleKey, RoleInfo>();
/// <summary>
/// RoleInfoを追加する
/// </summary>
/// <param name="roleInfo"></param>
public void AddRoleInfo(RoleInfo roleInfo)
{
_roles.Add(new RoleKey { ApplicationName = roleInfo.ApplicationName, RoleName = roleInfo.RoleName }, roleInfo);
}
/// <summary>
/// RoleInfoを削除する
/// </summary>
/// <param name="roleInfo"></param>
public void RemoveRoleInfo(RoleInfo roleInfo)
{
RemoveRoleInfo(roleInfo.ApplicationName, roleInfo.RoleName);
}
/// <summary>
/// RoleInfoを削除する
/// </summary>
/// <param name="applicationName"></param>
/// <param name="roleName"></param>
public void RemoveRoleInfo(string applicationName, string roleName)
{
_roles.Remove(new RoleKey { ApplicationName = applicationName, RoleName = roleName });
}
public bool RoleExists(string applicationName, string roleName)
{
return _roles.ContainsKey(new RoleKey { ApplicationName = applicationName, RoleName = roleName });
}
public string[] GetAllRoles(string applicationName)
{
var v = from role in _roles.Values
where role.ApplicationName == applicationName
select role.RoleName;
return v.ToArray();
}
public string[] GetRolesForUser(string applicationName, string username)
{
var v = from role in _roles.Values
where (role.ApplicationName == applicationName && role.ContainUser(username))
select role.RoleName;
return v.ToArray();
}
public RoleInfo GetRoleInfo(string applicationName, string roleName)
{
try
{
return _roles[new RoleKey { ApplicationName = applicationName, RoleName = roleName }];
}
catch (KeyNotFoundException)
{
return null;
}
}
#region IXmlSerializable Membersの実装
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
/// <summary>
/// 独自でデシリアライズを行う
/// </summary>
/// <param name="reader"></param>
public void ReadXml(System.Xml.XmlReader reader)
{
XmlSerializer s = new XmlSerializer(typeof(RoleInfo));
reader.Read();
while (reader.NodeType != System.Xml.XmlNodeType.EndElement && reader.NodeType != System.Xml.XmlNodeType.None)
{
RoleInfo o = s.Deserialize(reader) as RoleInfo;
AddRoleInfo(o);
}
}
/// <summary>
/// 独自でシリアライズを行う
/// </summary>
/// <param name="writer"></param>
public void WriteXml(System.Xml.XmlWriter writer)
{
XmlSerializer s = new XmlSerializer(typeof(RoleInfo));
foreach (RoleInfo val in _roles.Values)
{
s.Serialize(writer, val);
}
}
#endregion
}
}
XmlSerializerでシリアライズできるようにXmlElementなどがアノテートされています。詳細についてはMSDNライブラリや本サイトのサンプルXmlSerializerを使ってインスタンスをXML形式でシリアライズする を参照して下さい。一部のC# 3.0以上の機能が使われていますが、C# 2.0用に書き換えることによって.NET 2.0環境でも動作するようになります。
今回の説明は以上です。次回はXmlRoleProviderを実装してみます。