AOP using Unity 2.0






4.89/5 (9 votes)
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 exceptionMyCustomBaseException
, 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