3

I am using MS WebAPI with Spring.NET for my DI, and making use of Sprint.NET AOP to mark methods as transactional.

When I mark a "Controller" action as transactional, I get the following error:

Unable to cast object of type 'CompositionAopProxy_13695853c76b40f8b9436e27afa947f0' to type 'TPMarketing.PayrollConsole.Web.Rest.Controllers.OrganisationsController'.","exceptionType":"System.InvalidCastException","stackTrace":" at lambda_method(Closure , Object , Object[] )\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c_DisplayClass13.b_c(Object instance, Object[] methodParameters)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.<>c_DisplayClass5.b_4()\r\n at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)

Does this mean you can't use proxy based AOP with Web API Controllers?

(I have got a workaround, I have made my own "Transaction" attribute for that inherits from ActionFilterAttribute to just use in the web tier)

thanks, Jordan.

EDIT... I haven't had time to check out Marijns suggestion below yet, so here is my workaround for anyone interested. This is the body of the code from my Action Filter: (TransactionManager is the Spring.NET IPlatformTransactionManager). I am still using the normal Spring.NET Transaction attribute in my service layer, and this should play nicely with that.

    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; }
gusgorman
  • 170
  • 1
  • 11
  • related: http://stackoverflow.com/questions/4280143/asp-net-mvc-controller-declarative-aop-with-spring-net/4346791#4346791 – Marijn Jul 09 '13 at 17:18
  • I haven't tried this with web api, but some time ago I've posted a [detailed this answer on this](http://stackoverflow.com/a/9115510/322283), in the context of a "normal" asp.net MVC controller. – Marijn Jul 09 '13 at 17:22
  • Ok will do, will probably be later in the week. – gusgorman Jul 10 '13 at 14:40

1 Answers1

0

CopositionAopProxy is based in contracts, is an implementation your interface, and cannot be cast to your class because is not a inheritance of your class, the proxy contains an instance of your class, as a property, but only implement same interfaces of your class.

Look at AOP documentation:

13.1.3. AOP Proxies in Spring.NET

Spring.NET generates AOP proxies at runtime using classes from the System.Reflection.Emit namespace to create necessary IL code for the proxy class. This results in proxies that are very efficient and do not impose any restrictions on the inheritance hierarchy.

Another common approach to AOP proxy implementation in .NET is to use ContextBoundObject and the .NET remoting infrastructure as an interception mechanism. We are not very fond of ContextBoundObject approach because it requires classes that need to be proxied to inherit from the ContextBoundObject either directly or indirectly. In our opinion this an unnecessary restriction that influences how you should design your object model and also excludes applying AOP to "3rd party" classes that are not under your direct control. Context-bound proxies are also an order of magnitude slower than IL-generated proxies, due to the overhead of the context switching and .NET remoting infrastructure.

Spring.NET AOP proxies are also "smart" - in that because proxy configuration is known during proxy generation, the generated proxy can be optimized to invoke target methods via reflection only when necessary (i.e. when there are advices applied to the target method). In all other cases the target method will be called directly, thus avoiding performance hit caused by the reflective invocation.

Finally, Spring.NET AOP proxies will never return a raw reference to a target object. Whenever a target method returns a raw reference to a target object (i.e. "return this;"), AOP proxy will recognize what happened and will replace the return value with a reference to itself instead.

The current implementation of the AOP proxy generator uses object composition to delegate calls from the proxy to a target object, similar to how you would implement a classic Decorator pattern. This means that classes that need to be proxied have to implement one or more interfaces, which is in our opinion not only a less-intruding requirement than ContextBoundObject inheritance requirements, but also a good practice that should be followed anyway for the service classes that are most common targets for AOP proxies. In a future release we will implement proxies using inheritance, which will allow you to proxy classes without interfaces as well and will remove some of the remaining raw reference issues that cannot be solved using composition-based proxies.