• 应用AOP简化WinForm的异步操作——Spring.NET实现


    此篇狗尾续狗,有炒现饭之嫌。但为了学习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和配置还是很强大的。
      
    
    
    
    
    



    作者:CnSharp.com
    本文版权归CnSharp.com和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    【60.97%】【BZOJ 1925】 [Sdoi2010]地精部落
    【14.06%】【hdu 5904】LCIS
    【50.40%】【BZOJ 4553】[Tjoi2016&Heoi2016]序列
    【52.55%】【BZOJ 4520】K远点对
    洛谷——P2446 [SDOI2010]大陆争霸
    Python模块之re
    Docker从入门到实战
    分析增加站点权重的四大切入点(转载)
    远程桌面连接不上|windows server 2003 sp2 termdd.sys(转载)
    不同服务器数据库之间的数据操作(转载)
  • 原文地址:https://www.cnblogs.com/cnsharp/p/2301363.html
Copyright © 2020-2023  润新知