Aug 112012
 
Share...Tweet about this on Twitter2Share on Facebook4Share on Google+1Share on StumbleUpon0Share on LinkedIn3Flattr the authorPin on Pinterest0Share on Reddit0Share on Tumblr

Spring.NET is a great open-source framework with rich capabilities and a large amount of “plugins” or services that are implemented around the Spring Core. In this post I am going to discuss the same content discussed in one of the earlier posts (applied to PostSharp framework), which is about how to apply Aspect Oriented Programming specifically the method interception but this time in Spring.NET.

I am using the Spring.AOP that can be easily referenced in the project via nuget.

In order to start lets check the Spring.NET AOP naming convention.

AOP terminology in Spring.NET

The text in this section is taken from the http://www.springframework.net/doc-latest/reference/html/aop.html#aop-introduction-advice-types page. All credits to the author of the text.

Let us begin by defining some central AOP concepts. These terms are not Spring.NET-specific. Unfortunately, AOP terminology is not particularly intuitive. However, it would be even more confusing if Spring.NET used its own terminology.

  • Aspect: A modularization of a concern for which the implementation might otherwise cut across multiple objects. Transaction management is a good example of a crosscutting concern in enterprise applications. Aspects are implemented using Spring.NET as Advisors or interceptors.
  • Joinpoint: Point during the execution of a program, such as a method invocation or a particular exception being thrown.
  • Advice: Action taken by the AOP framework at a particular joinpoint. Different types of advice include “around,” “before” and “throws” advice. Advice types are discussed below. Many AOP frameworks, including Spring.NET, model an advice as an interceptor, maintaining a chain of interceptors “around” the joinpoint.
  • Pointcut: A set of joinpoints specifying when an advice should fire. An AOP framework must allow developers to specify pointcuts: for example, using regular expressions.
  • Introduction: Adding methods or fields to an advised class. Spring.NET allows you to introduce new interfaces to any advised object. For example, you could use an introduction to make any object implement an IAuditable interface, to simplify the tracking of changes to an object’s state.
  • Target object: Object containing the joinpoint. Also referred to as advised or proxied object.
  • AOP proxy: Object created by the AOP framework, including advice. In Spring.NET, an AOP proxy is a dynamic proxy that uses IL code generated at runtime.
    Weaving: Assembling aspects to create an advised object. This can be done at compile time (using the Gripper-Loom.NET compiler, for example), or at runtime. Spring.NET performs weaving at runtime.

Different advice types include:

  • Around advice: Advice that surrounds a joinpoint such as a method invocation. This is the most powerful kind of advice. Around advice will perform custom behaviour before and after the method invocation. They are responsible for choosing whether to proceed to the joinpoint or to shortcut executing by returning their own return value or throwing an exception.
  • Before advice: Advice that executes before a joinpoint, but which does not have the ability to prevent execution flow proceeding to the joinpoint (unless it throws an exception).
  • Throws advice: Advice to be executed if a method throws an exception. Spring.NET provides strongly typed throws advice, so you can write code that catches the exception (and subclasses) you’re interested in, without needing to cast from Exception.
  • After returning advice: Advice to be executed after a joinpoint completes normally: for example, if a method returns without throwing an exception.

Basics

Spring.NET uses interception “Inversion Of Control” mechanism in order to enable the AOP, which is a very different approach from the one used in PostSharp where the actual Aspect code is directly compiled into the assembly.

Lets start with the code as it will be more clear how is this implemented in Spring.NET

The following is the starting code, exactly as in the previous mentioned PostSharp example. The only difference is that now the CustomerService implements the ICustomerService interface. This is needed by the Spring.NET as it seems to be a limitation of the Spring.NET framework itself. But, as you may see, this is absolutely not a big deal to implement and to maintain. On the other hand is really reccomended to work agains interfaces rather than with the implementation.

Starting code…

public interface ICustomerService
{
    Customer GetCustomer(string name);

    void AddCustomer(Customer c);
}

public class CustomerService : ICustomerService
{
    private List<Customer> _customerList = new List<Customer>();

    public Customer GetCustomer(string name)
    {
        return _customerList.FirstOrDefault(
			t => t.FirstName.ToLower().Contains(name.ToLower()));
    }

    public void AddCustomer(Customer c)
    {
        _customerList.Add(c);
    }
}
    
public class Customer
{
    public string FirstName { get; set; }

    public string LastName { get; set; }
}

Implementation of the advice

As mentioned before, Spring.NET offers several possibilities in order where to execute the advice before, around, after or throws. In our case we are going to use the “around” advice as shown in the next code snipped.

In order to implement the advice that we have called in the exactly the same way as in the previous post, we need to implement the IMethodInterceptor interface offered by the Spring framework as follows:

[Serializable]
public class LoggingAdvice : IMethodInterceptor
{
	public object Invoke(IMethodInvocation invocation)
	{
		//1. on entry - code executed before the method fires
		Console.Out.WriteLine("OnEntry: {0}.{1}", 
			invocation.Method.DeclaringType.Name, 
			invocation.Method.Name);

		//2. executing the underlying method
		object returnValue = invocation.Proceed();

		//3. on exit - code executed after the method has finished 
		// the execution
		Console.Out.WriteLine("OnExit: {0}.{1}", 
			invocation.Method.DeclaringType.Name, 
			invocation.Method.Name);
		
		//4. Returning the value
		return returnValue;
	}
}

as you may see, there are 4 main points in our aspect code.

1. Code executed BEFORE the actual method
2. Calling the method itself
3. Code executed AFTER the actual method
4. Returning the value to the caller (client).

Wiring it all together

Spring.AOP offers mainly two possibilities of how to call and add the advice to the method, either by using the configuration settings directly in the web.config or app.config files or writing directly the code. Here I will be showing you both the possibilities.

For the full details of how to use Spring.NET (configuration and other settings) is not really a topick for this blog post and I invite you to directly check the Spring.NET documentation.

Using the configuration

class Program
{
	static void Main(string[] args)
	{
	    //registering objects as defined in the app/web.config	
		IApplicationContext ctx = ContextRegistry.GetContext();

		//instantiating the concrete object
		var command = (ICustomerService)ctx["customerServiceObject"];
		
		//calling the AddCustomer method.
		command.AddCustomer(new Customer
								{
									FirstName = "Zoran",
									LastName = "Maksimovic"
								});

		var customer = command.GetCustomer("zoran");
		
		Console.WriteLine("{0} {1}", customer.FirstName, 
		                             customer.LastName);
		Console.ReadLine();
	}
}

Following is the content of the app.config. Please pay attention on the fact that Spring.First is simple the namespace I have given to my solution. You would need to replace it with your namespace.

<configuration>
  <configSections>
    <sectionGroup name="spring">
      <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
      <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
    </sectionGroup>
  </configSections>

  <spring>
    <context>
      <resource uri="config://spring/objects"/>
    </context>

    <objects xmlns="http://www.springframework.net">
      <object id="loggingAdvice" type="Spring.First.LoggingAdvice"/>
      <object id="customerServiceObject" type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="target">
          <object id="customerService" type="Spring.First.CustomerService"/>
        </property>
        <property name="interceptorNames">
          <list>
            <value>loggingAdvice</value>
          </list>
        </property>
      </object>
    </objects>
  </spring>
</configuration>

For brevity I haven’t included the assembly name, but when specifying the type, as everywhere in the app.config you may specify the full namespace and the assembly
something like

<object id="loggingAdvice" type="Spring.First.LoggingAdvice,Spring.First"/>

Using the code programmatically

As you may see, a part omitting completely the app/web.config part the only difference is that we need to instantiate manually the ProxyFactory object and from there create the ICustomerService.

class Program
{
	static void Main(string[] args)
	{
	    //creating the proxy
		var factory = new ProxyFactory(new CustomerService());
		//adding the logging advice programmatically
		factory.AddAdvice(new LoggingAdvice());

		//getting the concrete service object
		var command = (ICustomerService)factory.GetProxy();
		
		//calling the AddCustomer method.
		command.AddCustomer(new Customer
								{
									FirstName = "Zoran",
									LastName = "Maksimovic"
								});

		var customer = command.GetCustomer("zoran");
		Console.WriteLine("{0} {1}", customer.FirstName, 
		                             customer.LastName);
		Console.ReadLine();
	}
}

the output in both cases is

OnEntry: CustomerService.AddCustomer
OnExit: CustomerService.AddCustomer
OnEntry: CustomerService.GetCustomer
OnExit: CustomerService.GetCustomer
Zoran Maksimovic

Conclusion

With Spring.AOP module is really easy to create aspects and it offers a great deal of possibility when it comes to the configuration and features. I have mentioned several times in the article the PostSharp tool as I wanted to emphasize the differencies between the two frameworks, even though I haven’t really done a feature to feature comparison, that could be a great topic for one of the future blog posts.
I hope you will enjoy working with Spring.NET as I did. Web is really full of information about the framework and it worth mentioning that is completely free to use.

References

http://www.springsource.org/

Share...Tweet about this on Twitter2Share on Facebook4Share on Google+1Share on StumbleUpon0Share on LinkedIn3Flattr the authorPin on Pinterest0Share on Reddit0Share on Tumblr

My name is Zoran Maksimovic a Software Developer and Solution Architect. I'm interested in Software Development, Object-Oriented Design and Software Architecture all this especially bound to the Microsoft.NET platform. Feel free to contact me or know more in the about section

Leave a Reply

womble-valentin@mailxu.com champine_pamula@mailxu.com