WCF及双工

//WCF .Net Framework 3.5出的
//支持多种协议:http  tcp  IPC MSMQ p2p
//支持多种宿主:控制台  网站  winform  windows-service
//双工
//1 接口是契约,要有特性ServiceContract
//  方法上有特性OperationContract
//2 出参返回实体如果没有任何标记,返回所有属性,但实体必须有无参构造函数
//  如果没有无参构造函数,需要在类上加特性DataContractAttribute;属性加特性[DataMember]后才会返回

//WCF托管到控制台:
//1.配置文件中配置behavior、binding、service(address+binding+contract)
//2.ServiceHost实例Open(需要管理员权限)
//3.服务引用时 可能需要设置Windows/Temp文件夹给IIS_User的权限

//Tcp协议不能穿防火墙(需要授权),有状态

//一般WCF+WindowsService  随机启动

//WCF双工:相互通信,可以实现IM
//用tcp协议  通过回调来实现
//1 服务端契约标记需要加上回调接口  特性[ServiceContract(CallbackContract = typeof(ICallback))]
//  其中ICallback是用户自己定义的回调接口
//  方法上的[OperationContract(IsOneWay = true)]表明是相当于异步式的,请求后异步接收结果
//2 客户端调用服务时必须实现ICallback接口,ICallback只能有一个方法,两个回调的时候出错了
//  调用时把回调方法传入

//webService和WCF泛型返回值不可以

//WCF安全
//1 带上口令--请求时带上参数
//2 SoapHeader
//3 Windows 身份验证
//4 X509证书
Console.WriteLine("Hello World!");
try
{
	ServiceInit.Process();
}
catch (Exception ex)
{
	Console.WriteLine(ex.ToString());
}
Console.Read();

服务初始化&启动

using MySOA.WCF.Service;
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Text;

namespace MySOA.Project
{
    public class ServiceInit
    {
        public static void Process()
        {
            //ServiceHost  服务主机
            List<ServiceHost> hosts = new List<ServiceHost>()
            {
                new ServiceHost(typeof(MathService)),
                new ServiceHost(typeof(CalculatorService)),//双工
            };

            foreach (var host in hosts)
            {
                host.Opening += (s, e) => Console.WriteLine($"{host.GetType().Name} 准备打开");
                host.Opened += (s, e) => Console.WriteLine($"{host.GetType().Name} 已经打开");
                host.Closing += (s, e) => Console.WriteLine($"{host.GetType().Name} 准备关闭");
                host.Closed += (s, e) => Console.WriteLine($"{host.GetType().Name} 已经关闭");
                host.Open();
            }
            Console.WriteLine("输入任意字符停止服务");
            Console.ReadKey();
            foreach (var host in hosts)
            {
                host.Close();
            }
            Console.ReadKey();
        }
    }
}

契约&回调约束类

using MySOA.WCF.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace MySOA.WCF.Interface
{
    [ServiceContract]
    public interface IMathService
    {
        [OperationContract]
        int PlusInt(int x, int y);

        [OperationContract]
        int Minus(int x, int y);

        [OperationContract]
        UserWCF GetUser(int age);

        [OperationContract]
        List<UserWCF> GetUserList();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace MySOA.WCF.Interface
{
    [ServiceContract(CallbackContract = typeof(ICallback))]
    public interface ICalculatorService
    {
        [OperationContract(IsOneWay = true)]
        void PlusInt(int x, int y);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace MySOA.WCF.Interface
{
    /// <summary>
    /// 普通接口,由客户端实现
    /// </summary>
    public interface ICallback
    {
        [OperationContract(IsOneWay = true)]
        void Show(int x, int y, int rst);

        //void Show2(int x, int y, int rst);
    }
}

服务类——实现契约

using MySOA.WCF.Interface;
using MySOA.WCF.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MySOA.WCF.Service
{
    public class MathService : IMathService
    {
        public UserWCF GetUser(int age)
        {
            return new UserWCF()
            {
                Id = 1,
                Name = "小王",
                Age = 18,
                Sex = 1,
                Discription = "帅"
            };
        }

        public List<UserWCF> GetUserList()
        {
            return new List<UserWCF>()
            {
                new UserWCF()
                {
                    Id = 1,
                    Name = "小王",
                    Age = 18,
                    Sex = 1,
                    Discription = "帅"
                },
                new UserWCF()
                {
                    Id = 2,
                    Name = "小高",
                    Age = 18,
                    Sex = 0,
                    Discription = "美"
                }
            };
        }

        public int Minus(int x, int y)
        {
            return x + y;
        }

        public int PlusInt(int x, int y)
        {
            return x - y;
        }
    }
}
using MySOA.WCF.Interface;
using MySOA.WCF.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MySOA.WCF.Service
{
    public class CalculatorService : ICalculatorService
    {
        public void PlusInt(int x, int y)
        {
            int rst = x + y;
            Thread.Sleep(2000);
            ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
            callback.Show(x, y, rst);
            //callback.Show2(x, y, rst);
        }
    }
}

服务引用

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MySOA.WCFTcpDuplex.TestProject
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"双工调用开始  ThreadId:{Thread.CurrentThread.ManagedThreadId}");
            MyConsoleWCFTcpDuplex.CalculatorServiceClient clent = null;
            try
            {
                //实现回调,并在请求时把回调传入,回调结果会由不同线程接收
                InstanceContext callbackInstance = new InstanceContext(new CustomeCallback());
                clent = new MyConsoleWCFTcpDuplex.CalculatorServiceClient(callbackInstance);
                clent.PlusInt(1, 23);
                Console.ReadKey();//通道保持
                clent.Close();
                Console.WriteLine($"双工调用结束  ThreadId:{Thread.CurrentThread.ManagedThreadId}");
            }
            catch (Exception ex)
            {
                if (clent != null)
                    clent.Abort();//如果调用过程中断网,上面的步骤会出现异常,这能保证WCF被释放掉
                Console.WriteLine(ex.ToString());
            }
        }
    }
}

双工客户端需要实现服务端的回调接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MySOA.WCFTcpDuplex.TestProject
{
    public class CustomeCallback : MyConsoleWCFTcpDuplex.ICalculatorServiceCallback
    {
        public void Show(int x, int y, int rst)
        {
            Console.WriteLine($"回调:{x}+{y}={rst} ThreadId:{Thread.CurrentThread.ManagedThreadId}");
        }

        //public void Show2(int x, int y, int rst)
        //{
        //    Console.WriteLine($"回调2:{x}+{y}={rst} ThreadId:{Thread.CurrentThread.ManagedThreadId}");
        //}
    }
}

控制台寄宿时配置

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
  </startup>
  <system.serviceModel>
    <!--行为-->
    <behaviors>
      <serviceBehaviors>
        <behavior name="MathServiceBehavior">
          <!-- httpGetEnabled - bool类型的值,表示是否允许通过HTTP的get方法获取sevice的WSDL元数据 -->
          <serviceMetadata httpGetEnabled="false"/>
          <serviceDebug httpHelpPageEnabled="false"/>
          <serviceTimeouts transactionTimeout="00:10:00"/>
          <serviceThrottling maxConcurrentCalls="1000" maxConcurrentSessions="1000"  maxConcurrentInstances="1000" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <bindings>
      <!--http-->
      <basicHttpBinding>
        <binding name="httpbinding">
        </binding>
      </basicHttpBinding>
      <!--tcp-->
      <netTcpBinding>
        <binding name="tcpbinding">
          <security mode="None">
            <transport clientCredentialType="None" protectionLevel="None" />
          </security>
        </binding>
      </netTcpBinding>
    </bindings>


    <services>
      <!--<service name="MySOA.WCF.Service.MathService" behaviorConfiguration="MathServiceBehavior">
        <host>
          <baseAddresses>
            --><!-- 每种传输协议的baseAddress,用于跟使用同样传输协议Endpoint定义的相对地址组成完整的地址,
            每种传输协议只能定义一个baseAddress。HTTP的baseAddress同时是service对外发布服务说明页面的URL --><!--
            <add baseAddress="http://localhost:8009/MathService"/>
          </baseAddresses>
        </host>
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="httpbinding" contract="MySOA.WCF.Interface.IMathService">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        --><!-- 此终结点不使用安全绑定,应在部署前确保其安全或将其删除--><!--
        --><!--<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>--><!--
      </service>-->
      
      <!--tcp-->
      <service name="MySOA.WCF.Service.MathService" behaviorConfiguration="MathServiceBehavior">
        <host>
          <baseAddresses>
            <!-- 每种传输协议的baseAddress,用于跟使用同样传输协议Endpoint定义的相对地址组成完整的地址,
            每种传输协议只能定义一个baseAddress。HTTP的baseAddress同时是service对外发布服务说明页面的URL -->
            <add baseAddress="net.tcp://localhost:8010/MathService"/>
          </baseAddresses>
        </host>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
        <endpoint address="" binding="netTcpBinding" bindingConfiguration="tcpbinding" contract="MySOA.WCF.Interface.IMathService">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <!-- 此终结点不使用安全绑定,应在部署前确保其安全或将其删除-->
        <!--<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>-->
      </service>

      <!--tcp双工-->
      <service name="MySOA.WCF.Service.CalculatorService" behaviorConfiguration="MathServiceBehavior">
        <host>
          <baseAddresses>
            <!-- 每种传输协议的baseAddress,用于跟使用同样传输协议Endpoint定义的相对地址组成完整的地址,
            每种传输协议只能定义一个baseAddress。HTTP的baseAddress同时是service对外发布服务说明页面的URL -->
            <add baseAddress="net.tcp://localhost:8011/CalculatorService"/>
          </baseAddresses>
        </host>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
        <endpoint address="" binding="netTcpBinding" bindingConfiguration="tcpbinding" contract="MySOA.WCF.Interface.ICalculatorService">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <!-- 此终结点不使用安全绑定,应在部署前确保其安全或将其删除-->
        <!--<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>-->
      </service>
    </services>
  </system.serviceModel>
</configuration>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值