Click here to Skip to main content
Click here to Skip to main content
Go to top

AOP using Unity 2.0

, 23 Jun 2010
Rate this:
Please Sign up or sign in to vote.
Demonstrates AOP for Exception Handling using Unity2.0 in ASP.NET application

Introduction

This article demonstrates how to implement AOP using Unity 2.0.

Background

AOP takes care of removing cross cutting concerns like Exception Handling / Logging / Validations, etc., and extracting it in a configuration file or a central place so that developers can focus on implementing Business logic.

Problem Description

Consider the below code from a Business Logic component:

public class UserBO : IUserBO
{
     	public Boolean SaveUser(UserDTO userDTO)
       	{
          	try
            	{
                	return _userDAL.SaveUser(userDTO);
            	}
            	catch (UpdateException uex)
            	{
			logger.Log(uex);	
                	throw new MyCustomSqlException("DB Exception occurred", uex);
            	}
            	catch (Exception ex)
            	{
                	    logger.Log(ex);
                	    throw new MyCustomBaseException(ex.Message, ex);
            	}
         }
}

Here, the majority of code is doing Exception handling. The above function demonstrates handling an Entity framework UpdateException (like duplicate user already in database) and rethrowing a custom exception with a message (after logging it to a file). In case of any other exception, it rethrows any other type of exception (after logging it to a file). You often write such wrapping exception codes in Webservices to convert a exception to SoapException and rethrowing it. How about stripping the above code to the one shown below and defining an Exception policy in a configuration file to achieve Exception handling and logging.

public class UserBO : IUserBO
{
       	public Boolean SaveUser(UserDTO userDTO)
        	{
           	return _userDAL.SaveUser(userDTO);
        	}
}

Here all we are doing is writing the business logic. Below is a sample policy:

  • No exception handling at DAL layer. So, any exception thrown is propagated to Domain object layer.
  • For Domain object, if DB Exception is thrown, log the exception with stack trace, throw a custom exception MyCustomSqlException, wrapping the actual exception in it. If not a DB Exception, then log the exception with stack trace, throw a custom exception MyCustomBaseException, wrapping the actual exception in it.

With this policy in place, we do not write any try/catch in BO and DAL layers. At UI layer, we use try/catch to identify the type of exception to show user friendly message to the users.

Sample Exception Policy

We are using Unity 2.0 from Enterprise library 5.0. We can use EntLib configuration tool to create a policy. The below image shows the EntLib configuration setting to implement policy described above:

<configSections>
    <section name="policyInjection" type="Microsoft.Practices.EnterpriseLibrary.
	PolicyInjection.Configuration.PolicyInjectionSettings, Microsoft.
	Practices.EnterpriseLibrary.PolicyInjection, Version=5.0.414.0, 
	Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.
	Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.
	Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
	requirePermission="true" />
    <section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.
	ExceptionHandling.Configuration.ExceptionHandlingSettings, 
	Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, 
	Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
	requirePermission="true" />
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.
	UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
  </configSections>

<policyInjection>
    <policies>
      <add name="MyPolicy">
        <matchingRules>
          <add type="Microsoft.Practices.EnterpriseLibrary.
		PolicyInjection.MatchingRules.TypeMatchingRule, 
		Microsoft.Practices.EnterpriseLibrary.PolicyInjection, 
		Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            name="Type Matching Rule">
            <matches>
              <add match="MyNamespace.IUserBO" />
            </matches>
          </add>
        </matchingRules>
        <handlers>
          <add type="Microsoft.Practices.EnterpriseLibrary.
		ExceptionHandling.PolicyInjection.ExceptionCallHandler, 
		Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, 
		Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            exceptionPolicyName="ExceptionPolicy" order="1" 
		name="Exception Handling Call Handler" />
        </handlers>
      </add>
    </policies>
</policyInjection>
<loggingConfiguration><!-- Removed for code brevity. You can use your listeners here. 
   The EntLib configuration tool will insert the entries here --></loggingConfiguration>
<exceptionHandling>
    <exceptionPolicies>
      <add name="ExceptionPolicy">
        <exceptionTypes>
          <add name="UpdateException" type="System.Data.UpdateException, 
		System.Data.Entity, Version=3.5.0.0, Culture=neutral, 
		PublicKeyToken=b77a5c561934e089"
            postHandlingAction="ThrowNewException">
            <exceptionHandlers>
              <add name="Wrap Handler" type="Microsoft.Practices.EnterpriseLibrary.
		ExceptionHandling.WrapHandler, Microsoft.Practices.EnterpriseLibrary.
		ExceptionHandling, Version=5.0.414.0, Culture=neutral, 
		PublicKeyToken=31bf3856ad364e35"
                exceptionMessage="Exception while updating entity" 
		wrapExceptionType="MyNamespace.MyCustomSQLException, 
		Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
              <add name="Wrap Handler Logging Exception Handler" 
                type="Microsoft.Practices.EnterpriseLibrary.
		ExceptionHandling.Logging.LoggingExceptionHandler, 
		Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, 
		Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                logCategory="General" eventId="100" severity="Error" 
			title="SQL Exception Handling"
                formatterType="Microsoft.Practices.EnterpriseLibrary.
		ExceptionHandling.TextExceptionFormatter, 
		Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
                priority="0" />
            </exceptionHandlers>
          </add>
          <add name="Exception" type="System.Exception, mscorlib, 
		Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
            postHandlingAction="NotifyRethrow">
            <exceptionHandlers>
              <add name="Logging Exception Handler" 
                type="Microsoft.Practices.EnterpriseLibrary.
		ExceptionHandling.Logging.LoggingExceptionHandler, 
		Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, 
		Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                logCategory="General" eventId="100" severity="Error" 
			title="RepSetup Exception Handling"
                formatterType="Microsoft.Practices.EnterpriseLibrary.
			ExceptionHandling.TextExceptionFormatter, 
			Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
                priority="0" />
            </exceptionHandlers>
          </add>
        </exceptionTypes>
      </add>
    </exceptionPolicies>
  </exceptionHandling>

The above configuration is quite understandable. We have actually configured our policy and attached handlers available in Enterprise Library for Logging and Exception Handling.

Here below is the code to implement the Policy defined in configuration file. This can be done from configuration also, but here I am showing it in code (ASP.NET in this case).

protected void Application_Start(object sender, EventArgs e)
{
    // create and populate a new Unity container from configuration
    IUnityContainer unityContainer = new UnityContainer();
    //Whatever is written below in this function can also be configured
    //via unity configuration using unityContainer.LoadConfiguration();	
	    	
    //Add Interception extension to intercept calls
    unityContainer.AddNewExtension<interception>();
    unityContainer.AddNewExtension<enterpriselibrarycoreextension>();
    unityContainer.Resolve<exceptionpolicyimpl>("ExceptionPolicy");
    //Get Policy Injection Settings from the Configuration
    IConfigurationSource configSource = ConfigurationSourceFactory.Create();
    PolicyInjectionSettings policyInjectionsettings = 
	(PolicyInjectionSettings)configSource.GetSection
			(PolicyInjectionSettings.SectionName);

    unityContainer.RegisterType<iuserbo,>();
    unityContainer.Configure<interception>().SetInterceptorFor<iuserbo>
		(new TransparentProxyInterceptor());
            
    if (policyInjectionsettings != null)
    {
        policyInjectionsettings.ConfigureContainer(unityContainer, configSource);
    }

   Application["UnityContainer"] = unityContainer;
}

Here we have configured Unity and registered IUserBO objects to be intercepted and perform the work configured in the policy.

Conclusion

Defining policy in config allows cleaner code and enables changing the policy via configuration. Moving cross cutting concerns from application enables developers to focus on actual business logic.

History

  • 23rd June, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ashish Mundra
Architect
India India
Ashish has 9 years of software development experience on Microsoft Technology. He is a MCSD .Net 1.1 and TS - SQL Server 2005 and TS - WCF
 
He has worked on both windows and web based applications and participated in various phases of Software Development Life Cycle.

Comments and Discussions

 
Questionunity Pinmemberkiquenet AE19-Dec-11 0:42 
GeneralCode corrections PinmemberAloCat8-Oct-10 0:31 
Hi!
 
The code, you provided is not fully functional. The following change has to be made:
 
unityContainer.RegisterType<iuserbo,userbo>();(mapping the actual UserBo class to the intercepted IUserBo interface)
 
Also, if you are using Visual Studio as your development environment, you should change the
 
unityContainer.AddNewExtension<interception>() to unityContainer.AddNewExtension<Interception>() (etc.) for VS to resolve the classnames correctly.
 
One question puzzles me   - is there a way to reuse the interface interception functionality for multiple classes that inherit one interface?
 
e.g Intercept database exceptions from every DAL class that inherits from the IDALClass intercepted interface?

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140922.1 | Last Updated 23 Jun 2010
Article Copyright 2010 by Ashish Mundra
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid