介绍
{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和对象[]。它的构造如下:
aspectHandler - 与AspectContext的委托作为第一个参数,对象[]作为第二个参数,为返回void通过参数 - 对象数组作为其第二个参数时调用aspectHandlerpublic Decoration(DecorationDelegate aspectHandler, object[] parameters)
DecorationDelegate的定义如下:
{体C3}
从本质上讲,一个方面的AOP容器是一个方法需要签名DecorationDelegate的。
希望,给你足够的背景,要了解以下方面的注册码。
的代码:{的C4}
注册的预处理方面SharedLib.SharedConcerns.EnterLog的后处理方面SharedLib.SharedConcerns.ExitLog实现IRepositorylt RepositoryDepartment 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,解决RepositoryDepartment对象。它返回一个IRepositorylt接口; IDepartmentgt;的变量rpDepartment。当使用rpDepartment调用getAll方法,你会看到之前进入日志和退出日志该方法的执行目标。
下一步,rpDepartment.RepList [0]。DepartmentID将进入日志写在返回之前的部门ID。是这样的原因是,在aopcontainer用来解决个别部门内部的RepositoryDepartment 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容器。:加里Ĥ郭