扩展机制的本质:
在实现持久化的类中,定义一个静态的事件成员,通过订阅事件来实现扩展功能.
我根据BlogEngine.Net系统中用户发表评论后,系统发送邮件通知功能,来描述一下BlogEngine.Net的扩展机制.
首先是扩展接口.也就是定义事件:
public class Post
{
//.........
public static event EventHandler<EventArgs> CommentAdded;
}
然后,定义一个负责引发事件的方法来通知已订阅事事件的对象,事件已经发生.
protected virtual void OnCommentAdded(Comment comment)
{
if (CommentAdded != null)
{
CommentAdded(comment, new EventArgs());
}
}
下面,就是在添加评论发表成功后,调用一下这个方法.
public void AddComment(Comment comment)
{
CancelEventArgs e = new CancelEventArgs();
OnAddingComment(comment, e);
if (!e.Cancel)
{
Comments.Add(comment);
DataUpdate();
OnCommentAdded(comment);//这里
SendNotifications(comment);
}
}
到目前为止,仅仅是实现了一个自定义的事件.:-).这里有一个关键点,那就是事件成员,是静态的.
下面再说一下,扩展功能的实现.
[Extension("Sends an e-mail to the blog owner whenever a comment is added", "1.3", "BlogEngine.NET")]//这个Attribute的功能,是告诉扩展管理者,当前扩展的描述信息,版本信息以及作者.
public class SendCommentMail
{
public SendCommentMail()
{
Post.CommentAdded += new EventHandler<EventArgs>(Post_CommentAdded);//订阅事件
}
private void Post_CommentAdded(object sender, EventArgs e)
{
//..具体的发邮件的代码.
}
}
下面也是很关键的一点,就是将扩展的功能,应用到系统中.
void Application_Start(object sender, EventArgs e)
{
try
{
// Mono does not use "__code" as the name of the App_Code assembly.
// Rather, it uses "App_Code", which is case sensitive!
string assemblyName = "__code";
Type t = Type.GetType("Mono.Runtime");
if (t != null)
assemblyName = "App_Code";
Assembly a = Assembly.Load(assemblyName);
Type[] types = a.GetTypes();
foreach (Type type in types)
{
object[] attributes = type.GetCustomAttributes(typeof(ExtensionAttribute), false);
foreach (object attribute in attributes)
{
if (ExtensionManager.ExtensionEnabled(type.Name))
{
a.CreateInstance(type.FullName);
}
}
}
}
catch (System.IO.FileNotFoundException)
{
// There are no extensions in the App_Code folder, this error can be safely ignored
}
}
这种扩展还是比较好理解的,当然,它能做的事情,也可能比较少.:-)
BlogEngine.Net是一个开源的Blog系统,地址:http://www.codeplex.com/blogengine