1

I start learning Spring.NET framework and I am very confusing with behavior of proxy, auto-proxy and exception handling.

for example I defined simple business object and from this object I will throw custom exception.

namespace Aspect.Managers
{
    public interface IDbCustomerManager
    {
        Customer GetCustomerById(long id);
    }

    public class DbCustomerManager:IDbCustomerManager
    {

        public Customer GetCustomerById(long id)
        {
            throw new DbException(string.Format("Problem load customer with Id: {0}",id));
        }

    }
}

Second I defined Advice for handling with exception.

public class LogExThrowsAdvice:IThrowsAdvice
{
    public void AfterThrowing(MethodInfo method, Object[] args,
            Object target, DbException exception)
    {
        Console.WriteLine(exception.Message);

    }
}

And last I join togheter business object and advice with proxy.

In app.confing

Advice:

  <object id="theLogExThrowsAdvice"
          type="Aspect.LogExThrowsAdvice, Log4NetInSpringNet"/>

Auto-Proxy

  <object id="theProxyCreator"
          type="Spring.Aop.Framework.AutoProxy.TypeNameAutoProxyCreator, Spring.Aop">
    <property name="TypeNames" value="Aspect.Managers.DbCustomerManager*"/>
    <property name="InterceptorNames">
      <list>
        <value>theLogExThrowsAdvice</value>
      </list>
    </property>
  </object>

And test it:

            var springContext = ContextRegistry.GetContext();
            var dbMgr = (IDbCustomerManager)springContext["theDbCustomerManager"];
            dbMgr.GetCustomerById(1);

Exception is throwed, method AfterThrowing from LogExThrowsAdvice is not calling.

I try changed type of advice for type BeforeAdvice.

 public class DbAccessAdvice:IMethodBeforeAdvice
{
    #region Implementation of IMethodBeforeAdvice

    public void Before(MethodInfo method, object[] args, object target)
    {
        Console.WriteLine("You try access to DB");
    }

    #endregion
}

and in app.config:

  <object id="theDbAccessAdvice"
          type="Aspect.DbAccessAdvice, Log4NetInSpringNet"/>


  <object id="theProxyCreator"
          type="Spring.Aop.Framework.AutoProxy.TypeNameAutoProxyCreator, Spring.Aop">
    <property name="TypeNames" value="Aspect.Managers.DbCustomerManager*"/>
    <property name="InterceptorNames">
      <list>
        <value>theDbAccessAdvice</value>
        <value>theLogExThrowsAdvice</value>
      </list>
    </property>
  </object>

BeforeAdvice is fire but ThrowsAdvice no. Why?

I tried change auto proxy for proxy object factory and tried proxying interfaces IDbCustomerManager.

  <object id="theProxy"
          type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
    <property name="ProxyInterfaces" value="Aspect.Managers.IDbCustomerManager"/>
    <property name="Target">
      <object type="Aspect.Managers.DbCustomerManager">
      </object>
    </property>
    <property name="InterceptorNames">
      <list>
        <value>theDbAccessAdvice</value>
        <value>theLogAdvice</value>
      </list>
    </property>
  </object>
  var springContext = ContextRegistry.GetContext();
  var dbMgr = (IDbCustomerManager)springContext["theProxy"];
  dbMgr.GetCustomerById(1);

Before advice is fired but throws advice are not? why? Only exception is throwed.

For me is magic how it really work.

I tried used Advisors instead advices:

  <!--Advisor-->
  <object id="theDbAccessAdvisor"
          type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
    <property name="Pattern" value="Aspect*"/>
    <property name="Advice"  ref="theDbAccessAdvice"/>
  </object>

  <object id="theLogAdvisor"
    type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
    <property name="Pattern" value="Aspect*"/>
    <property name="Advice"  ref="theLogAdvice"/>
  </object>

But same result before advice is fired but throws advice not.

I tried use also ExceptionHandleAdvice aspect from Spring.NET same exception is throwed but advice not.

 <object id="exAdvice"
          type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop">
    <property name="ExceptionHandlers">
      <list>
        <value>on exception name DbException swallow</value>
      </list>
    </property>
  </object>

This project is for me magic I upload all VS project here:

http://hotfile.com/dl/135485464/93558e0/Log4Net.7z.html

Here is stackTrace of exception:

at Aspect.Managers.DbCustomerManager.GetCustomerById(Int64 id) in E:\C# PROJECTS\STUDY\SPRING.NET\Study.Spring.Net\Aspects\Logging\Log4Net\Managers\DbCustomerManager.cs:line 20 at _dynamic_Aspect.Managers.DbCustomerManager.GetCustomerById(Object , Object[] ) at Spring.Reflection.Dynamic.SafeMethod.Invoke(Object target, Object[] arguments) at Spring.Aop.Framework.DynamicMethodInvocation.InvokeJoinpoint() at Spring.Aop.Framework.AbstractMethodInvocation.Proceed() at Spring.Aspects.Exceptions.ExceptionHandlerAdvice.Invoke(IMethodInvocation invocation)

Also if I try catch exception something like this:

        try
        {
            var springContext = ContextRegistry.GetContext();
            var dbMgr = (IDbCustomerManager)springContext["theDbCustomerManager"];
            dbMgr.GetCustomerById(1);
        }
        catch (Exception ex)
        {

            Console.WriteLine("{0}\n{1}", ex.GetType(), ex.Message);
        }

It is not possible..system show message is unhandled exception....

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215

2 Answers2

1

I tested your package. Everything works fine (I'm using v1.3.2). The exception is caught by the AfterThrows advice (use a breakpoint) but not ignored. Here is my config:

public void AfterThrowing(MethodInfo method, Object[] args,
    Object target, DbException exception)
{
    Console.WriteLine(exception.Message);

}
<!--DAO-->
<object id="theCustomerDao"
        type="Aspect.Dao.CustomerDao"/>

<!--Business object-->
<object id="theDbCustomerManager"
        type="Aspect.Managers.DbCustomerManager">
  <!--<property name="CustomerDao" ref="theCustomerDao"/>-->
</object>


<!--Advices-->     
<object id="theLogAdvice"
        type="Aspect.LogExThrowsAdvice, Log4NetInSpringNet"/>

<!--Proxy creator-->
<object type="Spring.Aop.Framework.AutoProxy.TypeNameAutoProxyCreator, Spring.Aop">
  <property name="TypeNames" value="Aspect.Managers.DbCustomerManager*"/>
  <property name="InterceptorNames">
    <list>
      <value>theLogAdvice</value>
    </list>
  </property>
</object>
Marijn
  • 10,367
  • 5
  • 59
  • 80
bbaia
  • 1,193
  • 7
  • 8
  • @Marjin. If I run app in VS exception is not ignored (swallow) but if I run external exe file, exception is ignored (swallow). The second behavior is correct. What cause this behavior ? –  Nov 20 '11 at 10:35
1

If you take your code and combine it with bbaia's config, then you're halfway there I think.

From your question and comments, I understand that you want to swallow the DbExceptions. Note that generally speaking, you'd never want your logger swallow exceptions, but for the question's sake assume you do - but promise me you'll never do this in a production environment :-)

I suggest you slightly adjust your LogExThrowsAdvice to:

public class LogExThrowsAdvice : Spring.Aspects.Exceptions.ExceptionHandlerAdvice, IThrowsAdvice
{
    public void AfterThrowing(MethodInfo method, Object[] args,
        Object target, Exception exception)
    {
        Console.WriteLine(exception.Message);

    }
}

Inheriting from ExceptionHandlerAdvice allows you to specify how to handle thrown exceptions, for instance swallow it. Then take bbaia's config and add an event handler to it:

<object id="theLogAdvice"
        type="Aspect.LogExThrowsAdvice, Log4NetInSpringNet">
  <property name="exceptionHandlers">
    <list>
      <value>on exception name DbException swallow</value>
    </list>
  </property>
</object>

Now all DbExceptions are swallowed.

With respect to your question as to how this still throws in Visual Studio: could it be that your VS is set to "break on a thrown exception"? Go to Debug -> Exceptions and _un_check the Thrown checkbox for Common Language Runtime Exceptions.

Note that if you keep this checked, you can still continue when the exception is raised: the program will not crash, because the exception is handled.

Marijn
  • 10,367
  • 5
  • 59
  • 80
  • ref: https://github.com/serra/stackoverflow/tree/master/spring-questions/q8196368 – Marijn Nov 20 '11 at 13:20
  • @Marjin: thank you again ... problem was that I test application in VS. My aim was if exception is throwed log to file with log4net. It didn’t work because exception was catch by VS. If I ran directly *.exe assembly exception was logged to file. I was very confusing with this behavior. I tried found problem in code but problem didn’t exist. :) Thank for your time and patience. Your answer are really helpfull. –  Nov 20 '11 at 14:14
  • Hey, no need to thank! Keep posting good questions - if you keep up the effort you put into your questions, you'll continue to get good responses. Be it from me or others. – Marijn Nov 20 '11 at 20:36
  • Other good way to learn the framework: browse [questions on spring.net](http://stackoverflow.com/questions/tagged/spring.net) and [upvote](http://stackoverflow.com/privileges/vote-up) good questions and answers. The [spring.net forum](http://forum.springframework.net/) is a good resource and [the docs are excellent](http://www.springframework.net/doc-latest/reference/html/index.html). And then of course there is [the source code](https://github.com/SpringSource/spring-net) to learn from :-). Keep em coming! Ah, [I see you have](http://stackoverflow.com/questions/8202252/). – Marijn Nov 20 '11 at 20:43
  • And I learn *a lot* [from answering questions](http://stackoverflow.com/privileges/create-posts); you might too. – Marijn Nov 20 '11 at 20:47