zoukankan      html  css  js  c++  java
  • WCF服务端基于配置的实现——路由

    上篇回顾

        上一篇,简单的讲了一下WCF里面如何拦截一个操作,不过,只说了一半,因为程序拦截住WCF的一个操作请求之后,并不知道应该去干什么,因此,这个拦截没有发挥它该有的功能。那么怎么才能让我们的拦截发挥作用,并且有能够实现主题——基于配置的实现哪?

        思考这个问题的时候,是否想到了在Web上大显身手的MVC模式哪?想一下MVC是如何判断应该调用那个Controller的,当然当然是RouteTable。

        那么我们为什么不也作一个路由表哪?

    打造路由表——寻找Url的等价物

        开始打造我们自己的路由表之前,需要想明白一件事情,WCF里面的路由的URL怎么取,事实上,WCF的每个操作都有自己的Action,因此,完全可以用Action来作为WCF中Url的等价物。

        那么,怎么在WCF中抓取出当前操作的Action哪?

        其实,相当的简单,只需要这样一句就可以了:

    string action = OperationContext.Current.IncomingMessageHeaders.Action;

        有了Action,这个Url的等价物之后,我们需要做的就是决定如何定义一个路由表,这个字符串简单,变成一个可以执行的操作。

    打造路由表——思考路由策略

        因为是自己打造路由,所以,很多时候可以跳出现有的MVC之类的框架的思维定式,寻找一个真正想要的策略(即使不是什么最佳策略,也无关紧要)。

        对于任何一个WCF的操作来说,总是可以想象到下面这几步的:

    • 日志
    • 验证参数
    • 错误处理
    • 各种未知的操作

        其中,各种未知操作可能也会出现管道/过滤器式(pipe/filter)的处理,前一步做完再做下一步。因此,我们的路由表最好能支持链式处理。

        说到这里,是不是想到了什么?

        至少我在第一时间想到的是:设计模式——责任链模式。

    打造路由表——基于责任链的路由表

        既然确定了要基于责任链,那么首先来准备责任链的基础类型:

    public interface IOperationHandler
    {
       IOperationHandler Next { get; set; }
       object Request { get; set; }
       object Response { get; set; }
       void Handle();
    }

        此时,是不是发现上一篇中之前要限定操作只有一个参数和一个返回值了,以及只支持同步方法,为这里的接口带来了巨大的简化。

    打造路由表——路由到原始处理

        在打造别的Handler之前,先写一个原始的WCF的处理

        internal sealed class RawHandler
            : IOperationHandler
        {
    
            public object Instance { get; private set; }
            public object Request { get; set; }
            public object Response { get; set; }
            private readonly IOperationInvoker m_raw;
    
            public RawHandler(object instance, IOperationInvoker raw)
            {
                Instance = instance;
                m_raw = raw;
            }
    
            public override void Handle()
            {
                object[] outputs;
                Response = m_raw.Invoke(Instance, new object[] { Request }, out outputs);
            }
    
        }

        有了这个RawHandler,就可以打造出:

        public abstract class HandlerFactory
        {
    
            private static HandlerFactory m_default = new DefaultHandlerFactory();
            public static HandlerFactory Default { get { return m_default; } }
            private static HandlerFactory m_current = m_default;
            public static HandlerFactory Current
            {
                get { return m_current; }
                set { m_current = value; }
            }
    
            public abstract IOperationHandler CreateHandlerChains(RawHandler raw);
    
        }
    
        internal sealed class DefaultHandlerFactory
            : HandlerFactory
        {
    
            public override IOperationHandler CreateHandlerChains(RawHandler raw)
            {
                IOperationHandler handler = raw;
                // todo : create handler chains ...
                return handler;
            }
    
        }

        然后,在把这个HandlerFactory放到上一篇的ControllerInvoker类里面:

            public object Invoke(object instance, object[] inputs, out object[] outputs)
            {
                var raw = new RawHandler(instance, Inner);
                var c = HandlerFactory.Current.CreateHandlerChains(raw);
                c.Request = inputs[0];
                c.Handle();
                outputs = new object[0];
                return c.Response;
            }

        到目前为止,WCF服务就有可以正常的跑起来了,当然目前没有更改任何WCF的行为,而仅仅是绕了一圈,把服务里面加了个拦截和路由,并且路由总是直接调用服务原来的代码实现。

        感到很沮丧?别急,虽然到这里写了一大堆类,并且没有更改任何的WCF的默认行为,但是,已经成功的加入了一个可以更改WCF行为的注入点:CreateHandlerChains方法

        通过这个方法,我们可以随时添加Handler,来修改WCF的行为。

    打造路由表——硬编码的路由表

        在思考如何动态配置之前,不妨先从硬编码开始。所以写一个简单的HardCodeHandlerFactory:

        public class HardCodeHandlerFactory
            : HandlerFactory
        {
    
            private readonly List<HandlerInfo> Creators = new List<HandlerInfo>();
    
            private sealed class HandlerInfo
            {
                public string ActionPattern;
                public Func<IOperationHandler, IOperationHandler> Creator;
    
                public bool IsMatch(string action)
                {
                    return Regex.IsMatch(action, ActionPattern);
                }
            }
    
            public void Add(Func<IOperationHandler, IOperationHandler> creator, string actionPattern)
            {
                Creators.Add(new HandlerInfo
                {
                    ActionPattern = actionPattern,
                    Creator = creator,
                });
            }
    
            public override IOperationHandler CreateHandlerChains(RawHandler raw)
            {
                IOperationHandler handler = raw;
                string action = OperationContext.Current.IncomingMessageHeaders.Action;
                foreach (var item in Creators)
                {
                    if (item.IsMatch(action))
                    {
                        handler = item.Creator(handler);
                    }
                }
                return handler;
            }
    
        }

        通过这个简单的Factory,可以很简单的通过添加Handler,作用于那些Action符合Pattern的操作。

        为了方便演示,先定义一个简单的Handler:

            public abstract class OperationHandlerBase
                : IOperationHandler
            {
    
                private object m_request;
                private object m_response;
                public IOperationHandler Next { get; set; }
    
                public abstract void Handle();
    
                public object Request
                {
                    get
                    {
                        if (Next == null)
                            return m_request;
                        else
                            return Next.Request;
                    }
                    set
                    {
                        if (Next == null)
                            m_request = value;
                        else
                            Next.Request = value;
                    }
                }
    
                public object Response
                {
                    get
                    {
                        if (Next == null)
                            return m_response;
                        else
                            return Next.Response;
                    }
                    set
                    {
                        if (Next == null)
                            m_response = value;
                        else
                            Next.Response = value;
                    }
                }
    
            }
    
            public class LogHandler
                : OperationHandlerBase
            {
    
                public override void Handle()
                {
                    Trace.TraceInformation("Begin action:{0}", OperationContext.Current.IncomingMessageHeaders.Action);
                    // this handler can handle nothing.
                    //if (false)
                    //    return;
                    //else
                    if (Next != null)
                    {
                        Next.Handle();
                    }
                    else
                    {
                        Trace.TraceInformation("Action {0} not implemented.", OperationContext.Current.IncomingMessageHeaders.Action);
                        throw new FaultException("Not implemented.");
                    }
                    Trace.TraceInformation("End action:{0}", OperationContext.Current.IncomingMessageHeaders.Action);
                }
    
            }

        然后再把这个Handler注册到工厂中,例如:

    HardCodeHandlerFactory f = new HardCodeHandlerFactory();
    f.Add(handler => new LogHandler { Next = handler }, "\\S");
    HandlerFactory.Current = f;
    

        这样,所有有Controller这个特性的WCF操作都会在开始和正常结束的时候输出2行日志(因为正则\S可以匹配和Action,如果需要选择性的注入,可以修改正则)。

        当然,因为LogHandler本身并不能处理掉任何的请求,因此,在责任链中的它必须把请求发送给下一个处理者(如果没有下一个处理者,那就是有问题的责任链,因此直接抛错)。

        但是在某些Handler中(例如负责参数检查的Handler),如果发现参数有问题,将可以直接将请求变成已经处理,从而短路后面的处理。

    打造路由表——思考和下篇预告

        前面一节,已经可以简单实现HardCode的路由功能,然后可以思考一下如何通过配置的形式来更改路由表。

        思考一下路由的要素:

    • 处理器类型是如何发现的(配置文件指定等方式)
    • 处理器的创建(构造函数等约定)
    • 处理器是否需要可配置的生效(也就是HardCode中的正则的作用)
    • 环境变量(也就是前面的处理器可以修改环境值而影响后面的处理器行为)

        下一篇将解决这些问题,实现一个基于配置的WCF。

  • 相关阅读:
    openpyxl模块的读写使用及mongodb概念
    MongoDB数据库的下载安装及配置方法
    利用while循环写的简单小游戏猜数字
    爬虫之爬取豆瓣top250电影排行榜及爬取斗图啦表情包解读及爬虫知识点补充
    红薯网防爬措施与斗图啦及豆瓣实战案例
    (小知识)结局不会的问题的解决流程
    spring2.5.6 jar包
    Struts2的DMI动态方法调用
    Struts2.1.6 jar包
    Hibernate3.3.2 jar包
  • 原文地址:https://www.cnblogs.com/vwxyzh/p/1882663.html
Copyright © 2011-2022 走看看