返回首页

介绍
{A}文章介绍了一个AOP模型,使任何IoC容器配置有AOP的功能。作为例子,该模型被应用到{A2的},{A3的容器。
其出版以来,AOP容器已加强了与新功能,如注册方面使用代码后创建的对象中添加方面。在这篇文章中讨论这些功能。背景
我的原因,以创建一个AOP容器是AOP的功能很容易地添加IoC容器。因此,它是有道理的,AOP的集装箱提供登记方面,就像大多数IoC容器中使用代码的方法,提供注册类型使用代码的方法。
有情况,你可能不希望一个组件中的所有对象,有一个方面,但想添加或链的各个环节,以一个特定的对象,如需要后的创作。 AOP容器提供这种灵活性,提供了一个方法,为您创建一个对象后使用。
在下面的章节中,我将讨论如何注册方面的一个组件使用代码和如何链的各个环节后,其创造的对象。温莎容器Unity容器使用IoC容器的例子。使用代码
下面的代码演示使用的AOP容器连同温莎集装箱和Unity容器。基本上,AOP容器提供了一个共同的方面的登记和解决对象的应用程序编程接口。

static void Main(string[] args)

{

    AOPContainer aopcontainer = null;

    switch (args[0])

    {

        case "0":

        //Register types for Windsor Container and create AOPWindsorContainer

            {

                IWindsorContainer windsorContainer = new WindsorContainer();

                windsorContainer.Register(AllTypes

                    .FromAssembly(Assembly.LoadFrom("Employee.dll"))

                    .Where(t => t.Name.Equals("Employee"))

                    .Configure(c => c.LifeStyle.Transient)

                ).Register(AllTypes

                    .FromAssembly(Assembly.LoadFrom("Department.dll"))

                    .Where(t => t.Name.Equals("Department"))

                    .Configure(c => c.LifeStyle.Transient)

                ).Register(AllTypes

                    .FromAssembly(Assembly.GetExecutingAssembly())

                    .Where(t => (t.Name.Equals("RepositoryEmployee") || 

                           t.Name.Equals("RepositoryDepartment")))

                    .Configure(c => c.LifeStyle.Transient)

                ).Register(Castle.MicroKernel.Registration.Component.For(typeof(List<IEmployee>))

                ).Register(Castle.MicroKernel.Registration.Component.For(typeof(List<IDepartment>))

                );



                aopcontainer = new AOPWindsorContainer(windsorContainer);

            }

            break;



        case "1": //Register types for Unity Container and create AOPUnityContainer

            {

                IUnityContainer unityContainer = new UnityContainer();

                unityContainer.RegisterType<IEmployee, Employee>(new InjectionConstructor()

                ).RegisterType<IDepartment, Department>(new InjectionConstructor()

                ).RegisterType<IRepository<IDepartment>, RepositoryDepartment>(new InjectionConstructor()

                ).RegisterType<IRepository<IEmployee>, RepositoryEmployee>(new InjectionConstructor()

                ).RegisterType<IList<IEmployee>, List<IEmployee>>(new InjectionConstructor()

                ).RegisterType<IList<IDepartment>, List<IDepartment>>(new InjectionConstructor()

                );



                aopcontainer = new AOPUnityContainer(unityContainer);

            }

            break;



        default:

            {

                Console.WriteLine("Invalid number for an AOP container.");

                Console.ReadLine();

            }

            return;

    }



    //Register Aspects

    aopcontainer.RegisterAspect<RepositoryDepartment, 

                  IRepository<IDepartment>>("GetAll",

        new Decoration(SharedLib.SharedConcerns.EnterLog, null),

        new Decoration(SharedLib.SharedConcerns.ExitLog, null)

    ).RegisterAspect<RepositoryEmployee, IRepository<IEmployee>>("GetAll",

        null,

        new Decoration((ctx, parameters) =>

        {

            object target = ctx.Target;

            if (target.GetType().ToString() == "ConsoleUtil.RepositoryEmployee")

            {

                List<IEmployee> emps = ((IRepository<IEmployee>)target).RepList;

                IEnumerable<IEmployee> query = emps.OrderByDescending(emp => emp,

                    new EmployeeLastnameComparer()).ToList<IEmployee>();

                ((IRepository<IEmployee>)target).RepList = (List<IEmployee>)query;

            }

        }, null)

    ).RegisterAspect<Department, IDepartment>("get_DepartmentID",

        new Decoration(SharedLib.SharedConcerns.EnterLog, null),

        null);



    //Set security policy.

    //Commenting out this line, the security check aspect will throw out an exception 

    Thread.GetDomain().SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);



    //Load employees and departments into a data set from an xml file.

    DataSet dsDB = new DataSet();

    dsDB.ReadXml("employees.xml");



    //Print original employees

    Console.WriteLine("Employees");

    string str = "ID\tFName\tLName\tDateOfBirth\tDepartmentID";

    Console.WriteLine(str);

    Console.WriteLine("====================================================");

    foreach (DataRow r in dsDB.Tables["Employee"].Rows)

    {

        str = r["EmployeeID"].ToString() + "\t" + 

              r["FirstName"].ToString() + "\t" + 

              r["LastName"].ToString() + "\t" + 

              r["DateOfBirth"].ToString() + "\t" + 

              r["DepartmentID"].ToString();

        Console.WriteLine(str); 

    }

    Console.WriteLine();



    IRepository<IDepartment> rpDepartment = 

      aopcontainer.Resolve<RepositoryDepartment, 

          IRepository<IDepartment>>("GetAll");

    rpDepartment.AopContainer = aopcontainer;

    rpDepartment.DataSource = dsDB;

    //The following line populates a department list and writes enter/exit logs.

    rpDepartment.GetAll();



    //The following line gets a department id and writes enter log.

    int? iDep = rpDepartment.RepList[0].DepartmentID;





    IRepository<IEmployee> rpEmployee = 

      aopcontainer.Resolve<RepositoryEmployee, 

            IRepository<IEmployee>>("GetAll");

    rpEmployee.AopContainer = aopcontainer;

    rpEmployee.DataSource = dsDB;

    //The following line populates an employee list and sorts the list.

    rpEmployee.GetAll();



    Console.WriteLine();



    //Print employees sorted by employee's last name 

    Console.WriteLine("Employees sorted by employee's last name");

    str = "ID\tFName\tLName\tDateOfBirth\tDepartmentID";

    Console.WriteLine(str);

    Console.WriteLine("====================================================");

    foreach (IEmployee em in rpEmployee.RepList)

    {

        str = em.EmployeeID.ToString() + "\t" + em.FirstName + 

              "\t" + em.LastName + "\t" + 

              em.DateOfBirth.ToShortDateString() + "\t" + 

              em.DepartmentID.ToString();

        Console.WriteLine(str);

    }

    Console.WriteLine();



    try

    {

        IEmployee oEm = rpEmployee.RepList[0];

        //Add a security check aspect to an employee before changing its property

        oEm = AOPContainer.ChainAspect<IEmployee, IEmployee>(oEm,

            "set_EmployeeID,set_FirstName,set_LastName,set_DateOfBirth,set_DepartmentID",

            new Decoration(AppConcerns.SecurityCheck, 

            new object[] { System.Threading.Thread.CurrentPrincipal }),

            null);

        //The following line check security before setting the property

        oEm.DepartmentID = 2;



        //Chain enetr/exit log aspects to the employee's DetailsByLevel method

        oEm = AOPContainer.ChainAspect<IEmployee, IEmployee>(oEm,

            "DetailsByLevel",

            new Decoration(SharedLib.SharedConcerns.EnterLog, null),

            new Decoration(SharedLib.SharedConcerns.ExitLog, null));

        //The following line write entering log before and exiting log

        //after execution of the target's DetailsByLevel(3)

        oEm.DetailsByLevel(3);

        Console.WriteLine();

    }

    catch (Exception ex)

    {

        Console.WriteLine(ex.Message);

        Console.WriteLine();

    }



    //Print employees after sort and update

    Console.WriteLine("Employees after sort and update");

    str = "ID\tFName\tLName\tDateOfBirth\tDepartmentID";

    Console.WriteLine(str);

    Console.WriteLine("====================================================");

    foreach (IEmployee em in rpEmployee.RepList)

    {

        str = em.EmployeeID.ToString() + "\t" + em.FirstName + "\t" + 

              em.LastName + "\t" + em.DateOfBirth.ToShortDateString() + 

              "\t" + em.DepartmentID.ToString();

        Console.WriteLine(str);

    }

    Console.WriteLine();



    aopcontainer.IocContainer.Dispose();



    Console.ReadLine();

}

代码的第一部分(开关... case子句之间的代码)是特定的IoC容器。也就是说,这取决于使用IoC容器,你注册你的组件的IoC容器,并建立相应的AOP容器。具体到温莎集装箱,而代码的情况下quot; 0quot;为代码的情况下quot; 1quot;是具体到Unity容器。代码基本上是IOC容器注册的类型,以便以后可以使用IoC容器解决注册类型的对象。根据使用IoC容器,你也建立了相应的AOP容器。对于温莎集装箱,一个AOPWindsorContainer被创建,通过温莎容器的实例。团结集装箱,创建AOPUnityContainer通过Unity容器的实例。
代码的其余部分是独立的IoC容器。在我们继续之前,让我解释多一点细节的RegisterAspect方法的AOPContainer。如下声明RegisterAspect。{C}的T - 目标类型(目标是原来的对象,这方面附加)实施目标类型和返回时使用的AOPContainer解决T对象的V - 接口目标的方法的方法 - 名称(如果超过一个逗号分隔),将连接指定的由preDeco和postDeco方面preDeco - 预处理装饰postDeco - 后处理装饰
装修是一个聚集的DecorationDelegate和对象[]。它的构造如下:
public Decoration(DecorationDelegate aspectHandler, object[] parameters)
aspectHandler - 与AspectContext的委托作为第一个参数,对象[]作为第二个参数,为返回void通过参数 - 对象数组作为其第二个参数时调用aspectHandler
DecorationDelegate的定义如下: {体C3}
从本质上讲,一个方面的AOP容器是一个方法需要签名DecorationDelegate的。
希望,给你足够的背景,要了解以下方面的注册码。
的代码:{的C4}
注册的预处理方面SharedLib.SharedConcerns.EnterLog的后处理方面SharedLib.SharedConcerns.ExitLog实现IRepositorylt RepositoryDe​​partment getAll方法; IDepartmentgt;SharedLib.SharedConcerns.EnterLog和SharedLib.SharedConcerns.ExitLog方面的方法写进入/退出日志,分别。
的代码:{C5的}
注册了一个空的预处理方面getAll方法到的RepositoryEmployee的和后处理方面的匿名方法实现IRepositorylt; IEmployeegt;请注意,匿名方法提供的RepositoryEmployee排序逻辑。
的代码:{5233}
注册的预处理方面SharedLib.SharedConcerns.EnterLog的和空后处理方面的get_DepartmentID方法部实现IDepartment。
我们正在做的类型登记方面登记。之前我们使用AOP容器做一些有用的东西,我们的安全政策的WindowsPrincipal加载到数据集中的部门和员工,并打印出员工。
现在,我们已经准备好要使用AOP容器做一些事情。
首先,我们使用的aopcontainer,解决RepositoryDe​​partment对象。它返回一个IRepositorylt接口; IDepartmentgt;的变量rpDepartment。当使用rpDepartment调用getAll方法,你会看到之前进入日志和退出日志该方法的执行目标。
下一步,rpDepartment.RepList [0]。DepartmentID将进入日志写在返回之前的部门ID。是这样的原因是,在aopcontainer用来解决个别部门内部的RepositoryDe​​partment GETALL。
同样,aopcontainer用于解决RepositoryEmployee的对象,它返回一个接口IRepositorylt的; IEmployeegt;的变量rpEmployee。当使用rpEmployee调用getAll方法,将雇员列表进行排序,并保存它的目标。
使用RegisterAspectlt组件注册方面,T,VGT;方法的组件由Resolvelt解决意味着所有的对象,T,VGT;将有方面的重视。不过,也有情况下,您不想组件中的所有对象,有一个方面的重视,但想补充的一个方面后创建的对象。还有的情况下,你想链更多的方面,其成立后的对象。 ChainAspectlt,T,VGT;AOPContainer方法,针对这些情况提供了一个解决方案,可用于添加或链方面的对象。
在上面的代码的try块,ChainAspectlt; IEmployeegt IEmployee,增加了安全检查方面的第一个雇员 因此,只有内置的管理员可以修改雇员的属性。如果应用程序是由一个非管理员执行,将抛出异常和财产不被修改。
运行的应用程序,输出如下:
{S0的}景点AOP容器提供一个IoC容器中添加方面的机制和一个共同的应用程序编程接口。AOP容器提供登记方面的组件能说一口流利的接口。由AOP容器解决的对象有附加的方面。AOP的容器提供了一种方法,对象创建后需要添加/链的各个环节。尽管本文讨论了与温莎和IOC容器统一的AOP容器,你应该能够很容易地与其他IoC容器相结合的AOP容器。:加里Ĥ郭

回答

评论会员: 时间:2
N