AOP Unity和EF POCO最佳工作流程
本文关键字:最佳 工作流程 POCO EF Unity AOP | 更新日期: 2023-09-27 18:05:49
当实体框架ORM从数据库构造POCO对象时,我想使用Unity容器在域POCO类上"注入"AOP方面
Unity可以通过两种方式轻松地将AOP方面"注入"到POCO类中(让我们分析一下利弊)
1)接口拦截器
你得到一个代理对象,它不是你的POCO类的派生对象。
你可以添加APO到一个先前存在的POCO对象,你不需要实例化一个新的。
或
2)虚拟方法拦截器
你得到一个对象,它是你的POCO类的派生对象。
你不能将AOP添加到先前存在的POCO对象中,你需要实例化一个新的。
而且. .我们可以。
a)配置统一容器并使用Resolve方法。
或
b)通过拦截类手动执行AOP注入,而不必配置Unity容器。
我还可以通过EF从数据库中检索POCO对象,然后使用带有接口拦截器的Intercept类将AOP注入到先前检索到的对象上。但是结果不会是POCO类的派生对象。
所以我需要在某些EF点(事件)上告诉EF它必须使用Unity容器来解析POCO类(或使用带有VirtualMethod Interceptor的Intercept类),因此AOP将被注入,对象将从POCO类派生。
BR Alex
我正在考虑使用PostSharp进行此类拦截
但如果我被迫使用Unity来做这件事,我能想到的唯一方法就是使用一个接口来解决问题和一个Decorator模式。
缺点是实现会很繁琐,不容易长期维护。
值得一提的是,你永远不应该访问没有在接口上声明或由装饰器指向的属性,因为对这些属性的更改不会反映但是作为下面代码的练习
public interface IProduct
{
int ProductID { get; set; }
string ProductName { get; set; }
decimal? UnitPrice { get; set; }
}
public class Product : IProduct
{
public virtual int ProductID { get; set; }
public virtual string ProductName { get; set; }
public int? SupplierID { get; set; }
public int? CategoryID { get; set; }
public string QuantityPerUnit { get; set; }
public virtual decimal? UnitPrice { get; set; }
public short? UnitsInStock { get; set; }
public short? UnitsOnOrder { get; set; }
public short? ReorderLevel { get; set; }
public bool Discontinued { get; set; }
}
public class AopProduct : Product
{
private readonly IProduct _product;
public override int ProductID { get { return _product.ProductID; } set { _product.ProductID = value; } }
public override string ProductName { get { return _product.ProductName; } set { _product.ProductName = value; } }
public override decimal? UnitPrice { get { return _product.UnitPrice; } set { _product.UnitPrice = value; } }
public AopProduct(IProduct product)
{
_product = Intercept.ThroughProxy(product, new InterfaceInterceptor(), new IInterceptionBehavior[] { new LoggingInterceptionBehavior() });
}
}
public class LoggingInterceptionBehavior : IInterceptionBehavior
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Console.WriteLine("Invoking {0} at {1}", input.MethodBase.Name, DateTime.Now.ToLongTimeString());
return getNext()(input, getNext);
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public bool WillExecute => true;
}
[TestClass]
public class UnitTest
{
[TestMethod]
public void AopProductShouldHaveAspectsAndBeProduct()
{
var product = new Product();
var aopProduct = new AopProduct(product) { ProductID = 100, ProductName = "a product", UnitPrice = 12.5m };
DisplayProduct(aopProduct);
Assert.IsTrue(aopProduct is Product);
}
private static void DisplayProduct(Product product)
{
Console.WriteLine($"{product.ProductID} - {product.ProductName} - {product.UnitPrice}");
}
}
如果我们运行代码显示
调用set_ProductID at 0:53:36
调用set_ProductID at 0:53:36
在0:53:36调用set_ProductName
在0:53:36调用set_ProductName
调用set_UnitPrice at 0:53:36
调用set_UnitPrice at 0:53:36
调用get_ProductID at 0:53:36
调用get_ProductID at 0:53:36
在0:53:36调用get_ProductName
在0:53:36调用get_ProductName
在0:53:36调用get_UnitPrice
在0:53:36调用get_UnitPrice
100 - a产品- 12,5
现在比较PostSharp的解决方案,你不需要任何额外的东西,没有接口,没有装饰,没有Unity,只是你的普通POCO类。我只是将一些属性"标记"为虚拟属性,只是为了将它们与那些我不想附加方面的属性区分开来,但如何应用这些方面取决于您。
public class Product
{
public virtual int ProductID { get; set; }
public virtual string ProductName { get; set; }
public int? SupplierID { get; set; }
public int? CategoryID { get; set; }
public string QuantityPerUnit { get; set; }
public virtual decimal? UnitPrice { get; set; }
public short? UnitsInStock { get; set; }
public short? UnitsOnOrder { get; set; }
public short? ReorderLevel { get; set; }
public bool Discontinued { get; set; }
}
[Serializable]
public sealed class LoggingOnMethodBoundaryAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
Console.WriteLine("Invoking {0} at {1}", args.Method.Name, DateTime.Now.ToLongTimeString());
}
}
[TestClass]
public class UnitTest
{
[TestMethod]
public void PSharpAopProductShouldHaveAspectsAndBeProduct()
{
var product = new Product() { ProductID = 100, ProductName = "a product", UnitPrice = 12.5m };
DisplayProduct(product);
}
private static void DisplayProduct(Product product)
{
Console.WriteLine($"{product.ProductID} - {product.ProductName} - {product.UnitPrice}");
}
}
和GlobalAspects.cs文件内容
using PostSharp.Extensibility;
[assembly: LoggingOnMethodBoundaryAspect(AttributeTargetTypes = "EFUnityAOPTest.Product", AttributeTargetTypeAttributes = MulticastAttributes.Public, AttributeTargetMemberAttributes = MulticastAttributes.Virtual)]
如果我们运行代码显示
调用set_ProductID at 1:10:39
调用set_ProductName在1:10:39
在1:10:39调用set_UnitPrice
调用get_ProductID at 1:10:39
在1:10:39调用get_ProductName
在1:10:39调用get_UnitPrice
100 - a产品- 12,5
快乐编码
BR Alex