真实代理(RealProxy)在WCF中的运用

在WCF中,当我们在调用服务端的方法时,一般有两点需要考虑:1、捕获服务端的异常信息,记录日志;2、及时关闭会话信道,当调用超时或调用失败时及时中断会话信道。我们一般会像下面这样处理(以CalculatorService为例):

using (ChannelFactory<ICalculatorService> channelFactory = new ChannelFactory<ICalculatorService>("CalculatorService"))

            {

                ICalculatorService proxy = channelFactory.CreateChannel();

                var commObj = proxy as ICommunicationObject;

                 try

                     {

                    Console.WriteLine("x + y = {2} when x = {0} and y = {1}", 1, 2, proxy.Add(1, 2));

                    commObj.Close();

                     }

                  catch (CommunicationException)

                    {

                        commObj.Abort();

                    }

                    catch (TimeoutException)

                    {

                        commObj.Abort();

                    }

                    catch (Exception)

                    {

                        //TODO:记录异常到日志

                        commObj.Abort();

                        throw;

                    }

            }

 

以上这种处理方式完全可以满足我们的需要,但存在一个问题,每次调用服务端的方法时都需要手工加上这些异常捕获代码,如果服务有很多方法时,这样势必会存在大量功能重复的代码,可复用性很差。我们可以借鉴一下AOP的思想,具体来说就是对服务端方法调用进行拦截。对于.Net应用来说,自定义RealProxy是实现方法调用拦截最简单的一种方式。下面是一个自定义RealProxy的例子:

 

public class CalculatorServiceRealProxy : RealProxy

    {

        public CalculatorServiceRealProxy():base(typeof(ICalculatorService)){}

        public override IMessage Invoke(IMessage msg)

        {

            IMethodReturnMessage methodReturn = null;

            IMethodCallMessage methodCall = (IMethodCallMessage)msg;

            var client = new ChannelFactory<ICalculatorService>("CalculatorService");

            var channel = client.CreateChannel();

            try

            {

               object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[];

                methodCall.Args.CopyTo(copiedArgs, 0);

                object returnValue = methodCall.MethodBase.Invoke(channel, copiedArgs);

                methodReturn = new ReturnMessage(returnValue,

                                                copiedArgs,

                                                copiedArgs.Length,

                                                methodCall.LogicalCallContext,

                                                methodCall);

                //TODO:Write log

            }

            catch (Exception ex)

            {

                var exception = ex;

                if (ex.InnerException != null)

                    exception = ex.InnerException;

                methodReturn = new ReturnMessage(exception, methodCall);

            }

            finally

            {

                var commObj = channel as ICommunicationObject;

                if (commObj != null)

                {

                    try

                    {

                        commObj.Close();

                    }

                    catch (CommunicationException)

                    {

                        commObj.Abort();

                    }

                    catch (TimeoutException)

                    {

                        commObj.Abort();

                    }

                    catch (Exception)

                    {

                        commObj.Abort();

                        //TODO:Logging exception

                        throw;

                    }

                }

            }

            return methodReturn;

        }

    }

 

方法调用:

static void Main(string[] args)

        {



        ICalculatorService proxy = (ICalculatorService)new CalculatorServiceRealProxy().GetTransparentProxy();



            Console.WriteLine("x + y = {2} when x = {0} and y = {1}", 1, 2, proxy.Add(1, 2));

            Console.WriteLine("x - y = {2} when x = {0} and y = {1}", 1, 2, proxy.Subtract(1, 2));

            Console.WriteLine("x * y = {2} when x = {0} and y = {1}", 1, 2, proxy.Multiply(1, 2));

            Console.WriteLine("x / y = {2} when x = {0} and y = {1}", 1, 2, proxy.Divide(1, 2));





            Console.ReadKey();

        }

 

通过自定义的RealProxy创建TransparentProxy供客户端代码调用,对于通过TransparentProxy的每一次调用,都会被RealProxy接管,这样我们就可以在RealProxy中加入异常捕获、记录日志等非业务逻辑代码,这些代码在每次调用服务端方法时都会被调用。

 

源代码下载  (工程ConsoleHosting为服务端,工程Client3为客户端)

image

你可能感兴趣的:(proxy)