4

A few months back I've discovered PostSharp, and for a time, it was good.

But then legal came back with an answer saying that they don't like the licence of the old versions. Then the department told me that 2.0's price was unacceptably high (for the number of seats we need)... I was extremely disapponted, but not disheartened. Can't be the only such framework, I thought.

I kept looking for a replacement, but most of it was either dead, ill maintained (especially in documentation department), for academic use, or all of the above (I'm looking at you Aspect.Net)

Then I've discovered Spring.Net, and for a time, it was good.

I've been reading the documentation and it went on to paint what seemed to be a supperior picture of an AOP nirvana. No longer was I locked to attributes to mark where I wanted code interception to take place, but it could be configured in XML and changes to it didn't require re-compile. Great.

Then I looked at the samples and saw the following, in every single usage scenario:

// Create AOP proxy using Spring.NET IoC container.
IApplicationContext ctx = ContextRegistry.GetContext();
ICommand command = (ICommand)ctx["myServiceCommand"];    
command.Execute();
if (command.IsUndoCapable)
{
    command.UnExecute();
}

Why must the first two lines of code exist? It ruins everything. This means I cannot simply provide a user with a set of aspects and attributes or XML configs that they can use by sticking appropriate attributes on the appropriate methods/classes/etc or editing the match pattern in XML. They have to modify their program logic to make this work!

Is there a way to make Spring.Net behave as PostSharp in this case? (i.e. user only needs to add attributes/XML config, not edit content of any methods.

Alternatively, is there a worthy and functioning alternative to PostSharp? I've seen a few question titled like this on SO, but none of them were actually looking to replace PostSharp, they only wanted to supplement its functionality. I need full replacement.

Alex K
  • 10,835
  • 8
  • 29
  • 34
  • Short answer is no, since PostSharp actually rewrites your code as a post-build step. I'll let the Spring experts weigh in, though; I know you can get pretty close if you use DI to instantiate your services and are willing to dabble in method interception. – Aaronaught Mar 19 '10 at 22:26
  • Hell, I'm all for re-writing! I'd even do what is needed myself. If only CCI-AST was documented well enough, or at least it's sample code was functional and sufficiently diverse >_> Is there anything else that can serve my needs on this? – Alex K Mar 19 '10 at 22:30
  • Maybe you can be more specific about what you're trying to do and where you found this example? I'm not much on Spring, as I mentioned already, but I did evaluate it once and don't remember having to embed any of that `ICommand` stuff in classes to use the Advice system. – Aaronaught Mar 19 '10 at 22:43
  • This code comes directly from the Examples folder in Spring.Net 1.3 install. ICommand is not the problem (it's basically their sample "do work" interface, from which real worker classes are derived). That stuff will exsist in client's code already. The problem is with IApplicationContext stuff. This is Spring specific and everyone who uses it will have to modify every function they want to create Command objects in... this is the unacceptable part. – Alex K Mar 19 '10 at 22:57
  • You said price of PostSharp was too high. Well compared to what ? If you really need it you should be able to prove to your manager that the price is justified for x,y,z reason etc. This is what I would do if I really deeply believe that Postsharp is essential for the success of the project. Otherwise your manager is correct and you are needlessly spending money for no real benefit. I see this sort of argument too often without a proper price-benefit evaluation. This is a comment on IT projects in general. – softveda Nov 05 '10 at 11:45
  • You have to differentiate between compiletime weaving and runtime weaving of aop aspects. spring.net does runtime weaving. Those two lines allow spring to wrap the object in an advisable proxy object. If you are using IoC you can configure all objects in spring an only get one object from springs Context (the lines you referred to) - spring will then take care of resolving every dependency of that object and also take into account if proxiing needs to take place. Also there are other alternatives to PostSharp: http://stackoverflow.com/a/5601847/27083 – tobsen Feb 02 '12 at 15:55

2 Answers2

9

In short, yes, Spring.Net AOP can work in the way you describe using XML-based configuration: you do not have to use those initial two lines of code, in fact code-based configuration is discouraged. You can configure Spring.Net AOP using XML-based configuration only and this is in fact the recommended approach.

There are several steps to this:

  1. Create your advices: BeforeAdvice, AroundAdvice, AfterReturningAdvice and ThrowsAdvice are the types of advice supported. AroundAdvice uses the AOPAlliance interface, the others use the Spring.AOP interfaces.
  2. Define your pointcuts
  3. Apply the pointcuts and advice

Example configuration (generalized from a live configuration):

  <!-- START Spring.Net AOP -->

  <object id="beforeAdvice" type="MyBeforeAdvice, MyAOP"></object>
  <object id="beforeAdvisor" type="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop">
    <property name="Advice" ref="beforeAdvice" />
  </object>

  <object id="returnsAdvice" type="MyAfterReturningAdvice, MyAOP"></object>
  <object id="returnsAdvisor" type="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop">
     <property name="Advice" ref="returnsAdvice" />
  </object>

  <object id="throwsAdvice" type="MyThrowsAdvice, MyAOP"></object>
  <object id="throwsAdvisor" type="Spring.Aop.Support.DefaultPointcutAdvisor, Spring.Aop">
    <property name="Advice" ref="throwsAdvice" />
  </object>


  <!-- Advise objects -->
  <object type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
    <property name="ObjectNames">
      <list>
        <value>*Command</value>
        <value>...</value>
      </list>
    </property>
    <property name="InterceptorNames">
      <list>
        <value>beforeAdvisor</value>
        <value>returnsAdvisor</value>
        <value>throwsAdvisor</value>
      </list>
    </property>
  </object> 


  <!-- END Spring.Net AOP -->

Weaving is performed at runtime and is pretty fast and unintrusive.

Hope this is of use,

Andrew

Alfamale
  • 1,069
  • 1
  • 9
  • 13
  • A blog post with a brief introduction to AOP in general: http://andrewlocatelliwoodcock.com/2011/05/02/brief-intro-to-aop/ – Alfamale May 10 '11 at 10:00
2

I think you're looking for the lookup-method injection feature.

You have loaded the Spring.NET application context somewhere at the start. The code-based dependency on Spring.NET there is minimal. The problem is that everywhere you need an (adviced) service, you explicitly depend on Spring.NET with ContextRegistry.GetContext()..

You can work around that with method replacement using lookup-method, example:

Create an AbstractCommandFactory:

namespace MyNamespace {
  public abstract class AbstractCommandFactory : ICommandFactory {
    public abstract ICommand getMyCommand();  
  }
}

Using Spring.NET you can getMyCommand return a Spring.NET object:

<objects>
  <object id="commandfactory"
          type="MyNamespace.AbstractCommandFactory, MyAssembly">
    <lookup-method name="getMyCommand" object="commands.mycommand" />
  </object>

  <object id="commands.mycommand" 
          type=MyNamespace.MyCommandImplementation, MyAssembly" />
</objects>

Now when you initialize the Spring.NET Application Context, load this command factory and pass the reference along. When you need an instance of MyCommandImplementation, you just request one from the factory instance:

public void doSomeWork() {
  // factory is an ICommandFactory
  // instantiated earlier using the explicit context.getObject("commandfactory")
  ICommand myCommand = this.factory.getMyCommand();
  myCommand.Execute();
}

Now your explicit dependency on Spring.NET is very minimal: only at the initial load + instantiation of your factories. The rest of your code stays clean.

Bonus points: you can more easily create ICommandFactory/ICommand mocks to unit-test your code.

toong
  • 1,360
  • 12
  • 18