65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Unity 2.0 的 AOP

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (9投票s)

2010年6月23日

CPOL

2分钟阅读

viewsIcon

42418

演示了如何在 ASP.NET 应用程序中使用 Unity 2.0 进行异常处理的 AOP

引言

本文演示了如何使用 Unity 2.0 实现 AOP。

背景

AOP 负责处理诸如异常处理/日志记录/验证等横切关注点,并将其提取到配置文件或中心位置,以便开发人员可以专注于实现业务逻辑。

问题描述

考虑来自业务逻辑组件的以下代码

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);
            	}
         }
}

在这里,大部分代码都在进行异常处理。 上述函数演示了如何处理 Entity Framework 的 UpdateException (例如数据库中已经存在重复的用户)并重新抛出带有消息的自定义异常(在将其记录到文件之后)。 如果发生任何其他异常,它会重新抛出任何其他类型的异常(在将其记录到文件之后)。 您通常在 Web 服务中编写此类包装异常代码以将异常转换为 SoapException 并重新抛出它。 如何将上述代码简化为如下所示的代码,并在配置文件中定义异常策略以实现异常处理和日志记录?

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

在这里,我们所做的就是编写业务逻辑。 以下是一个示例策略

  • 在 DAL 层不进行异常处理。 因此,抛出的任何异常都会传播到域对象层。
  • 对于域对象,如果抛出 DB 异常,则使用堆栈跟踪记录异常,抛出自定义异常 MyCustomSqlException,将实际异常包装在其中。 如果不是 DB 异常,则使用堆栈跟踪记录异常,抛出自定义异常 MyCustomBaseException,将实际异常包装在其中。

有了此策略,我们无需在 BO 和 DAL 层编写任何 try/catch 。 在 UI 层,我们使用 try/catch 来确定异常的类型,以便向用户显示友好的消息。

示例异常策略

我们使用来自 Enterprise library 5.0 的 Unity 2.0。 我们可以使用 EntLib 配置工具来创建策略。 如下图所示,是 EntLib 配置设置,用于实现上述策略

<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>

上述配置很容易理解。 我们实际上已经配置了我们的策略,并附加了 Enterprise Library 中可用于日志记录和异常处理的处理程序。

下面是实现配置文件中定义的策略的代码。 也可以从配置完成,但在这里我将其显示在代码中(在这种情况下是 ASP.NET)。

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;
}

在这里,我们配置了 Unity,并注册了要拦截的 IUserBO 对象,并执行策略中配置的工作。

结论

在配置中定义策略允许更干净的代码,并可以通过配置更改策略。 将横切关注点从应用程序中移除,使开发人员能够专注于实际的业务逻辑。

历史

  • 2010年6月23日:初始帖子
© . All rights reserved.