3

我正在为我的 DI 使用带有 Spring.NET 的 MS WebAPI,并使用 Sprint.NET AOP 将方法标记为事务性的。

当我将“控制器”操作标记为事务性时,我收到以下错误:

无法将类型为 'CompositionAopProxy_13695853c76b40f8b9436e27afa947f0' 的对象转换为类型 'TPMarketing.PayrollConsole.Web.Rest.Controllers.OrganisationsController'。","exceptionType":"System.InvalidCastException","stackTrace":" at lambda_method(Closure , Object , Object [] )\r\n 在 System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c_ DisplayClass13.b _c(Object instance, Object[] methodParameters)\r\n 在 System.Web.Http.Controllers.ReflectedHttpActionDescriptor .ActionExecutor.Execute(对象实例,Object[] 参数)\r\n 在 System.Web.Http.Controllers.ReflectedHttpActionDescriptor.<>c_ DisplayClass5.b _4()\r\n 在 System.Threading.Tasks.TaskHelpers。 RunSynchronously[TResult](Func`1 func,CancellationToken 取消令牌)

这是否意味着您不能将基于代理的 AOP 与 Web API 控制器一起使用?

(我有一个解决方法,我已经创建了我自己的“事务”属性,该属性继承自 ActionFilterAttribute 以仅在 Web 层中使用)

谢谢,乔丹。

编辑... 我还没有时间查看下面的 Marijns 建议,所以这是我为任何感兴趣的人提供的解决方法。这是我的动作过滤器中的代码主体:(TransactionManager 是 Spring.NET IPlatformTransactionManager)。我仍在我的服务层中使用普通的 Spring.NET Transaction 属性,这应该可以很好地配合它。

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.ReadOnly = ReadOnly;
        actionContext.Request.Properties[TRANSACTION_KEY] = TransactionManager.GetTransaction(def);
    }


    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        ITransactionStatus ts = actionExecutedContext.Request.Properties[TRANSACTION_KEY] as ITransactionStatus;
        if (ts.RollbackOnly || actionExecutedContext.Exception != null)
        {
            TransactionManager.Rollback(ts);
        }
        else
        {
            TransactionManager.Commit(ts);
        }
    }

    public bool ReadOnly { get; set; }
4

1 回答 1

0

CopositionAopProxy 基于契约,是您的接口的实现,并且不能转换为您的类,因为它不是您的类的继承,代理包含您的类的实例,作为属性,但仅实现您的类的相同接口。

查看 AOP文档

13.1.3. Spring.NET 中的 AOP 代理

Spring.NET 在运行时使用 System.Reflection.Emit 命名空间中的类生成 AOP 代理,为代理类创建必要的 IL 代码。这导致代理非常有效,并且不会对继承层次结构施加任何限制。

在 .NET 中实现 AOP 代理的另一种常见方法是使用 ContextBoundObject 和 .NET 远程处理基础结构作为拦截机制。我们不太喜欢 ContextBoundObject 方法,因为它需要需要代理的类才能直接或间接地从 ContextBoundObject 继承。在我们看来,这是一个不必要的限制,它会影响您应该如何设计您的对象模型,并且还排除了将 AOP 应用于不受您直接控制的“第 3 方”类。由于上下文切换和 .NET 远程处理基础设施的开销,上下文绑定代理也比 IL 生成的代理慢一个数量级。

Spring.NET AOP 代理也是“智能的”——因为代理配置在代理生成期间是已知的,所以生成的代理可以优化为仅在必要时通过反射调用目标方法(即,当有应用到目标方法的建议时)。在所有其他情况下,将直接调用目标方法,从而避免反射调用造成的性能损失。

最后,Spring.NET AOP 代理永远不会返回对目标对象的原始引用。每当一个目标方法返回一个对目标对象的原始引用(即“return this;”)时,AOP 代理将识别发生了什么并将返回值替换为对自身的引用。

AOP 代理生成器的当前实现使用对象组合将代理调用委托给目标对象,类似于您将如何实现经典的装饰器模式。这意味着需要代理的类必须实现一个或多个接口,在我们看来,这不仅是一个比 ContextBoundObject 继承要求更少侵入性的要求,而且还是一个很好的实践,对于服务类来说无论如何都应该遵循AOP 代理的最常见目标。在未来的版本中,我们将使用继承实现代理,这将允许您代理没有接口的类,并将删除一些使用基于组合的代理无法解决的剩余原始引用问题。

于 2014-07-24T02:18:06.717 回答