zoukankan      html  css  js  c++  java
  • (转)WCF中的REST是什么

     
    -

    基于SOAP消息格式的WCF之所以强大原因之一是因为SOAP消息头的高度扩展性。相应的WS-*协议很多都体现在消息头封装的信息上,包括诸如寻址,需要调用方法名,维护Session的信息等等……

    SOAP示例

    <s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing"
    xmlns:s
    ="http://www.w3.org/2003/05/soap-envelope">
    <s:Header>
    <a:Action s:mustUnderstand="1" u:Id="_2" xmlns:u="http://docs.oasis-
    open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    >
    http://www.thatindigogirl.com/samples/2006/06/PhotoUploadContract/UploadPhoto
    </a:Action>
    <a:MessageID u:Id="_3" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-
    200401-wss-wssecurity-utility-1.0.xsd"
    >
    urn:uuid:940d5687-fcb2-44b5-a696-cc7eba22524b</a:MessageID>
    <a:ReplyTo u:Id="_4" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-
    200401-wss-wssecurity-utility-1.0.xsd"
    >
    <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
    <a:To s:mustUnderstand="1" u:Id="_5" xmlns:u="http://docs.oasis-
    open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    >
    http://localhost:3045/PhotoApplication/PhotoManagerService.svc/Soap12</a:To>
    <o:Security .../>
    </s:Header>

    <s:Body>........</s:Body>
    </s:Envelope>



    我们要清楚的是,SOAP协议规定的只是一种带有固定格式的XML。规定了由消息头和消息体两部分组成,并且规定了相应的节点。

    WCF中的REST是一种POX(plain old xml),换句话说就是没有任何规定的xml,没有强行规定消息头,没有消息体。甚至因为没有规定,所以传输的格式用不用xml都不是大问题,Json也可以做为传输数据的封装格式。

    没有消息头,所以我们需要另外一种方式定位所需调用的方法,传递我们需要传送的参数信息。而我们能依靠的,就是Http协议给我们提供的信息。

    总的来说,基于SOAP消息的WCF是对于WS-*规范的一种实现。而REST方式的WCF和采用basicHttpBinding差不多,也就是什么都没有,相应的规范则由我们自己定义和实现。

    我们都知道(额,不知道的话以后再说)如果调用基于SOAP消息的WCF服务的客户端也是WCF的话,那么客户端就可以使用透明代理,在通过反射把对方法栈的调用拦截并转换为相应的消息,发送给服务提供者。其中相应的调用方法信息则封装在action属性里。服务端通过消息过滤器查找到相应的信息,并实例化service对象(服务对象也有可能已经实例化好了,具体看你的InstanceContextMode),调用相应的方法。

    图一:Contract的定义

    570)?'570px':'auto'; }" alt="" src="http://www.th7.cn/d/file/p/2012/02/03/3ea89160cbcb87ea82419660cb5b4d27.png" tosee1335751119343="-1">
    图2:根据Contract信息生成的元数据:

    570)?'570px':'auto'; }" alt="" src="http://www.th7.cn/d/file/p/2012/02/03/c68f653f256a03c0660191ad4ef4d4ad.png" tosee1335751119343="-1">

    图3:在客户端调用方法时,发送的SOAP消息:

    570)?'570px':'auto'; }" alt="" src="http://www.th7.cn/d/file/p/2012/02/03/8f5288161ee6a622bed875f6a71c5814.jpg" tosee1335751119343="-1">




    现在问题出来了,如果我们不是通过相应的序列化器,而是选择自己发送没有相应消息头的XML,或者干脆就是在浏览器输入一个地址,当然也就没有action,会出现什么问题?

     我们最直接的反应应该是,服务端找不到相应的信息,报错:

    <Fault><Code><Value>Sender</Value><Subcode><Value>a:ActionNotSupported</Value></Subcode></Code><Reason><Text xml:lang="zh-CN">由于 ContractFilter 在 EndpointDispatcher 不匹配,因此 Action 为“”的消息无法在接收方处理。这可能是由于协定不匹配(发送方和接收方 Action 不匹配)或发送方和接收方绑定/安全不匹配。请检查发送方和接收方是否具有相同的协定和绑定(包括安全要求,如 Message、Transport、None)。</Text></Reason></Fault>


    因此我们的OperationContract特性需要修改一下,处理那些找不到调用信息的请求:

    为了方便说明,因此我新写了一个方法。

            //[OperationContract]
    [OperationContract(Action = "*", ReplyAction = "*")]
    Message Resource(Message input);

    这样我们就可以处理那些不带消息头的信息了。以Message类作为参数是为了方便使用Http中所包含的信息,因为可以方便的转换为HttpRequestMessageProperty 类型。下面这个方法实现的简单功能就是根据参数信息获取相应的文件。比如访问http://localhost:9527/Service?job,获取job.xml的信息:

            public Message Resource(Message input)        {            HttpRequestMessageProperty httpRequestProperty = (HttpRequestMessageProperty)input.Properties[HttpRequestMessageProperty.Name];            string query = httpRequestProperty.QueryString;            string fileName = string.Format("{0}.xml", query);            switch (httpRequestProperty.Method)            {                case "GET":                    Message message = null;                    if (File.Exists(fileName))                    {                        XmlDocument document = new XmlDocument();                        document.Load(fileName);                        message = Message.CreateMessage(                        MessageVersion.None,                        "*",                        new XmlNodeReader(document.DocumentElement));                    }                    else                    {                        message = Message.CreateMessage(                        MessageVersion.None,                        "*");                    }                    return message;                default:                    return Message.CreateMessage(                    MessageVersion.None, "*");            }        }

    相应的配置文件,不用多说了吧,既然采用的是REST,那么编码方式肯定就是文本,传输方式肯定就是Http。注意MessageVersion = None意味着咱们不需要对输入的数据的格式有要求
        <services>
    <service name="Service.SimpleServer">
    <endpoint address="Service" binding="customBinding" bindingConfiguration="RESTPOXBinding"
    contract
    ="IService.ISimpleResource" />
    <host>
    <baseAddresses>
    <add baseAddress="http://localhost:9527/" />
    </baseAddresses>
    </host>
    </service>
    </services>
    <bindings>
    <customBinding>
    <binding name="RESTPOXBinding">
    <textMessageEncoding messageVersion="None"/>
    <httpTransport/>
    </binding>
    </customBinding>
    </bindings>

    当然,这么写是有点小麻烦,WCF的设计者肯定会考虑到这点,帮我们封装好了,于是就成了下面这样:
    [WebGet(UriTemplate = “/{query}”, BodyStyle = WebMessageBodyStyle.Bare)]
    Message Resource(string query);

    这样我们在实现方法的时候就不用再自己手动调用HttpRequestMessageProperty 类提取信息,看起来也简洁了很多。
            public Message Resource(String query)        {            string fileName = string.Format("{0}.xml", query);                    Message message = null;                    if (File.Exists(fileName))                    {                        XmlDocument document = new XmlDocument();                        document.Load(fileName);                        message = Message.CreateMessage(                        MessageVersion.None,                        "*",                        new XmlNodeReader(document.DocumentElement));                    }                    else                    {                        message = Message.CreateMessage(                        MessageVersion.None,                        "*");                    }                    return message;        }

    同样的,系统给了我们一个webHttpBinding套餐,也是对上面传输协议和编码的封装。


    关于OperationContract 和 WebGet 特性的说明
    这两个特性主要是给Operation的描述添加了一些元数据信息,给一个Operation添加了这两个特性以后,该Operation仍然可以通过SOAP消息的方式来访问。


  • 相关阅读:
    小透明学弟的华为上岸之路
    手把手体验远程开发,确实爽
    老弟做了个网盘,炸了!
    聊聊我在腾讯和字节工作感受
    2021,编程语言如何选择?
    优化了破网站的搜索功能
    15 道超经典大厂 Java 面试题!重中之重
    我两年的坚持,值了!
    聊聊百度搜索背后的故事
    struts2的配置步骤
  • 原文地址:https://www.cnblogs.com/syf/p/2476755.html
Copyright © 2011-2022 走看看