AOP Unity和EF POCO最佳工作流程

时间:2015-08-01 22:12:41

标签: c# entity-framework dependency-injection enterprise-library

我希望在Entity Framework ORM从数据库构建POCO对象时,使用Unity容器在域POCO类上“注入”AOP方面

Unity可以使用两种方式轻松地在POCO类中“注入”AOP方面(让我们分析优缺点)

1)接口拦截器

您获得的代理OBJECT不是POCO类的DERIVED对象。

您可以将APO添加到以前存在的POCO对象中,您不需要安装新的POCO对象。

2)VirtualMethod拦截器

你得到一个对象,它是你的POCO类的一个派生对象。

你不能添加AOP到一个以前存在的POCO对象,你需要安装一个新的。

此外..我们可以。

a)配置Unity CONTAINER并使用Resolve方法。

b)MANUALY通过Intercept类进行AOP注入而无需配置Unity CONTAINER。

我还可以通过EF从数据库中检索POCO对象,然后使用带有接口拦截器的Intercept类,只是为了在先前检索的对象上注入AOP。但结果不会是POCO类的派生对象。

所以我需要在一些EF点(事件)上告诉EF它必须使用Unity容器来解析POCO类(或者使用带有VirtualMethod拦截器的Intercept类),因此将注入AOP该对象将派生于POCO类。

BR Alex

2 个答案:

答案 0 :(得分:0)

我正在考虑使用PostSharp进行此类拦截

但如果我被迫使用Unity来做,我能想象的唯一方法就是使用一个接口来解析和一个装饰模式。

缺点是实施起来很乏味,长期来说不易维护。

值得一提的是,您不应该访问未在装饰器指向的NOR接口上声明的属性,因为不会反映对这些属性的更改

但是,在下面的练习中可以实现的代码

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}");
    }
}

如果我们运行代码显示

在0:53:36调用set_ProductID

在0:53:36调用set_ProductID

在0:53:36调用set_ProductName

在0:53:36调用set_ProductName

在0:53:36调用set_UnitPrice

在0:53:36调用set_UnitPrice

在0:53:36调用get_ProductID

在0:53:36调用get_ProductID

在0:53:36调用get_ProductName

在0:53:36调用get_ProductName

在0:53:36调用get_UnitPrice

在0:53:36调用get_UnitPrice

100 - 产品--12,5

答案 1 :(得分:0)

现在比较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)]

如果我们运行代码显示

在1:10:39调用set_ProductID

在1:10:39调用set_ProductName

在1:10:39调用set_UnitPrice

在1:10:39调用get_ProductID

在1:10:39调用get_ProductName

在1:10:39调用get_UnitPrice

100 - 产品--12,5

快乐编码

BR Alex