1、如何在控制台中Host多个WCF服务?2、要是服务继承多个契约,在服务器配置文件中该如何写?PS:不能是多个Open方法,那样太幼稚了。谢谢!

解决方案 »

  1.   

    楼主的问题提的不错。我也最近在学习WCF相关内容,也希望能够与大家进行讨论。我大概说说我的感受,但不一定能够帮到你。我觉得WCF是一种通信机制,关键功能在于通信,因此,在处理对象关系方面,应该尽量将其置于其它层面,而不要在WCF的层面上做,这样就复杂了。比如你所说的服务继承多个契约,我认为,从WCF角度考虑,是应该需要避免的,我们是不是可以考虑,把这多个契约的功能合并一下。比如,在领域模型中,类与类之间的关系处理是非常频繁的事情,一个类可以继承于另一个类,并实现多个接口,这些都是合理的,因为他们遵循业务需求,是领域问题在计算机上的一种表现形式,那么在处理完这些业务逻辑后,我们需要通过某种机制将处理结果传输到UI,并显示给用户,那么这个传输工作就由WCF完成。事实上国外有很多文章都谈到至今WCF都不太流行的原因,大多都认为WCF在扩展性支持方面做的不是很好,即使有类似DynamicProxy的东西,也无法完美的解决WCF的扩展问题。设想,如果今后你的业务系统发生了更改,在服务端添加了某些服务契约,那么在客户端,你不得不去修改配置文件以达到使用这个服务的目的。退一步说,如果你的服务端公布的契约很多,那么你不得不去维护一个庞大的配置文件,这是让人头疼的事情。
    所以我觉得,WCF层面上的设计应该要尽量简单,不要将过多的逻辑放在这个层面。不知楼主是否能够苟同我的想法呢。
      

  2.   

    首先,服务的一些配置都在配置文件中,如下<?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.serviceModel>
        <services>
          <service name="ChinaQueue.Restaurant.WCFService.ServiceImplementations.PrinterSer" behaviorConfiguration="sb">
            <host>
              <baseAddresses>
                <add baseAddress="net.tcp://localhost:8081" />
              </baseAddresses>
            </host>
            <endpoint name="NetTcpBinding_IPrinterServer" address="PrinterSer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.IPrinterSer" />
            <endpoint name="MexTcpBinding_IPrinterServer" address="Printer" binding="mexTcpBinding" contract="IMetadataExchange" />
          </service>
          <service name="ChinaQueue.Restaurant.WCFService.ServiceImplementations.CounterSer" behaviorConfiguration="sb">
            <host>
              <baseAddresses>
                <add baseAddress="net.tcp://localhost:8081" />
              </baseAddresses>
            </host>
            <endpoint name="NetTcpBinding_ICounterServer" address="CounterSer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.ICounterSer" />
            <endpoint name="MexTcpBinding_ICounterServer" address="Counter" binding="mexTcpBinding" contract="IMetadataExchange" />
          </service>
          <service name="ChinaQueue.Restaurant.WCFService.ServiceImplementations.QuerySer" behaviorConfiguration="sb">
            <host>
              <baseAddresses>
                <add baseAddress="net.tcp://localhost:8081" />
              </baseAddresses>
            </host>
            <endpoint name="NetTcpBinding_IQueryServer" address="QuerySer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.IQuerySer" />
            <endpoint name="MexTcpBinding_IQueryServer" address="Query" binding="mexTcpBinding" contract="IMetadataExchange" />
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="sb">
              <serviceMetadata />
              <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <bindings>
          <netTcpBinding>
            <binding name="NetTcpBinding_IServer">
              <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
              <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
              <security mode="None">
                <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                <message clientCredentialType="Windows" />
              </security>
            </binding>
          </netTcpBinding>
        </bindings>
        <client>
          <endpoint address="net.tcp://localhost:8081/PrinterSer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.IPrinterSer" name="NetTcpBinding_IPrinterServer" />
          <endpoint address="net.tcp://localhost:8081/CounterSer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.ICounterSer" name="NetTcpBinding_ICounterServer" />
          <endpoint address="net.tcp://localhost:8081/QuerySer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.IQuerySer" name="NetTcpBinding_IQueryServer" />
        </client>
      </system.serviceModel>
    </configuration>以上是三个服务的配置,
    然后在Main方法中Host这三个服务,以下是如何从配置文件中读取服务并进行Host的Configuration conf = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location);
                ServiceModelSectionGroup svcmod = (ServiceModelSectionGroup)conf.GetSectionGroup("system.serviceModel");
                foreach (ServiceElement el in svcmod.Services.Services)
                {
                    Type svcType = Type.GetType(el.Name + "," + "ChinaQueue.Restaurant.WCFService");
                    if (svcType == null)
                        throw new Exception("Invalid Service Type " + el.Name + " in configuration file.");
                    aServiceHost = new ServiceHost(svcType);
                    aServiceHost.Open();
                }这是以前写过的一个多服务的项目中的代码,还有什么不明白的地方加QQ79878172
      

  3.   

    顶一下!楼上的代码完全可行,我也这样用过。但这种是多个serviceHost的Open调用,不知楼主是否满意。
      

  4.   

    首先很感谢二楼“飞雪孤风”的正确答案,但是学习过程中还是有小小的疑问:
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <services>
          <service behaviorConfiguration="MyBehavior1" name="Book.Bll.UserBll">
            <endpoint address="UserBll" binding="netTcpBinding" bindingConfiguration="DuplexBinding"
              contract="Book.Contract.IUser" />
            <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
              contract="IMetadataExchange" />
            <host>
              <baseAddresses>
                <add baseAddress="net.tcp://localhost:9999/Service" />
              </baseAddresses>
            </host>
          </service>
          
          <service behaviorConfiguration="MyBehavior2" name="Book.Bll.UserOperation">
            <endpoint address="UserOperation" binding="netTcpBinding" bindingConfiguration="DuplexBinding"
              contract="Book.Contract.ICommonOperation" />
            <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
              contract="IMetadataExchange" />
            <host>
              <baseAddresses>
                <add baseAddress="net.tcp://localhost:9999/Service" />
              </baseAddresses>
            </host>
          </service>
      </services>    <behaviors>
          <serviceBehaviors>
            <behavior  name="MyBehavior1">
              <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:9111/Service" />
              <serviceThrottling maxConcurrentSessions="10000" />
              <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
            <behavior  name="MyBehavior2">
              <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:9112/Service" />
              <serviceThrottling maxConcurrentSessions="10000" />
              <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>    <bindings>
          <netTcpBinding>
            <binding name="DuplexBinding">
              <reliableSession enabled="true" />
              <security mode="None" />
            </binding>
          </netTcpBinding>
        </bindings>
      </system.serviceModel>
    </configuration>我的多服务配置文件这样写,其中<behavior  name="MyBehavior1">和<behavior  name="MyBehavior2">分别对应两个服务,不知道为什么会这样,如果只有一个<behavior>的话,两个服务都引用它,就会报错,好像二楼“飞雪孤风”也是这样引用的啊,怎么没事?
    还有直接把<client>节点写在服务器端配置文件里也行吗?
    再者我执行Type svcType = Type.GetType(el.Name+","+"Book");这句时,发那会的svcType=null,这怎么解决。
      

  5.   

    #sunnychen.org
    首先还是表示对这帖子的关注!O(∩_∩)O~
    目前对我来说合并契约也许是一个不错的选择。在WCF中,如果服务多了,庞大的配置文件和客户端代理类的却是一个令人头疼的问题,但是事情总是两面的,也好的就会有不好的。
    “WCF层面上的设计应该要尽量简单”这是应该遵循的,但是如果有的逻辑必需交给服务器处理,那就没有办法逃避了。
      

  6.   

    好长时间没弄WCF了,但是楼主,我写的服务配置是在本机上的8081端口上开了三个服务,就是说一个端口上有三个服务可访问,通讯方式是TCP传输.而你的配置是开了两个端口,一个是9111,一个是9112,而且behavior设置是HTTP传输的.但你设置服务的地址时是Net.Tcp啊,我不明白你为什么这样配置!
      

  7.   

    #ycsno1
    这样就能够通过svcutil获取服务端的元数据了。
    如果按你那样写的话,怎么样通过svcutil工具获取元数据呢?
      

  8.   

    我在使用WCF过程中也遇到同样的问题,一开始准备构建N个服务接口,但是就光打开、关闭就N个,还有非常复杂的配置文件,维护起来比较麻烦。
      

  9.   

    http://xiaoyu8882008.blog.163.com/blog/static/1068919142010315414383/ 这里面这种方法完全可用,我试过了,只用改配置就可以了