WCF
一、WCF合并了 ASP.NET Web服务,.NET Remoting技术,消息队列,.NET Enterprise Service(支持自动事物处理)技术。
WCF服务可以存放在ASP.NET运行库,windows服务,COM+进程或windows窗体应用程序中进行对等计算。
WCF提供了HTTP、TCP和IPC信道进行通信的多条信道。也可以创建使用不同传输协议的自定义信道。
WSDL:提供描述服务的元数据。
简单实现的服务和客户端
服务协定
定义服务协定的接口 IRoomService(RoomReservation实体类)
View Code
[ServiceContract()] public interface IRoomService { [OperationContract] bool ReserveRoom(RoomReservation roomReservation); [OperationContract] RoomReservation[] GetRoomReservations(DateTime fromDate, DateTime toDate); }
实现IRoomService
View Code
public class RoomReservationService : IRoomService { public bool ReserveRoom(RoomReservation roomReservation) { var data = new RoomReservationData(); data.ReserveRoom(roomReservation); return true; } public RoomReservation[] GetRoomReservations(DateTime fromDate, DateTime toDate) { var data = new RoomReservationData(); return data.GetReservations(fromDate, toDate); } }
配置文件(可以右键配置文件动态配置)
View Code
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.diagnostics> <trace autoflush="true" /> </system.diagnostics> <system.web> <compilation debug="true" /> </system.web> <!-- 部署服务库项目时,必须将配置文件的内容添加到 主机的 app.config 文件中。System.Configuration 不支持库的配置文件。--> <system.serviceModel> <services> <service name="RoomReservationService.RoomReservationService"> <endpoint address="" name="haha" binding="wsHttpBinding" contract="RoomReservationService.IRoomService"> <identity> <dns value="localhost" /> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost:8735/Design_Time_Addresses/RoomReservationService/aa/" /> </baseAddresses> </host> </service> </services> <behaviors> <serviceBehaviors> <behavior> <!-- 为避免泄漏元数据信息, 请在部署前将以下值设置为 false 并删除上面的元数据终结点 --> <serviceMetadata httpGetEnabled="True"/> <!-- 要接收故障异常详细信息以进行调试, 请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息--> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
自定义服务宿主(包含跟踪错误消息:在配置文件配置可以使用工具svctraceviewer.exe查看错误信息)
View Code
class Program { internal static ServiceHost myServiceHost = null; /// <summary> /// 启动服务 /// </summary> internal static void StartService() { myServiceHost = new ServiceHost(typeof(RoomReservationService)); myServiceHost.Open(); } /// <summary> /// 停止服务 /// </summary> internal static void StopService() { if (myServiceHost.State != CommunicationState.Closed) { myServiceHost.Close(); } } static void Main() { StartService(); Console.WriteLine("Server is runnin. Press return to exit"); Console.ReadLine(); StopService(); } }
宿主的配置文件
View Code
<?xml version="1.0"?> <configuration> <connectionStrings> <add name="RoomReservationsEntities" connectionString="metadata=res://*/RoomReservationModel.csdl|res://*/RoomReservationModel.ssdl|res://*/RoomReservationModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=(local)\sqlexpress;Initial Catalog=RoomReservations;Integrated Security=True;Pooling=False;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient"/> </connectionStrings> <system.diagnostics> <sources> <source name="System.ServiceModel.MessageLogging" switchValue="Verbose,ActivityTracing"> <listeners> <add type="System.Diagnostics.DefaultTraceListener" name="Default"> <filter type=""/> </add> <add name="ServiceModelMessageLoggingListener"> <filter type=""/> </add> </listeners> </source> <source name="System.ServiceModel" switchValue="Verbose,ActivityTracing" propagateActivity="true"> <listeners> <add type="System.Diagnostics.DefaultTraceListener" name="Default"> <filter type=""/> </add> <add name="ServiceModelTraceListener"> <filter type=""/> </add> </listeners> </source> </sources> <sharedListeners> <add initializeData="c:\code\wcf\roomreservation\roomreservationhost\app_messages.svclog" type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp"> <filter type=""/> </add> <add initializeData="c:\code\wcf\roomreservation\roomreservationhost\app_tracelog.svclog" type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="ServiceModelTraceListener" traceOutputOptions="Timestamp"> <filter type=""/> </add> </sharedListeners> <trace autoflush="true"/> </system.diagnostics> <system.web> <compilation debug="true"/> </system.web> <!-- When deploying the service library project, the content of the config file must be added to the host's app.config file. System.Configuration does not support config files for libraries. --> <system.serviceModel> <diagnostics> <messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true"/> <endToEndTracing propagateActivity="true" activityTracing="true" messageFlowTracing="true"/> </diagnostics> <services> <service name="Wrox.ProCSharp.WCF.RoomReservationService"> <host> <baseAddresses> <add baseAddress="http://localhost:8732/Design_Time_Addresses/RoomReservationService/aa/"/> </baseAddresses> </host> <!-- Service Endpoints --> <!-- Unless fully qualified, address is relative to base address supplied above --> <endpoint address="" binding="wsHttpBinding" contract="Wrox.ProCSharp.WCF.IRoomService"> <!-- Upon deployment, the following identity element should be removed or replaced to reflect the identity under which the deployed service runs. If removed, WCF will infer an appropriate identity automatically. --> <identity> <dns value="localhost"/> </identity> </endpoint> <!-- Metadata Endpoints --> <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. --> <!-- This endpoint does not use a secure binding and should be secured or removed before deployment --> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior> <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment --> <serviceMetadata httpGetEnabled="True"/> <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
客服端就是添加引用服务,也可以编程的方式引用服务
二、WCF的协定:数据协定;服务协定;消息协定。
数据协定的属性 DataCOntrace(Namespace可以解决版本的问题)和DataMember
View Code
[DataContract(Name = "RoomReservation", Namespace = "http://schemas.datacontract.org/2004/07/Wrox.ProCSharp.WCF", IsReference = true)] public class NewModel { [DataMemberAttribute(Name = "ID")] public int ID { get; set; } [DataMember(Name = "RoomName")] public string RoomName { get; set; } [DataMember(Name = "StartDate")] public DateTime StartDate { get; set; } [DataMember(Name = "EndDate")] public DateTime EndDate { get; set; } [DataMember(Name = "Contact")] public string Contact { get; set; } [DataMember(Name = "Event")] public string Event { get; set; } }
服务协定的属性ServiceContract和OperationContract
View Code
[ServiceContract()] public interface IRoomService { [OperationContract] bool ReserveRoom(RoomReservation roomReservation); [OperationContract] RoomReservation[] GetRoomReservations(DateTime fromDate, DateTime toDate); }
消息的协定的属性MessageContract,MessageHeader和MessageBodyMember(Order可以知道元素顺序)
View Code
[MessageContract] public class ProcessPersonRequestMessage { [MessageHeader] public int employeeId; [MessageBodyMember(Order= 0)] public Person person; } [ServiceContract] public interface IProcessPerson { [OperationContract] public ProcessPersonRequestMessage ProcessPerson(ProcessPersonRequestMessage message); } public class Person { }
三、服务的实现
实现服务的属性ServiceBehavior可以设置同步,事物,会话等问题
View Code
[ServiceBehavior] public class RoomReservationService : IRoomService { public bool ReserveRoom(RoomReservation roomReservation) { var data = new RoomReservationData(); data.ReserveRoom(roomReservation); return true; } public RoomReservation[] GetRoomReservations(DateTime fromDate, DateTime toDate) { var data = new RoomReservationData(); return data.GetReservations(fromDate, toDate); } }
1、如果接口[ServiceContract( SessionMode=SessionMode.Required)]和实现接口的类设置成[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)],那么配置文件必须配置会话状态的wsHttpBinding
View Code2、WSHttpBinding,WSDualHttpbing等支持会话就是。(P1355)
四、以编程方式创建客户端
ChannelFactory<TChannel>类
View Code
class Program { static void Main() { Console.WriteLine("wait for service..."); Console.ReadLine(); var binding = new WSHttpBinding(); var address = new EndpointAddress("http://localhost:8732/Design_Time_Addresses/StateServiceSample/Service1/"); var factory = new ChannelFactory<IStateService>(binding, address); IStateService channel = factory.CreateChannel(); channel.Init(1); Console.WriteLine(channel.GetState()); channel.SetState(2); Console.WriteLine(channel.GetState()); try { channel.SetState(-1); } catch (FaultException<StateFault> ex) { Console.WriteLine(ex.Message); StateFault detail = ex.Detail; Console.WriteLine(detail.BadState); } channel.Close(); factory.Close(); Console.ReadLine(); } }
五、错误处理
1、默认情况下WCF服务不会把错误消息发送给客服端<serviceMetadata httpGetEnabled="True"/>这样就发送了
View Code
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
2.1、可以抛出一个FaultException异常 在接口里面设置方法的FaultContract属性
View Code
[ServiceContract(SessionMode = SessionMode.Required)] public interface IStateService { [OperationContract(IsInitiating = true)] void Init(int i); [FaultContract(typeof(StateFault))] [OperationContract] void SetState(int i); [OperationContract] int GetState(); [OperationContract(IsTerminating = true)] void Close(); }
2.2 可以手动抛一个
View Code
public void SetState(int i) { if (i == -1) { FaultReasonText[] text = new FaultReasonText[2]; text[0] = new FaultReasonText("Sample Error", new CultureInfo("en")); text[1] = new FaultReasonText("Beispiel Fehler", new CultureInfo("de")); FaultReason reason = new FaultReason(text); throw new FaultException<StateFault>( new StateFault() { BadState = i }, reason); } else { this.i = i; } }
2.3客服端就可以直接try catch了
View Code
try { channel.SetState(-1); } catch (FaultException<StateFault> ex) { Console.WriteLine(ex.Message); StateFault detail = ex.Detail; Console.WriteLine(detail.BadState); }
六 、绑定(自己理解就是设置服务的url和启动服务)P1355页 预定义绑定包含WSHttpBinding等
1、编程绑定
View Code
static ServiceHost host; static void StartService() { var haseAddress = new Uri("http://localhost:8732/Design_Time_Addresses/StateServiceSample/Service1/"); host = new ServiceHost(typeof(StateService)); var binding1 = new WSHttpBinding(); host.AddServiceEndpoint(typeof(IStateService), binding1, haseAddress); host.Open(); }
2、配置文件绑定
View Code
<system.serviceModel>
<services>
<service name="Wrox.ProCSharp.WCF.StateService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8732/Design_Time_Addresses/StateServiceSample/Service1/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address ="" binding="wsHttpBinding" contract="Wrox.ProCSharp.WCF.IStateService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
七、宿主 ServiceHost这个要配置文件配置然后才代码启动
View Code
using (var sercviceHost = new ServiceHost()) { sercviceHost.Open(); Console.WriteLine(); //回车结束 sercviceHost.Close(); }
八、WAS宿主
九、预配置的宿主类
class Program { static void Main() { Uri baseAddress = new Uri("http://localhost:8732/RoomReservation"); var host = new WebServiceHost(typeof(RoomReservationService), baseAddress); host.Open(); Console.WriteLine("service running"); Console.WriteLine("Press return to exit..."); Console.ReadLine(); if (host.State == CommunicationState.Opened) host.Close(); } }
View Code
[WebGet(UriTemplate="Reservations?From={fromDate}&To={toDate}")] public RoomReservation[] GetRoomReservations(DateTime fromDate, DateTime toDate) { var data = new RoomReservationData(); return data.GetReservations(fromDate, toDate); }
十 客户端访问WSDL(服务的元数据)配置文件设置mexHttpBinding。
十一、双工通信
1、支持双工通信的绑定是wsDualHttpBinding
View Code
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client" />
</startup>
<system.serviceModel>
<services>
<service behaviorConfiguration="" name="Wrox.ProCSharp.WCF.MessageService">
<endpoint address="" binding="wsDualHttpBinding" bindingConfiguration=""
contract="Wrox.ProCSharp.WCF.IMyMessage">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/MessageService/Service1/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors />
</system.serviceModel>
</configuration>
2、服务协定由IMymessage接口定义。回调协定用服务协定定义的CallbackContract属性映射到服务协定上
View Code
public interface IMyMessageCallback { [OperationContract(IsOneWay = true)] void OnCallback(string message); } [ServiceContract(CallbackContract = typeof(IMyMessageCallback))] public interface IMyMessage { [OperationContract] void MessageToServer(string message); }
3、实现服务协定的类MessageService
View Code
public class MessageService : IMyMessage { public void MessageToServer(string message) { Console.WriteLine("message from the client: {0}", message); IMyMessageCallback callback = OperationContext.Current. GetCallbackChannel<IMyMessageCallback>(); callback.OnCallback("message from the server"); Task.Factory.StartNew(new Action<object>(TaskCallback), callback); // new Thread(ThreadCallback).Start(callback); } private void TaskCallback(object callback) { IMyMessageCallback messageCallback = callback as IMyMessageCallback; for (int i = 0; i < 10; i++) { messageCallback.OnCallback("message " + i.ToString()); Thread.Sleep(1000); } } //private void ThreadCallback(object callback) //{ // IMyMessageCallback messageCallback = callback as IMyMessageCallback; // for (int i = 0; i < 10; i++) // { // messageCallback.OnCallback("message " + i.ToString()); // Thread.Sleep(1000); // } //} }
配置文件
View Code
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service name="Wrox.ProCSharp.MessageService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8732/Design_Time_Addresses/MessageService/Service1/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address ="" binding="wsdualHttpBinding" contract="Wrox.ProCSharp.WCF.IMyMessage">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
客户端
View Code
class ClientCallback : IMyMessageCallback { public void OnCallback(string message) { Console.WriteLine("message from the server: {0}", message); } } class Program { static void Main() { Console.WriteLine("Client - wait for service"); Console.ReadLine(); var binding = new WSDualHttpBinding(); var address = new EndpointAddress("http://localhost:8732/Design_Time_Addresses/MessageService/Service1/"); var clientCallback = new ClientCallback(); var context = new InstanceContext(clientCallback); var factory = new DuplexChannelFactory<IMyMessage>(context, binding, address); IMyMessage messageChannel = factory.CreateChannel(); messageChannel.MessageToServer("From the client"); Console.WriteLine("Client - press return to exit"); Console.ReadLine(); } }
启动服务
View Code
class Program { internal static ServiceHost myServiceHost = null; internal static void StartService() { //Instantiate new ServiceHost myServiceHost = new ServiceHost(typeof(Wrox.ProCSharp.WCF.MessageService)); //Open myServiceHost myServiceHost.Open(); } internal static void StopService() { //Call StopService from your shutdown logic (i.e. dispose method) if (myServiceHost.State != CommunicationState.Closed) myServiceHost.Close(); } static void Main() { StartService(); Console.WriteLine("Service running; press return to exit"); Console.ReadLine(); StopService(); Console.WriteLine("stopped"); } }

浙公网安备 33010602011771号