此篇狗尾续狗,有炒现饭之嫌。但为了学习Spring.NET的AOP实现,同时也是响应前篇的读者,还是再选这个例子。这不,CCTV6又在放《失恋33天》,咱还写这个。

 

Advice(通知)

Spring.NET 使用标记接口 AopAlliance.Aop.IAdvice 来定义通知,这个接口又有四个直接的派生接口,还有两个间接地派生接口。

Spring.Aop.IAfterReturningAdvice,定义方法执行之后的通知,通知的方法名为 AfterReturning
Spring.Aop.IBeforeAdvice,定义所有的前置通知,还是一个标记接口
Spring.Aop.IMethodBeforeAdvice,方法的前置通知接口,通知的方法名称为 Before
AopAlliance.Intercept.IInterceptor, 环绕通知的接口,也是一个标记接口
AopAlliance.Intercept.IMethodInterceptor,方法的环绕通知接口,Invoke 是调用方法。

我们要用到的是IMethodInterceptor

class WorkThreadAdvice : IWorkThreadHandler, IMethodInterceptor
{
private IBlockDialog blockForm;
private bool reportProgress;
private BackgroundWorker worker;
private object returnValue;

public WorkThreadAdvice(bool reportProgress)
{
this.reportProgress = reportProgress;
}

#region Implementation of IWorkThreadHandler


void worker_DoWork(object sender, DoWorkEventArgs e)
{
var args = e.Argument as IMethodInvocation;
returnValue = args.Proceed();
}


void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
blockForm.ShowProcess(e.ProgressPercentage);
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (blockForm != null)
{
blockForm.UnBlock();
}
}

public void ReportProgress(int percentage)
{
worker.ReportProgress(percentage);
}

#endregion

#region Implementation of IMethodInterceptor

public object Invoke(IMethodInvocation invocation)
{
worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
if (reportProgress)
{
worker.WorkerReportsProgress = true;
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
}
worker.RunWorkerAsync(invocation);

blockForm = invocation.Target as IBlockDialog;
if (blockForm != null)
{
blockForm.Handler = this;
blockForm.Block();
}
while (worker.IsBusy)
{
Thread.Sleep(500);
}
return returnValue;
}

#endregion
}


Attribute

public class WorkThreadAttribute : AopAttributeBase
{
private readonly bool reportProgress;
public WorkThreadAttribute(bool reportProgress)
{
this.reportProgress = reportProgress;
}

public WorkThreadAttribute() : this(false)
{

}

public override IAdvice CreateAdvice()
{
return new WorkThreadAdvice(reportProgress);
}
}

 

UI:MVP模式

 View接口:

public interface IArticleView
{
List<ArticleModel> Articles { set; }
}
Persenter接口:
Spring.NET被拦截的类不能像PIAB那样继承MarshalByRefObject,必须实现一个接口
public interface IArticlePresenter : IAsyncPresenter
{
void Download();

IArticleView View { get; set; }
}

View实现:WinForm
    public partial class ArticleForm : BaseView, IArticleView
{
#region Constants and Fields


private readonly IArticlePresenter presenter;

#endregion

#region Constructors and Destructors

public ArticleForm()
{
this.InitializeComponent();

this.presenter = PresenterLoader.LoadPresenter<IArticlePresenter>();
this.presenter.View = this;

}

#endregion

#region Methods

protected override void OnShown(EventArgs e)
{
this.presenter.Download();
}

#endregion



#region Implementation of IArticleView

private List<ArticleModel> articles;


public List<ArticleModel> Articles
{
set;
}

#endregion
}

Presenter实现:
public class ArticlePresenter : AsyncPresenterBase,IArticlePresenter
{

private List<ArticleModel> articles;

#region Implementation of IAsyncPresenter

[WorkThread]
public void Download()
{
articles = ArticleModel.GetAll();
Thread.Sleep(3000);
}

public IArticleView View { get; set; }

protected override void Binding()
{
View.Articles = articles;
}

#endregion
}


Proxy(代理)

PIAB生成代理对象很方便:PolicyInjection.Create
Spring.NET没有如此简便的方法,但可以通过ProxyFactory来生成Proxy,同时加入自定义AOP相关的Attribute的逻辑即可
class PresenterLoader  
{
public static T LoadPresenter<T>() where T : IAsyncPresenter
{
var context = ContextRegistry.GetContext();

var sourceObject = (T)context.GetObject(typeof(T).Name.Substring(1),typeof(T));

var factory = new ProxyFactory(sourceObject);

var sourceObjectType = sourceObject.GetType();

var methodInfos = sourceObjectType.GetMethods();

foreach (MethodInfo methodInfo in methodInfos)
{
var attributes = methodInfo.GetCustomAttributes(false);

foreach (object attribute in attributes)
{
if (attribute is AopAttributeBase)
{
var pointcutAttribute = attribute as AopAttributeBase;

var advice = pointcutAttribute.CreateAdvice();
var advisor = new AttributeMatchMethodPointcutAdvisor { Advice = advice, Attribute = attribute.GetType() };
factory.AddAdvisor(advisor);
}
}
}

var obj = (T)factory.GetProxy();
return obj;
}
}


Configuration(配置)

使用过Spring.NET IoC的都知道
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>

</configSections>
<spring>
<context>
<resource uri="config://spring/objects"/>
</context>
<objects xmlns="http://www.springframework.net" >
<object id="ArticlePresenter" type="WinFormPractice.Presenters.ArticlePresenter" />
</objects>
</spring>
</configuration>

好了,Spring.NET之AOP研究告一段落。项目中咱还是用的EntLib,马上准备升级EntLib5。不过,Spring.NET的IoC和配置还是很强大的。
  


 



posted on 2011-12-25 22:43  CnSharp Studio  阅读(2268)  评论(4编辑  收藏  举报