WCF开发日志 -- WCF启动多个服务

一、摘要

场景:  

      项目比较大,不可能所有契约在一个类里来实现,可能会有上百个服务上千个契约,按照目前在网上搜索的结果是…..只能一个servicehost对应一个服务,某个mvp的建议是所有契约都放到一个类里来实现。。。我崩溃  。。。。。

想法:

       也有人建议用 partial class的方式,把不同的契约分布到不同的CS文件里,虽然可能看上去好一点,但每回添加服务都得重编译,我觉得太扯淡了 。。。。。

       我希望是尽可能的把服务根据功能的不同按模块划分开来,不同的服务做成不同的dll,以插件的形式注册到一个表里,用servicehost来加载,不知大家有没有好的建议 。

       其实可以考虑用CSLA.NET的方案,只写一个服务,它称为统一入口,这个方式还是不错的,就是他为解决并发,并发好像在博客园里有人写了怎么实现,地址是                  http://www.cnblogs.com/zgynhqf/archive/2010/07/01/1769228.html

现实: 

说一千道一万架不住我不会,我只能实现:

1、如何在Windows中Host多个WCF服务?
2、不能是多个Open方法,那样太幼稚了 !

3、 考虑到整个团队都不会CSLA.NET,或OEA 就我会一点:) , 这个还的多谢周哥,和 胡总 的栽培了。

4、 整个团队学习成本太高,只有不断的分享,讨论来加快进度了。 
二、本文大纲

       a、摘要 。

       b、本文大纲 。

       c、项目准备阶段 。

       d、主要核心代码 。

       e、达到的效果图 。

三、项目准备阶段

这个图需要一点C# 基础才能看的懂的:) 估计一上图大家就看的懂(自己想象中……..)了。

clipboard

   这里主要是创建 Windows项目和 WCF Service Library 项目

  Windows项目还需要引用WCF Service Library 项目

四、主要核心代码

clipboard[9]

运行按钮事件代码:

 1:         private void button1_Click(object sender, EventArgs e)

    
 2:         {

    
 3:             if (button1.Tag == "run")

    
 4:             {

    
 5:                 ServiceStart();

    
 6:                 button1.Text = "停止(&X)";

    
 7:                 button1.Tag = "stop";

    
 8:             }

    
 9:             else

    
10:             {

    
11:                 button1.Text = "运行(&R)";

    
12:                 button1.Tag = "run";

    
13:             }

    
14:         }

    
15:   
  

ServiceStart() 函数代码:

 1:  private List<ServiceHost> serviceHosts = new List<ServiceHost>();

    
 2:    private void ServiceStart()

    
 3:    {

    
 4:   

    
 5:        #region 初?始?化ˉ serviceHosts

    
 6:        if (serviceHosts != null)

    
 7:        {

    
 8:            foreach (ServiceHost t in serviceHosts)

    
 9:            {

    
10:                if (t != null)

    
11:                    t.Close();

    
12:            }

    
13:        }

    
14:        else

    
15:        {

    
16:            serviceHosts = new List<ServiceHost>();

    
17:        }

    
18:        #endregion

    
19:  

    
20:        string serviceAddress = string.Format("net.tcp://{0}:{1}", "127.0.0.1", "8000");

    
21:   

    
22:        Dictionary<Type,Type> sevtypes=new Dictionary<Type,Type>();

    
23:        sevtypes.Add(typeof(IService1),typeof(Service1));

    
24:        sevtypes.Add(typeof(IService2), typeof(Service2));

    
25:   

    
26:        string endpointAddress = string.Empty;

    
27:        string tName = string.Empty;

    
28:        StringBuilder msgService = new StringBuilder();

    
29:        foreach (var item in sevtypes)

    
30:        {

    
31:            tName = item.Key.Name.Substring(1);

    
32:            endpointAddress = serviceAddress + tName;

    
33:            if (!serviceAddress.EndsWith("/"))

    
34:                endpointAddress = string.Format("{0}/{1}", serviceAddress, tName);

    
35:            ServiceHost serviceHost = new ServiceHost(item.Value, new Uri(endpointAddress));

    
36:   

    
37:            //加载元数据结点

    
38:            ServiceMetadataBehavior smb = new ServiceMetadataBehavior();

    
39:            serviceHost.Description.Behaviors.Add(smb);

    
40:            serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");

    
41:            //加载NetTcpBinding结点

    
42:            NetTcpBinding netTcpBinding = new NetTcpBinding();

    
43:            netTcpBinding.Security.Mode = SecurityMode.None;

    
44:            netTcpBinding.ReceiveTimeout = TimeSpan.Parse("00:10:00");

    
45:            netTcpBinding.MaxBufferPoolSize = 2147483647;

    
46:            netTcpBinding.MaxBufferSize = 2147483647;

    
47:            netTcpBinding.MaxConnections = 10;

    
48:   

    
49:            netTcpBinding.ReaderQuotas.MaxDepth = 2147483647;

    
50:            netTcpBinding.ReaderQuotas.MaxStringContentLength = 2147483647;

    
51:            netTcpBinding.ReaderQuotas.MaxArrayLength = 2147483647;

    
52:            netTcpBinding.ReaderQuotas.MaxBytesPerRead = 2147483647;

    
53:            netTcpBinding.ReaderQuotas.MaxNameTableCharCount = 2147483647;

    
54:            netTcpBinding.MaxReceivedMessageSize = 2147483647;

    
55:            serviceHost.AddServiceEndpoint(item.Key, netTcpBinding, endpointAddress);

    
56:   

    
57:            serviceHost.Opened += delegate

    
58:            {

    
59:                msgService.AppendLine(string.Format("{0}开始监听 Uri 为 :{1}/mex", tName, endpointAddress.ToString()));

    
60:            };

    
61:   

    
62:            serviceHost.Open();

    
63:            serviceHosts.Add(serviceHost);

    
64:        }

    
65:        this.textBox1.Text = msgService.ToString();

    
66:    }

    
67:   
  

代码约定:

    每次增加服务和契约的时候都需要同时添加 Dictionary 要不然系统不会启动新增加的服务。

服务地址:

net.tcp://127.0.0.1:8000/服务名/mex

image

上面的例子生成如下地址:

net.tcp://127.0.0.1:8000/Service1/mex

net.tcp://127.0.0.1:8000/Service2/mex

把 ”Dictionary ”改成配置文件形式,也就通用了。

网上的一个使用配置文件的例子:

配置文件如下:

 1:   <system.serviceModel>

    
 2:      <services>

    
 3:        <service name="ChinaQueue.Restaurant.WCFService.ServiceImplementations.PrinterSer" behaviorConfiguration="sb">

    
 4:          <host>

    
 5:            <baseAddresses>

    
 6:              <add baseAddress="net.tcp://localhost:8081" />

    
 7:            </baseAddresses>

    
 8:          </host>

    
 9:          <endpoint name="NetTcpBinding_IPrinterServer" address="PrinterSer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.IPrinterSer" />

    
10:          <endpoint name="MexTcpBinding_IPrinterServer" address="Printer" binding="mexTcpBinding" contract="IMetadataExchange" />

    
11:        </service>

    
12:        <service name="ChinaQueue.Restaurant.WCFService.ServiceImplementations.CounterSer" behaviorConfiguration="sb">

    
13:          <host>

    
14:            <baseAddresses>

    
15:              <add baseAddress="net.tcp://localhost:8081" />

    
16:            </baseAddresses>

    
17:          </host>

    
18:          <endpoint name="NetTcpBinding_ICounterServer" address="CounterSer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.ICounterSer" />

    
19:          <endpoint name="MexTcpBinding_ICounterServer" address="Counter" binding="mexTcpBinding" contract="IMetadataExchange" />

    
20:        </service>

    
21:        <service name="ChinaQueue.Restaurant.WCFService.ServiceImplementations.QuerySer" behaviorConfiguration="sb">

    
22:          <host>

    
23:            <baseAddresses>

    
24:              <add baseAddress="net.tcp://localhost:8081" />

    
25:            </baseAddresses>

    
26:          </host>

    
27:          <endpoint name="NetTcpBinding_IQueryServer" address="QuerySer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.IQuerySer" />

    
28:          <endpoint name="MexTcpBinding_IQueryServer" address="Query" binding="mexTcpBinding" contract="IMetadataExchange" />

    
29:        </service>

    
30:      </services>

    
31:      <behaviors>

    
32:        <serviceBehaviors>

    
33:          <behavior name="sb">

    
34:            <serviceMetadata />

    
35:            <serviceDebug includeExceptionDetailInFaults="true" />

    
36:          </behavior>

    
37:        </serviceBehaviors>

    
38:      </behaviors>

    
39:      <bindings>

    
40:        <netTcpBinding>

    
41:          <binding name="NetTcpBinding_IServer">

    
42:            <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />

    
43:            <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />

    
44:            <security mode="None">

    
45:              <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />

    
46:              <message clientCredentialType="Windows" />

    
47:            </security>

    
48:          </binding>

    
49:        </netTcpBinding>

    
50:      </bindings>

    
51:      <client>

    
52:        <endpoint address="net.tcp://localhost:8081/PrinterSer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.IPrinterSer" name="NetTcpBinding_IPrinterServer" />

    
53:        <endpoint address="net.tcp://localhost:8081/CounterSer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.ICounterSer" name="NetTcpBinding_ICounterServer" />

    
54:        <endpoint address="net.tcp://localhost:8081/QuerySer" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServer" contract="ChinaQueue.Restaurant.WCFService.ServiceContracts.IQuerySer" name="NetTcpBinding_IQueryServer" />

    
55:      </client>

    
56:    </system.serviceModel>

    
57:  
  

以上是三个服务的配置,
然后在Main方法中Host这三个服务,以下是如何从配置文件中读取服务并进行Host的

System.ServiceModel.Configuration

 1:  Configuration conf = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location);

    
 2:             ServiceModelSectionGroup svcmod = (ServiceModelSectionGroup)conf.GetSectionGroup("system.serviceModel");

    
 3:             foreach (ServiceElement el in svcmod.Services.Services)

    
 4:             {

    
 5:                 Type svcType = Type.GetType(el.Name + "," + "ChinaQueue.Restaurant.WCFService");

    
 6:                 if (svcType == null)

    
 7:                     throw new Exception("Invalid Service Type " + el.Name + " in configuration file.");

    
 8:                 ServiceHost aServiceHost = new ServiceHost(svcType);

    
 9:                 aServiceHost.Open();

    
10:             }

    
11:   
  
五、达到的效果图

测试通过,有图作证:

clipboard[11]

这个服务启动成功了,客服端也测试通过,耶搞定。  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值