• XCF之原形


    上篇回顾

        上篇提出了个思考,WCF的契约是否可以也基于配置,而不是必须要生成类型,并且从WCF的原理出发点阐述了其可能性,最后提出了XCF的概念。

        经过2周的努力,终于实现了一个原形,这一篇里面就讲一下怎么做一个XCF的原形。

    实现基础

        首先,WCF客户端本身就支持发送任何消息。听起来很不可思议是吧?这就是大家的思维被WCF框架的思维定势所限制,反而把这些基础或者说原始的用法而忽略了。

        来看看一个关键接口:IRequestChannel

        当然,WCF的关键接口不止这一个,但是对付那些通常的基于tcp/http的WCF服务而言,这个接口就足够了。使用这个接口可以向tcp/http的wcf服务发送任何消息。当然,这里有个问题,任意消息必须要符合服务的协议,否则,服务端将返回错误。

    准备服务端

        为了方便试验,先简单的准备一个服务端契约:

    [ServiceContract(Namespace = "urn:test")]
    public interface IEchoService
    {
        [OperationContract(Action = "Echo")]
        Person Echo(Person p);
    }
    
    [DataContract(Namespace = "urn:test")]
    public class Person
    {
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Age { get; set; }
    }
    

        以及一个简单的实现:

    public class EchoService : IEchoService
    {
        public Person Echo(Person p)
        {
            Console.WriteLine("Name={0},Age={1}", p.Name, p.Age);
            return p;
        }
    }
    

        以及配置(加上wcf的日志):

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <bindings>
          <wsHttpBinding>
            <binding name="WSHttpBinding_IEchoService">
              <security mode="None" />
            </binding>
          </wsHttpBinding>
        </bindings>
        <behaviors>
          <serviceBehaviors>
            <behavior name="WcfHost.EchoServiceBehavior">
              <serviceMetadata httpGetEnabled="true" />
              <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <services>
          <service behaviorConfiguration="WcfHost.EchoServiceBehavior"
              name="WcfHost.EchoService">
            <endpoint address="" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IEchoService" contract="WcfHost.IEchoService">
              <identity>
                <dns value="localhost" />
              </identity>
            </endpoint>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:12345/EchoService/" />
              </baseAddresses>
            </host>
          </service>
        </services>
        <diagnostics>
          <messageLogging
               logEntireMessage="true"
               logMalformedMessages="true"
               logMessagesAtServiceLevel="true"
               logMessagesAtTransportLevel="true"
               maxMessagesToLog="3000"
               maxSizeOfMessageToLog="2000"/>
        </diagnostics>
      </system.serviceModel>
      <system.diagnostics>
        <sources>
          <source name="System.ServiceModel.MessageLogging">
            <listeners>
              <add name="messages"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData="messages.log" />
            </listeners>
          </source>
        </sources>
      </system.diagnostics>
    </configuration>
    

        在这里需要注意的是,要去除安全的部分,因为有安全的wcf会修改消息体,使用编码过的消息体,为原形带来不小的麻烦。

    标准客户端

        作为对比,先准备一个标准的客户端,过程当然是按照标准的添加服务引用。

        然后,准备上一个标准的调用:

    Svc.EchoServiceClient client = new WcfNormalClient.Svc.EchoServiceClient();
    var resp = client.Echo(new WcfNormalClient.Svc.Person
    {
        Name = "abc",
        Age = 12,
    });
    client.Close();
    Console.WriteLine("Name={0},Age={1}", resp.Name, resp.Age);
    

        准备好客户端和服务端后,来一次模拟调用,再查看wcf日志,可以找到:

              <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
                <s:Header>
                  <a:Action s:mustUnderstand="1">Echo</a:Action>
                  <a:MessageID>urn:uuid:fb825687-ad4c-4eab-8b65-0f7c78b9f845</a:MessageID>
                  <a:ReplyTo>
                    <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
                  </a:ReplyTo>
                  <a:To s:mustUnderstand="1">http://localhost:12345/EchoService/</a:To>
                </s:Header>
                <s:Body>
                  <Echo xmlns="urn:test">
                    <p xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                      <Age>12</Age>
                      <Name>abc</Name>
                    </p>
                  </Echo>
                </s:Body>
              </s:Envelope>
    

        这就是整个请求消息的消息体,也就是说,要实现Xcf的话,必须要完美的模拟这一请求。

    Xcf类库准备

        略:文件下载

    Xcf的使用

        首先,将类库解压并放在项目中,为了请求之前准备好的wcf服务,需要准备这样一个test.xml:

    <?xml version="1.0" encoding="utf-8" ?>
    <Echo xmlns="urn:test">
      <p>
        <Age>23</Age>
        <Name>def</Name>
      </p>
    </Echo>

        这一段的内容与之前抓下来的那个消息中的Body部分一致。

        准备工作做好了,来show一下如何让这个原形调用到服务:

    using (var f = new XcfChannelFactory(new WSHttpBinding()))
    using (var c = f.Create(new Uri("http://localhost:12345/EchoService/")))
    using (var reader = XmlReader.Create("Test.xml"))
    using (var resp = c.Request("Echo", reader))
    using (var respBody = resp.GetBody())
    {
        Console.WriteLine(respBody.ReadInnerXml());
    }
    

        其中,f是工程,c则是通道,reader用于获得一个请求的body,而请求由action和body两部分组成,resp用于保存返回消息,其中的respBody代表着resp消息中的主体。

        运行一下,可以在客户端显示出返回的消息,服务端也显示了请求的Name和Age,并且可以在日志中找到相应的请求和响应消息体。

    下集预告

        到目前为止,原形已经很好的工作了,但是,不能更改请求的Wcf调用,显然是不实用的。别急,如何让这个请求xml活起来,就是下一篇的议题了。

  • 相关阅读:
    数据库学习笔记01 Mariadb安装配置
    数据库学习笔记02 SQL 增删改查
    EF oral study notes 02 level 12~13
    Python编程学习基础笔记10
    EF oral study notes 01 level 10~11
    Linux基础操作命令
    20201318李兴昕第11章学习笔记
    20201318李兴昕第九章学习笔记
    20201318李兴昕第七、八章学习笔记
    20201318李兴昕第十章学习笔记
  • 原文地址:https://www.cnblogs.com/vwxyzh/p/1799675.html
Copyright © 2020-2023  润新知