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]

這個服務啟動成功了,客服端也測試通過,耶搞定。  

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM