03 配置服務
http://www.cnblogs.com/easy5weikai/p/3825357.html
數據庫
生成數據庫腳本:
CREATE DATABASE [EmployeeDb]; CREATE TABLE [dbo].[T_Employee]( [Id] [int] IDENTITY(1,1) NOT NULL, [Name] [nvarchar](50) NOT NULL, [Job] [nvarchar](50) NOT NULL, [Salary] [float] NOT NULL, [Dept] [nchar](10) NULL, ) ;
Employee.cs
數據訪問EmployeeDAL.cs
using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Text; using Keasy5.WCF.Imin.Chart06.DTO; namespace Keasy5.WCF.Imin.Chart06.DAL { public class EmployeeDAL { private const string ConnectingString = "Data Source=.;Initial Catalog=EmployeeDb;Integrated Security=True;Pooling=False"; public IEnumerable<Employee> GetEmployees() { using (var sqlConnection = new SqlConnection(ConnectingString)) { List<Employee> result = new List<Employee>(); Employee employee = null; string sqlQuery = "Select * from T_Employee;"; DataTable dataTable = new DataTable(); SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlQuery, sqlConnection); sqlDataAdapter.Fill(dataTable); for (int i = 0; i < dataTable.Rows.Count; i++) { employee = new Employee(); employee.Id = Convert.ToInt32(dataTable.Rows[i]["Id"]); employee.Name = Convert.ToString(dataTable.Rows[i]["Name"]); employee.Job = Convert.ToString(dataTable.Rows[i]["Job"]); employee.Salary = Convert.ToDouble(dataTable.Rows[i]["Salary"]); employee.Dept = Convert.ToString(dataTable.Rows[i]["Dept"]); result.Add(employee); } return result; } } public void AddEmployee(Employee employee) { using (var sqlConnection = new SqlConnection(ConnectingString)) { sqlConnection.Open(); using (SqlCommand command = sqlConnection.CreateCommand()) { StringBuilder insertSql = new StringBuilder(); insertSql.Append("insert into T_Employee values(@Name,@Job,@Salary,@Dept)"); command.CommandType = CommandType.Text; command.CommandText = insertSql.ToString(); command.Parameters.Add(new SqlParameter("@Name", employee.Name)); command.Parameters.Add(new SqlParameter("@Job", employee.Job)); command.Parameters.Add(new SqlParameter("@Salary", employee.Salary)); command.Parameters.Add(new SqlParameter("@Dept", employee.Dept)); command.ExecuteNonQuery(); } } } } }
WCF的定義
服務接口IService1
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Security.Cryptography.X509Certificates; using System.ServiceModel; using System.Text; using System.Data; using System.Data.SqlClient; using Keasy5.WCF.Imin.Chart06.DTO; namespace Keasy5.WCF.Imin.Chart06.Pro02 { [ServiceContract] public interface IService1 { [OperationContract] IEnumerable<Employee> GetEmployees(); [OperationContract] void AddEmployee(Employee employee); } }
服務實現類Service1.cs
WCF服務端的配置
一個最基本的服務(宿主)端配置如下:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <service name ="Keasy5.WCF.Imin.Chart06.Pro02.Service1" behaviorConfiguration="testBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:5555"/> </baseAddresses> </host> <endpoint address ="" binding="wsHttpBinding" contract="Keasy5.WCF.Imin.Chart06.Pro02.IService1"> </endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior name="testBehavior"> <serviceMetadata httpGetEnabled="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
宿主選擇WinForm,服務的開啓和關閉如下代碼所示:
其中創建宿主的ServiceHost類的構造函數:
// // 摘要: // 使用服務的類型及其指定的基址初始化 System.ServiceModel.ServiceHost 類的新實例。 // // 參數: // serviceType: // 承載服務的類型。 // // baseAddresses: // System.Uri 類型的數組,包含承載服務的基址。 // // 異常: // System.ArgumentNullException: // serviceType 爲 null。 public ServiceHost(Type serviceType, params Uri[] baseAddresses);
第二個參數是可變參數類型:所以可以參入基於不同協議的Uri,
Uri = “net.TCP://localhost/....”
Uri = "http://....."
Uri = "net.pipe://。。。"
。。。。
傳入這些Uir基地址,實現同一服務,可同時提供多種協議的服務:
//地址 Uri pipeaddress = new Uri("net.pipe://localhost/NetNamedPipeBinding"); Uri tcpaddress = new Uri("net.tcp://localhost:8088/TcpBinding"); //服務宿主對象 host = new ServiceHost(typeof(WcfServiceLibrary1.Service1), pipeaddress, tcpaddress); //綁定 NetNamedPipeBinding pb = new NetNamedPipeBinding(); NetTcpBinding tp = new NetTcpBinding();
或者使用配置文件進行配置:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <service name="WcfServiceLibrary1.Service1" behaviorConfiguration="textBehavior"> <host> <baseAddresses> <add baseAddress="net.tcp://localhost:8088/tcpBinding"/> <add baseAddress="http://localhost:3200/httpBinding"/> <add baseAddress="net.pipe://localhost/pipeBinding"/> </baseAddresses> </host> <endpoint address="tcpmex" binding="mexTcpBinding" contract="IMetaExchange"></endpoint> <endpoint address="pipemex" binding="mexNamedPipeBinding" contract="IMetaExchange"></endpoint> <endpoint address="" binding="wsHttpBinding" contract="WcfServiceLibrary1.IService1"></endpoint> <endpoint address="" binding="netTcpBinding" contract="WcfServiceLibrary1.IService1"></endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior name="textBehavior"> <serviceMetadata/> <serviceDebug/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
客戶端調用WCF服務
客戶端調用WCF服務,需要一個WCF服務的代理類;
獲取該代理類的方法有幾種:
【1】在客戶端的項目中引用服務的方式
添加服務引用時自動生成的服務代理時自動生成的EndPiont
<!--添加服務引用時自動生成的服務代理時自動生成的EndPiont--> <endpoint address="http://127.0.0.1:9999/Easy5WCFService" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_CalcutorService" contract="CalcutorWCFService.CalcutorService" name="BasicHttpBinding_CalcutorService" />
//方法1:使用添加服務引用時自動生成的服務代理(這時,自動生成app.config) //此法用的代理服務命名空間的類型 using (CalcutorWCFService.CalcutorServiceClient proxy = new CalcutorWCFService.CalcutorServiceClient()) { double x = Convert.ToDouble(this.textBox1.Text); double y = Convert.ToDouble(this.textBox2.Text); this.textBox3.Text = Convert.ToString(proxy.Add(x, y)); }
【2】手工生成代理類,這種又有很多種方式:
2.1 ChannelFactory<T>
使用ChannelFactory<T>的好處是支持泛型。
//此法需要:自己動手添加app.config using (ChannelFactory<Contract.ICalcuator> channelFactory = new ChannelFactory<Contract.ICalcuator>("calcutorService"))//calcutorService爲配置文件(app.config)中的endpoint的Name屬性 { Contract.ICalcuator calcuator = channelFactory.CreateChannel(); double x = Convert.ToDouble(this.textBox1.Text); double y = Convert.ToDouble(this.textBox2.Text); this.textBox3.Text = Convert.ToString(calcuator.Add(x, y)); }
需要手工在app.config文件中添加endPoint節點配置:
<!--自己動手寫服務代理時,需要手動添加的EndPoint--> <endpoint address="http://127.0.0.1:9999/Easy5WCFService" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_CalcutorService" contract="Contract.ICalcuator" name="calcutorService" />
ChannelFactory<T>的構造函數有多個重載,也可以按如下方式創建:
using (ChannelFactory<Contract.ICalcuator> channelFactory = new ChannelFactory<Contract.ICalcuator>(new BasicHttpBinding(), "http://127.0.0.1:9999/Easy5WCFService")) { Contract.ICalcuator calcuator = channelFactory.CreateChannel(); double x = Convert.ToDouble(this.textBox1.Text); double y = Convert.ToDouble(this.textBox2.Text); this.textBox3.Text = Convert.ToString(calcuator.Add(x, y)); }
但是,這種方式是硬編碼方式,靈活性不好,不推薦。
2.2 使用svcutil.exe工具生成代理類:
WCF的服務元數據(Metadata),遵循Web服務描述語言(WSDL)標準,所以支持多種編程語言,處理WCF的svcutil.exe外,
java程序員也可以使用諸如WSDL2Java工具生成Java語言的客戶端代理類。
下面介紹使用svcutil.exe生成C#語言的代理類:
第一步:公開WCF服務的元數據信息
方法一: 通過<serviceMetadata httpGetEnabled="true"/>公開,如下所示
<system.serviceModel> <services> <service name ="Keasy5.WCF.Imin.Chart06.Pro02.Service1" behaviorConfiguration="testBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:5555"/> </baseAddresses> </host> <endpoint address ="" binding="wsHttpBinding" contract="Keasy5.WCF.Imin.Chart06.Pro02.IService1"> </endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior name="testBehavior"> <serviceMetadata httpGetEnabled="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
方法二: 通過EndPoint端點的方式進行公開,在服務的配置文件中添加如下配置
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <service name ="Keasy5.WCF.Imin.Chart06.Pro02.Service1" behaviorConfiguration="testBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:5555"/> </baseAddresses> </host> <endpoint address ="" binding="wsHttpBinding" contract="Keasy5.WCF.Imin.Chart06.Pro02.IService1"> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetatadaExchange"> </endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior name="testBehavior"> <serviceMetadata httpGetEnabled="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
公開WCF服務的元數據信息後就可以在瀏覽器中輸入:http://localhost:5555 就可以查看WCF服務信息。
第二步:
打開【VS2013 開發人員命令提】,輸入:
svcutil.exe http://localhost:5555/?wsdl
自動生成的文件:
Service1.cs是生成的代理類
output.config是配置文件
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.serviceModel> <bindings> <wsHttpBinding> <binding name="WSHttpBinding_IService1" /> </wsHttpBinding> </bindings> <client> <endpoint address="http://localhost:5555/" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1" contract="IService1" name="WSHttpBinding_IService1"> <identity> <userPrincipalName value="easy5-PC\easy5" /> </identity> </endpoint> </client> </system.serviceModel> </configuration>
現在用在項目中引用服務的方式添加代理,客戶端如下調用代理:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Keasy5.WCF.Chart06.Pro02.Client.ServiceReference1; using Keasy5.WCF.Imin.Chart06.DTO; namespace Keasy5.WCF.Chart06.Pro02.Client { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { IService1 proxService1 = new Service1Client(); Employee newEmployee = new Employee() { Name = "Jack", Job = "Killer", Salary = 1000000, Dept = "N/A" }; proxService1.AddEmployee(newEmployee); } private void button2_Click(object sender, EventArgs e) { IService1 proxService1 = new Service1Client(); IEnumerable<Employee> employees = proxService1.GetEmployees(); this.dataGridView1.DataSource = employees; } } }
本文代碼下載: