WCF简单例子(仿照)
1.建一个wcf服务应用程序:
2.定义一个提供wcf服务的接口和数据契约:
namespace WcfService1 { // 服务合同 即提供服务的接口或类 [ServiceContract] public interface IService1 { [OperationContract] void AddTicket(uint count); // 加票 [OperationContract] bool BuyTickets(uint Num); // 买票 [OperationContract] uint GetRemainingNum(); // 查询余票 } //数据契约 [DataContract] public class Ticket { bool boolCount = true; // 判断还有余票 uint many = 10; // 还有多少车票 public Ticket(uint many) { this.many = many; } [DataMember] public bool BoolCount { get { return many > 0; } } [DataMember] public uint Many { get { return many; } set { many = value; } } } }
3.实现服务接口:
namespace WcfService1 { public class Service1 : IService1 { static Ticket ticket = new Ticket(50); // 保证整个服务生命周期的使用同一车票 /// <summary> /// 追加车票 /// </summary> /// <param name="count"></param> /// <returns></returns> public void AddTicket(uint count) { ticket.Many += count; } /// <summary> /// 买票 /// </summary> /// <param name="Num"></param> /// <returns></returns> public bool BuyTickets(uint Num) { if (ticket.Many < Num) { return false; } else {
ticket.Many -= Num; return true; } } /// <summary> /// 查询余票 /// </summary> /// <returns></returns> public uint GetRemainingNum() { return ticket.Many; } } }
4.对于服务器的web.config的配置暂时不是很熟悉。待分析。
5.添加宿主程序:
新建一个winform解决方案,并把wcf的dll导入引用中,追加开启服务,停止服务按钮。
导入引用:System.ServiceModel。
public partial class Form1 : Form { public Form1() { InitializeComponent(); } // 服务主机对象 ServiceHost host = null; private void button1_Click(object sender, EventArgs e) { // 命名空间+类名 host = new ServiceHost(typeof(WcfService1.Service1)); host.Open(); this.label1.Text = "服务已启动"; } private void button2_Click(object sender, EventArgs e) { if (host.State != CommunicationState.Closed) { host.Close(); } this.label1.Text = "服务已停止"; } }
这里的疑问是:为什么每次开启服务都要new对象。
这里要注意的是:new ServiceHost(typeof(WcfService1.Service1))是命名空间+类名,不是命名空间+接口。
6.配置宿主程序的配置文件:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <!--添加服务,服务名称必须是wcf的命名空间和类名--> <service name="WcfService1.Service1" behaviorConfiguration="CalculatorServiceBehavior"> <!--name 必须与代码中的host实例初始化的服务一样 behaviorConfiguration 行为配置 --> <host> <baseAddresses> <!--添加调用服务地址--> <add baseAddress="net.tcp://localhost:8133/WCFTcpService"/> <add baseAddress="http://localhost:8155/WCFTcpService"/> </baseAddresses> </host> <!--添加契约接口 A:address;B:binding="netTcpBinding" netTcpBinding为通过tcp调用;C:contract="WcfService1.IService1"--> <endpoint address="netTcpBinding" binding="netTcpBinding" bindingConfiguration="netTcpBinding" contract="WcfService1.IService1"></endpoint> </service> </services> <!--配置终结点的绑定--> <bindings> <basicHttpBinding> <binding name="basicHttpBinding" closeTimeout="01:01:00" receiveTimeout="01:10:00" sendTimeout="01:01:00" maxReceivedMessageSize="150000002" /> </basicHttpBinding> <wsHttpBinding> <binding name="wsHttpBinding" closeTimeout="01:01:00" receiveTimeout="01:10:00" sendTimeout="01:01:00" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" > <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" /> <security mode="None" /> </binding> </wsHttpBinding> <netTcpBinding> <binding name="netTcpBinding" closeTimeout="01:01:00" receiveTimeout="01:10:00" sendTimeout="01:01:00" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" portSharingEnabled="true" listenBacklog="2147483647" maxConnections="2147483647" maxBufferSize="2147483647"> <readerQuotas maxStringContentLength="2147483647" maxDepth="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" maxArrayLength="2147483647"/> <security mode="None" /> </binding> </netTcpBinding> </bindings> <!--CalculatorServiceBehavior就是终结点行为的名称--> <behaviors> <serviceBehaviors> <behavior name="CalculatorServiceBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
configuration下的system.serviceModel就是wcf的配置,services就是配置主服务,而services下的behaviorConfiguration的配置就是behaviors节点,这个节点下的httpGetEnabled表示使用Http,service表示前台接受异常。
service的name必须是wcf的名称空间+类名,host下的baseAddresses配置的是地址,现在这里有tcp协议和http协议。
最主要的是:endpoint终结点的配置,这里有三个属性分别是ABC,A代表地址address,这里用的是Tcp协议的地址,B代表binding,这个配置比较精细,在binding节点下,涉及到很多问题,C代表契约接口contract,内容是命名空间+接口名称。
7.开启服务:
按理来说我使用的是TCP协议,不知道为什么开启服务之后连接的是Http协议的地址
http://localhost:8155/WCFTcpService
个人猜想,
<?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings> <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" /> </appSettings> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5"/> </system.web> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior> <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false --> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/> <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 --> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> <protocolMapping> <add binding="basicHttpsBinding" scheme="https" /> </protocolMapping> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests="true"/> <!-- 若要在调试过程中浏览 Web 应用程序根目录,请将下面的值设置为 True。 在部署之前将该值设置为 False 可避免泄露 Web 应用程序文件夹信息。 --> <directoryBrowse enabled="true"/> </system.webServer> </configuration>
wcf配置的
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>的原因。待以后在修正。
8.调用服务:
新建winform,含有加票,买票,查票的按钮。
添加服务引用
这里的命名空间SeriveReference1将在接下来使用。
public partial class Form1 : Form { public Form1() { InitializeComponent(); } string msg = "当前车票为{0}张。"; ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(); private void Form1_Load(object sender, EventArgs e) { this.label2.Text = string.Empty; } private void button1_Click(object sender, EventArgs e) { client.AddTicket(5); this.label2.Text = string.Format(msg, client.GetRemainingNum()); } private void button2_Click(object sender, EventArgs e) { client.BuyTickets(1); this.label2.Text = string.Format(msg, client.GetRemainingNum()); } private void button3_Click(object sender, EventArgs e) { this.label2.Text = string.Format(msg, client.GetRemainingNum()); } }
接下来是效果图: