How to write to log before and after calling a method (using RealProxy)

30 בנובמבר 2008

תגיות:
3 תגובות


רונן עקרי הראה לי את ה RealProxy class


 יש לו הרבה שימושים, כאן אני אדגים איך על ידי שימוש ב RealProxy, אפשר לרשום ללוג, לפני ואחרי הפעלת מתודות.


נניח שיש לנו class dal שמממש interface שנקרא IDal והם נראים כך:




    8 public interface IDal


    9 {


   10     void SelectAll();


   11     void Insert();


   12     void Update();


   13 }


   14 


   15 public class Dal : IDal


   16 {


   17     #region Singleton


   18     private static IDal m_Instance;


   19 


   20     public static IDal Instance


   21     {


   22         get


   23         {


   24             if (m_Instance == null)


   25             {


   26                 m_Instance = new Dal();


   27             }


   28 


   29             return m_Instance;


   30         }


   31     }


   32 


   33     private Dal()


   34     {


   35 


   36     }


   37     #endregion Singleton


   38 


   39     #region IDal Members


   40 


   41     public void SelectAll()


   42     {


   43         Console.WriteLine("SelectAll…");


   44     }


   45 


   46     public void Insert()


   47     {


   48         Console.WriteLine("Insert…");


   49     }


   50 


   51     public void Update()


   52     {


   53         Console.WriteLine("Update…");


   54     }


   55 


   56     #endregion IDal Members


   57 }


 




 והשימוש בהם נראה כך:




 



    8 class Program


    9 {


   10     static void Main(string[] args)


   11     {


   12         Dal.Instance.SelectAll();


   13     }


   14 }



 הפלט יהיה כמובן


cmd1


 


עכשיו אנחנו רוצים לעשות שינוי קטן בקוד, שאוטומטית כל הפעלה של פונקציה של ה Dal תרשם ללוג, לפני ההפעלה ואחרי ההפעלה.


 החלק העיקרי שאנחנו צריכים לעשות זה לרשת מ RealProxy, הקוד מורכב יחסית, אבל אחרי שנעשה את זה פעם אחת, הקוד שלנו לא יצטרך כמעט לעבור שינויים.


(בדוגמא, כתבתי ConsoleProxy שכותב כל פעם ל Console, בקוד האמיתי שלנו, מן הסתם נגדיר DynamicProxy, ובכל פעם נרש ממנו כדי שלא נצטרך בכל פעם לרשת ישירות מ RealProxy)


 





 


   12 public class ConsoleProxy<TTarget> : RealProxy where TTarget : class


   13 {


   14     private TTarget m_Target;


   15 


   16     public TTarget TransparentProxy


   17     {


   18         get


   19         {


   20             return base.GetTransparentProxy() as TTarget;


   21         }


   22     }


   23 


   24     public ConsoleProxy(TTarget target)


   25         : base(typeof(TTarget))


   26     {


   27         m_Target = target;


   28     }


   29 


   30     protected void BeforeMethodCall(TTarget target, MethodBase method, object[] args, out object state)


   31     {


   32         state = null;


   33         Console.WriteLine("Before invoking " + method.Name);


   34     }


   35 


   36     protected void AfterMethodCall(TTarget target, MethodBase method, object[] args, object state)


   37     {


   38         Console.WriteLine("After invoking " + method.Name);


   39     }


   40 


   41     protected object OnInvokeMethod(object target, MethodBase method, object[] parameters)


   42     {


   43         return method.Invoke(target, parameters);


   44     }


   45 


   46     protected Exception OnException(TTarget target, MethodBase method, object[] args, Exception exception)


   47     {


   48         return exception;


   49     }


   50 


   51     public override IMessage Invoke(IMessage msg)


   52     {


   53         // Convert to a MethodCallMessage


   54         IMethodCallMessage methodMessage = new MethodCallMessageWrapper((IMethodCallMessage)msg);


   55 


   56         // Extract the method being called


   57         MethodBase method = methodMessage.MethodBase;


   58 


   59         // Perform the call


   60         object returnValue = null;


   61         object state = null;


   62 


   63         BeforeMethodCall(m_Target, method, methodMessage.Args, out state);


   64 


   65         ReturnMessage returnMessage = null;


   66 


   67         try


   68         {


   69             returnValue = OnInvokeMethod(m_Target, method, methodMessage.Args);


   70             returnMessage =


   71                 new ReturnMessage(returnValue, methodMessage.Args, methodMessage.ArgCount,


   72                                     methodMessage.LogicalCallContext, methodMessage);


   73 


   74         }


   75         catch (Exception ex)


   76         {


   77             if ((ex is RemotingException || ex is TargetInvocationException)


   78                 && ex.InnerException != null)


   79                 ex = ex.InnerException;


   80 


   81             ex = OnException(m_Target, method, methodMessage.Args, ex);


   82             returnMessage = new ReturnMessage(ex, methodMessage);


   83         }


   84         finally


   85         {


   86             AfterMethodCall(m_Target, method, methodMessage.Args, state);


   87         }


   88 


   89         return returnMessage;


   90     }


   91 }


 

 

ה- class שלנו הוא generic שמקבל כל מה שהוא ref type.

בשורה 14-22 יש לנו את ה member וה property שמחזירים את ה type האמיתי של ה proxy שלנו

בשורות 30-51 אנחנו מגדירים ארבע מתודות, לפני הפעלת הפונקציה, במהלך הפעלת הפונקציה, אחרי הפונקציה, ואם התרחש שגיאה.

החל משורה 51, אנחנו מגדירים את המתודה Invoke, שהיא מפעילה את כל הפונקציות. (לא נכנס כרגע למימוש הספציפי של ה Invoke)

בשורה 63, אנחנו מפעילים את המתודה BeforeMethodCall לאחריו בשורה 69 אנחנו מפעילים את המתודה עצמה, ובשורה 86 אנחנו מפעילים את המתודה AfterMethodCall

 

 

עכשיו, נצטרך לבצע שינוי קטן ב Dal, במקום להחזיר ישירות את ה Dal נחזיר Proxy של ה Dal

 

הקוד הישן בהערה:

 

 

 



   




   62 private static ConsoleProxy<IDal> m_Instance;


   63 // private static IDal m_Instance;


   64 


   65 public static IDal Instance


   66 {


   67     get


   68     {


   69         if (m_Instance == null)


   70         {


   71             m_Instance = new ConsoleProxy<IDal>(new Dal());


   72             // m_Instance = new Dal();


   73         }


   74 


   75         return m_Instance.TransparentProxy;


   76     }


   77 }



 

שימו לב לשינוי הקטן שעשינו ב property שמחזיר את ה dal,

ועכשיו, הרצה של הקוד הבא:



    8 class Program


    9 {


   10     static void Main(string[] args)


   11     {


   12         Dal.Instance.SelectAll();


   13     }


   14 }


יוציא את הפלט:

cmd2

 

הוסף תגובה
facebook linkedin twitter email

להגיב על Sasha Goldshtein לבטל

האימייל לא יוצג באתר. שדות החובה מסומנים *

3 תגובות

  1. Rotem Bloom1 בדצמבר 2008 ב 1:43

    מאוד נחמד חייב לציין 🙂

    הגב
  2. Ariel Ben Horesh1 בדצמבר 2008 ב 3:20

    I believe that performance wise, you can have a major hit. Remember that Reflection is always a hit and in this case it is on every method call. More important is that you cancel the compiler ability to inline your methods.

    הגב
  3. Sasha Goldshtein8 במאי 2009 ב 18:31

    Ariel, as much as I am for performance, your argument is slightly irrelevant.

    When you add interception to a system, you do it between significant layers, in this case — between the DAL and the rest of the system. The time to actually perform the logging (to the console or to a file) is significantly longer than the time it takes to intercept the call through the proxy. Obviously you wouldn't add interception to a critical operation such as multiplying two matrices when doing intensive image processing.

    Therefore, it's actually a perfectly feasible approach, albeit slightly cumbersome IMO.

    Sasha

    הגב