zoukankan      html  css  js  c++  java
  • 【WCF】基址与默认终结点

    五月份的时候,有位老友给老周提了个建议:希望老周写一写WCF的文章。其实老周以前是写过WCF的文章的,只是不是写在这个博客里,老周并不打算把X年前的博客导进来,要写的话,重新写吧。毕竟,那个时候写的文章是比较肤浅。

    根据老周有限的记忆,WPF、WCF、WF、WIF等已经问世有十个年头了,老周耍.net已经十几个年头了吧,因为.net好玩、耐玩,所以一玩十来年,一直享受着优游之乐,如同当年庄子在濠梁之上所说的一样。

    顺便跟各位在校的同胞们说一下,.net已不是什么新技术了,如果你认为它是新技术,表明你与你的学校实在太落后了,落后得无法用文字来形容。像WPF、WCF、WF、MEF等东东,包括现在的UWP、.net core等新玩意儿,你只能依靠自学,不走自学之路,你很难有所收获的。你一定要相信,你有自学成才的能力,想想,像老周这种笨蛋都可以完全依靠自学,你一定能的。而且,还要告诉你,老周自学的不仅仅是编程,老周自学的领域覆盖文、理,贯通天地人神鬼,涉猎古今……老周向来是爱好广,兴趣广。

    那么,为啥强调自学呢?因为当今中国的大学,计算机教学水平,普通低下,低到惨不忍睹的程度。许多大学计算机老师,一辈子只见过两样东西——C/C++ 和 Java,除此二者之外,他们都不懂,教材照样年年用着上世纪90年代的书,学习工具停留在VS 6.0,所学内容严重脱离实际应用。老周一直想不明白,那些什么教授啊老师啊,研究了几十年,就研究出这点水平,也不知道他们平时都干什么去了,可能去研究妹子去,看妹子的眼光比看技术的眼光还准。

    哪怕是C/C++,如果你问老师:函数传参中,int* x 和 const int& x 有什么不同,或者问 int const* x 是啥、exten "C"是什么东东,估计一些老师的反应是:这个,这个嘛,这个……现在别问这些,打基础要紧。

    所以,你看看,不依靠自学,你能学到东西吗?

    好了,转回咱们今天的主题。今天咱们聊聊WCF的一个基础知识——基址和默认终结点。

    基址,从base address翻译过来,可能英文名字更好理解,就是给服务指定一个基础URI,而随后向服务添加的终结点的地址可以基于这个地址,当然了,添加的终结点也可以指定绝对URI。

    例如,基址为http://mm.net/images/,某个终结点的相对地址为face,于是,与基址一组合,终结点的完整地址就是 http://mm.net/images/face。

    再比如,基址net.tcp://192.168.1.20:999/,某个终结点的相对URI为 pay,那么,与基址组合后,终结点的完整地址为:net.tcp://192.168.1.20:999/pay。

    在非IIS上运行时,比如在一个exe中承载服务,会用到ServiceHost类,实例化该host时,需要指定一个Type,它表示服务类的类型信息,至于基址,是可选的。

    如果不指定基址,那么,添加的终结点就必须指定绝对URI;如果有了基址,那么添加的终结点既可以用相对URI,也可以用绝对URI。

    在定义基址时,有一点要注意,相同的协议不能添加多次,比如:

    http://someone:1010/sv

    已经添加到基址列表中,你就不能再添加http://someone:1012/orders了,因为http协议的地址已经添加过了。不过,运行在IIS中的WCF服务可以通过以下配置来解决:

      <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>

    在windows进程中host的服务就不可以了,所以,你要记住了,像下面这样指定基址是会报错的。

        <services>
          <service name="sv">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:900/service"/>
                <add baseAddress="http://localhost:1000/services/mytest"/>
                <add baseAddress="http://localhost:1100/wcfservices/mytestfun"/>
              </baseAddresses>
            </host>
          </service>
        </services>

    如果不是同一协议,是可以指定多个基址的,比如:

            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:900/"/>
                <add baseAddress="net.tcp://localhost:3500/services"/>
              </baseAddresses>
            </host>

    一个是http的,一个是netTcp的,所以这两个基址是允许的。

    基址介绍完了,再看看默认终结点,要使用默认终结点,一定要添加基址。所谓默认终结点,就是你不用手动去添加终结点,只要向ServiceHost指定了基址和服务类的类型,那么,运行时会根据服务类所实现的协定,自动添加终结点,终结点的地址就是基址。

    比如,假设服务类实现了一个服务协定接口,并且指定了以下两个基址:

                <add baseAddress="http://localhost:6000/"/>
                <add baseAddress="net.tcp://localhost:6100"/>

    服务会添加两个默认终结点,针对http协议的终结点将使用basicHttpBinding,针对netTcp协议的终结点会使用NetTcpBinding,并且两个终结点的Contract都是同一个协定——服务实现的那个协定。

    可以加入以下代码来检测一下:

                ServiceHost host = new ServiceHost(typeof(MyService));
    
                host.Open();
    
                foreach(ServiceEndpoint ep in host.Description.Endpoints)
                {
                    Console.WriteLine($"地址:{ep.Address.Uri.AbsoluteUri},binding类型:{ep.Binding.GetType().Name}");
                }
    
                Console.WriteLine("按任意键退出。");
                Console.Read();
                host.Close();

    然后,你会看到以下输出。

    上面的情况是我只实现了一个服务协定,那么,如果服务类实现了多个服务协定接口呢?

    来,试试看。

        [ServiceContract()]
        public interface IService
        {
            [OperationContract]
            void GoodBoy(string name);
        }
    
        [ServiceContract]
        public interface IService2
        {
            [OperationContract]
            void GoodGirl(string name);
        }

    睁大眼睛看好了,这是两个服务协定接口,然后,我们用一个服务类同时实现这两个接口。

        class MyService : IService, IService2
        {
            public void GoodBoy(string name)
            {
                // .................................
            }
    
            public void GoodGirl(string name)
            {
                // .................................
            }
        }

    好了,现在你知道,服务类MyService实现了两个服务协定,那么,运行时添加的默认终结点会有几个呢?不急,真相就在下面。

    把上面的输出代码改一下,让其输出协定的类型名称。

                foreach (ServiceEndpoint ep in host.Description.Endpoints)
                {
                    Console.WriteLine($"地址:{ep.Address.Uri.AbsoluteUri},binding类型:{ep.Binding.GetType().Name},协定名:{ep.Contract.ContractType.Name}");
                }

    运行后,看到如下内容。

    为啥会变成4个终结点了?

    首先,我们知道,有两个基址,分别是http和nettcp协议。

    再者,服务实现了两个协定。

    一个终结点由地址、绑定、协定三个主要要素组成,非主要要素可能会有Behavior、地址头等。也就是说,一个终结点只能指定一个服务协定,一个终结点只能指定一个绑定,一个终结点也只能有一个地址

    现在你明白了吧,两个协定,两个地址,所以终结点的个数 = 2 × 2,就是4个了。

    依此类推,两个基址(不同协议)固定,如果服务类实现了3个协定接口,那么,运行时添加的默认终结点就有6个。

    好了,今天的话题就讨论到此了,不难吧。

  • 相关阅读:
    机器学习规则:ML工程最佳实践----rules_of_ml section 2【翻译】
    机器学习规则:ML工程最佳实践----rule_of_ml section 3【翻译】
    知识图谱技术分享会----有关知识图谱构建的部分关键技术简介及思考
    【e2Open】
    【2B】企业供应链管理软件
    【交互】复杂逻辑配置的一个不错的方法(神策数据)
    【视觉】交易数据展示
    【视觉】数据平台
    【设计复盘】APP设计复盘
    【设计规范】腾讯课堂
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/5830920.html
Copyright © 2011-2022 走看看