WCF(1)

WCF

1.WCF介绍

WCF介绍

    WCF是微软分布式应用程序开发的集大成者,它整合了.Net平台下所有的和分布式系统有关的技术,例如.Net Remoting、ASMX、WSE和MSMQ。
以通信(Communiation)范围而论,它可以跨进程、跨机器、跨子网、企业网乃至于Internet。

    WCF可以运行在ASP.NET,EXE,WPF,Windows Forms,NT Service,COM+上面。

    WCF支持的协议包括TCP,HTTP,跨进程以及自定义,安全模式则包括SAML, Kerberos,X509,用户/密码,自定义等多种标准与模式。

WCF 优势

1. 统一性:WCF是对于ASMX,.Net Remoting,Enterprise Service,WSE,MSMQ等技术的整合。
2. 互操作性:于WCF最基本的通信机制是SOAP,这就保证了系统之间的互操作性,即使是运行不同的上下文中。可以跨进程、跨机器甚至于跨平台的通信,只要支持标准的Web Service,例如J2EE应用服务器(如WebSphere,WebLogic)。应用程序可以运行在Windows操作系统下,也可以运行在其他的操作系统,如Sun Solaris,HP Unix,Linux等等。
3. 安全性:WS-Security,WS-Trust和WS-SecureConversation均被添加到SOAP消息中,以用于用户认证,数据完整性验证,数据隐私等多种安全因素。
4. 兼容性:WCF充分的考虑到了与旧有系统的兼容性。安装WCF并不会影响原有的技术如ASMX和.Net Remoting。
5. 高效开发:维护性、操作性、生产效率提升,开发环境的无缝集成

WCF 入门demo

接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfServiceDemoOne
{
    [ServiceContract]
    public interface IService1
    {
        [OperationContract(IsOneWay=true)]
        void GetData(int value);

    }

}

实现接口类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfServiceDemoOne
{
    public class Service1 : IService1
    {
        public void GetData(int value)
        {
             string.Format("You entered: {0}", value);
        }
    }
}

调用WCF,添加服务引用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ConsoleApplication.ServiceReference1;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            Service1Client client = new Service1Client();
            client.GetData(111);
            client.Close();
            Console.ReadKey();
        }
    }
}

2.WCF术语

服务(Service):服务是一个构造,它公开一个或多个终结点,其中每个终结点都公开一个或多个服务操作。

终结点(EndPoint):终结点是用来发送或接收消息(或执行这两种操作)的构造。终结点包括一个定义消息可以发送到的目的地的位置(地址)、
一个描述消息应如何发送的通信机制规范(绑定)以及对于可以在该位置发送或接收(或两者皆可)的一组消息的定义(服务协定)— 该定义还描述了可以发送何种消息。

应用程序终结点:一个终结点,由应用程序公开并对应于该应用程序实现的服务协定。
基础结构终结点:一个终结点,由基础结构公开,以便实现与服务协定无关的服务需要或提供的功能。 例如,服务可能拥有一个提供元数据信息的基础结构终结点。

地址(Adress):地址指定接收消息的位置。 地址以统一资源标识符 (URI) 的形式指定。 URI 架构部分指定用于到达该地址的传输机制,如 HTTP 和 TCP。 URI 的层次结构部分包含一个唯一的位置,其格式取决于传输机制。

绑定(Binding):绑定定义终结点与外界进行通信的方式。它由一组称为绑定元素的要素构造而成,这些元素“堆叠”在一起以形成通信基础结构。 绑定最起码应定义传输协议(如HTTP 或 TCP)和所使用的编码(如文本或二进制)。 绑定可以包含指定详细信息(例如,用于保护消息的安全机制或终结点所使用的消息模式)的绑定元素。

服务协定:服务协定将多个相关的操作联系在一起,组成单个功能单元。 协定可以定义服务级设置,如服务的命名空间、对应的回调协定以及其他此类设置。 在大多数情况下,协定是通过用您所选的编程语言创建一个接口并将 ServiceContractAttribute 属性应用于该接口来定义的。 通过实现该接口,可生成实际的服务代码。

操作协定:操作协定定义参数并返回操作的类型。 在创建定义服务协定的接口时,可以通过将 OperationContractAttribute 属性应用于协定中包含的每个方法定义来表示一个操作协定。 可以将操作建模为采用单个消息作为参数并返回单个消息,或者建模为采用一组类型作为参数并返回一个类型。 在后一种情况下,系统将确定需要为该操作交换的消息的格式。

宿主:服务必须承载于某个进程中。 “宿主”是控制服务的生存期的应用程序。 服务可以是自承载的,也可以由现有的宿主进程进行管理。

3.创建服务协定

类或接口都可以定义服务协定(但是建议使用接口,因为接口可以直接对服务协定建模)
服务协定接口具有托管接口的所有优点:
1.服务协定接口可以扩展任何数量的其他服务协定接口。
2.一个类可以通过实现服务协定接口来实现任意数量的服务协定。
3.可以通过更改接口实现来修改服务协定的实现,而让服务协定保持不变。 持不变。
4.可以通过实现旧接口和新接口来确定服务的版本。 老客户端连接到原始版本,而新客户端则可以连接到较新的版本

步骤:
1.定义服务协定
在类或接口上使用ServiceContractAttribute属性标记
2.定义服务操作
在方法上使用OperationContractAttribute属性对其进行标记
3.参数和返回值
3.1 每个操作都有一个返回值和一个参数 即使它们为void 可以使用局部方法将对对象的引用从一个对象传递到另一个对象,但与局部方法不同的是,服务操作不会传递对对象的引用, 它们传递的只是对象的副本。
3.2 这是因为参数或返回值中使用的每个类型都必须是可序列化的,换言之,该类型的对象必须能够转换为字节流, 是可序列化的。
3.3 默认情况下,基元类型是可序列化的,.NET Framework 中的很多类型都是可序列化的

4.服务协定的几种模式

基本模式:[OperationContract]  请求/响应

**操作的结果是除非客户端异步调用操作 否则客户端将停止处 理,直到收到返回消息

DEMO

namespace WcfServiceDemoOne
{
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetData(int value);
    }

}
 public class Service1 : IService1
    {

        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value); ;
        }
    }

单向模式:[OperationContract(IsOneWay=True)] 

**如果WCF 服务应用程序的客户端不必等待操作完成,并且不处理SOAP 错误,则该操作可以指定单向消息模式

DEMO 

namespace WcfServiceDemoOne
{
    [ServiceContract]
    public interface IService1
    {
        [OperationContract(IsOneWay=true)]
        void GetData(int value);
    }
}
namespace WcfServiceDemoOne
{
    public class Service1 : IService1
    {
        public void GetData(int value)
        {
             string.Format("You entered: {0}", value); ;
        }
    }
}

双向模式:[CallbackContract=typeof(I接口Callback))]]

**无论使用单向消息发送还是请求/答复消息发送方式,服务和客户端均能够独立地向对方发送消息。

DEMO

namespace WcfServiceThree
{
    [ServiceContract(Namespace = "", SessionMode = SessionMode.Required, CallbackContract = typeof(IService1CallBack))]
    public interface IService1
    {
        [OperationContract(IsOneWay=true)]
        void SendToServer(int value);

        [OperationContract(IsOneWay = true)]
        void SendToServer2(int value);
    }

    public interface IService1CallBack
    {
        [OperationContract(IsOneWay = true)]
        void SendToClient(int value);
    }
}
namespace WcfServiceThree
{
    public class Service1 : IService1
    {
        int num = 0;
        IService1CallBack callBack = null;
        public Service1()
        {
            //实例化回调的服务
            callBack = OperationContext.Current.GetCallbackChannel<IService1CallBack>();
        }
        public void SendToServer(int value)
        {
            num++;
            value = value + num;
            callBack.SendToClient(value);
        }
        public void SendToServer2(int value)
        {
            num++;
            value = value + num;
            callBack.SendToClient(value);
        }
    }
}
namespace ConsoleDemo
{
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
    public class CallBackHanle : IService1Callback //实现服务端的回调接口
    {
        public void SendToClient(int value)
        {
            Console.WriteLine(value);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            InstanceContext instance = new InstanceContext(new CallBackHanle());
            Service1Client client = new Service1Client(instance);
            client.SendToServer(1);
            client.SendToServer2(1);
            Console.Read();
            client.Close();
        }
    }
}
<services>
      <service name="WcfServiceThree.Service1" behaviorConfiguration="serviceDemo">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:1123/Service1.svc/Service1"/>
          </baseAddresses>
        </host>
        <endpoint address=""  binding="wsDualHttpBinding" contract="WcfServiceThree.IService1">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
      </service>
    </services>
<behaviors>
      <serviceBehaviors>
        <behavior name="serviceDemo">
          <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>

5.创建数据协定

数据协定:是服务协定的一部分用于描述您的服务操作交换的数据 ;是服务协定的一部分,用于描述您的服务操作交换的数据

一般使用DataContractAttribute和DataMemberAttribute属性对您的类型进行标记。

 DEMO

namespace WcfServiceUser
{
    [DataContract]
    public class User
    {
        [DataMember]
        public int ID { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Age { get; set; }
    }
}
namespace WcfServiceUser
{
    [ServiceContract]
    public interface IService1
    {

        [OperationContract]
        User GetData(ref int value);

    }
}
namespace WcfServiceUser
{
    public class Service1 : IService1
    {
        public User GetData(ref int value)
        {
            value++;
            return new User { Age=11, ID=123, Name="zhangsan"};
        }
    }
}
namespace ConsoleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Service1Client client = new Service1Client();
            int n = 111;
            User user = client.GetData(ref n);
            Console.WriteLine(user.Name);
            Console.WriteLine(n);
            client.Close();
        }
    }
}

***数据协定是可选的样式协定:除非您显式应用数据协定属性,否则不会序列化任何类型或数据成员。

***数据协定与托管代码的访问范围无关:可以对私有数据成员进行序列 并将其发送到其他位置,以便可以公开访问它们。

***WCF处理用于启用操作功能的基础SOAP消息的定义并处理数据类型到消息正文的序列化和从消息正文进行的反序列化。 数据类型一旦序列化,您就无需在设计操作时考虑基础消息交换基础结构。

***可以使用其他序列化机制。 标准ISerializable, SerializableAttribute和IXmlSerializable 机制都可用于处理数据类型到基础SOAP消息序列化,这些消息可将数据类型从一个应用程序带到另一个应用程序。

****引用参数传递

Out和Ref参数:由于out 和ref 参数都指示数据是从操作返回的,操作签名增加这2个关键字会使变更生效并返回
保留修改和方法返回值无关,即便是VOID
如果操作是单向操作,则将在运行时引发InvalidOperationException 异常

原文地址:https://www.cnblogs.com/youguess/p/13232233.html