zoukankan      html  css  js  c++  java
  • C# WCF服务入门

    之前在公司用的服务端是wcf写的,但是没有深入研究,最近找工作,面试的时候好多人看到这个总提问,这里做个复习

    就用微软官方上的例子,搭一个简单的wcf服务,分6步

    1 定义服务协定也就是契约,其实就是定义一个服务接口,这玩意后边是公开客户端用的,然后也告诉后边承载程序应该如何加载服务

       主要涉及两个特性:一个是ServiceContract(接口的特性,定义这个是服务契约,里边又一些设置参数可以设置一下),OperationContract设置接口的方法的,如果不设置,方法就不会呗公开

      这里是直接新建的wcf的服务程序,vs自动给生成了一个接口,就直接在这个里边添加了几个计算的接口函数了

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.Text;
    
    namespace GettingStartedLib
    {
    
        // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。
        //协定
        [ServiceContract(//CallbackContract =typeof(ICallBack),//双工时的返回协定
            ConfigurationName = "Calculator",//配置文件重的服务名
            Name = "ICalculator",//webservice描述文件重的portType名
            Namespace ="http://SampleWcfTest",//webservice描述文件重的portType命名空间
            ProtectionLevel =System.Net.Security.ProtectionLevel.EncryptAndSign,//保护等级
            SessionMode =SessionMode.Allowed)]//设置会话的支持模式
        public interface ICalculator
        {
    
            [OperationContract]
            string GetData(int value);
    
            [OperationContract]
            CompositeType GetDataUsingDataContract(CompositeType composite);
            //定义方法的操作,带了该特性才会被公布
            [OperationContract]
            double Add(double n1, double n2);
            [OperationContract]
            double Subtract(double n1, double n2);
            [OperationContract]
            double Multiply(double n1, double n2);
            [OperationContract]
            double Divide(double n1, double n2);
    
            // TODO: 在此添加您的服务操作
        }
        public interface ICallBack
        {
            [OperationContract(IsOneWay = true)]
            void Reply(string responseToGreeting);
        }
    
        // 使用下面示例中说明的数据约定将复合类型添加到服务操作。
        [DataContract]
        public class CompositeType
        {
            bool boolValue = true;
            string stringValue = "Hello ";
    
            [DataMember]
            public bool BoolValue
            {
                get { return boolValue; }
                set { boolValue = value; }
            }
    
            [DataMember]
            public string StringValue
            {
                get { return stringValue; }
                set { stringValue = value; }
            }
        }
    }

    2 实现上边的接口,vs自动生成了svc文件和对应的svc.cs文件,直接双击就是对应的实现类了,吧接口实现就好了,这个svc文件右键用文本编辑器打开可以进行编辑,如果后边用IIS加载的时候需要修改里边的东西

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.Text;
    
    namespace GettingStartedLib
    {
        // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。
        // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 Service1.svc 或 Service1.svc.cs,然后开始调试。
        public class Calculator : ICalculator
        {
            public string GetData(int value)
            {
                return string.Format("You entered: {0}", value);
            }
    
            public CompositeType GetDataUsingDataContract(CompositeType composite)
            {
                if (composite == null)
                {
                    throw new ArgumentNullException("composite");
                }
                if (composite.BoolValue)
                {
                    composite.StringValue += "Suffix";
                }
                return composite;
            }
            public double Add(double n1, double n2)
            {
                double result = n1 + n2;
                Console.WriteLine("Received Add({0},{1})", n1, n2);
                // Code added to write output to the console window.
                Console.WriteLine("Return: {0}", result);
                return result;
            }
    
            public double Subtract(double n1, double n2)
            {
                double result = n1 - n2;
                Console.WriteLine("Received Subtract({0},{1})", n1, n2);
                Console.WriteLine("Return: {0}", result);
                return result;
            }
    
            public double Multiply(double n1, double n2)
            {
                double result = n1 * n2;
                Console.WriteLine("Received Multiply({0},{1})", n1, n2);
                Console.WriteLine("Return: {0}", result);
                return result;
            }
    
            public double Divide(double n1, double n2)
            {
                double result = n1 / n2;
                Console.WriteLine("Received Divide({0},{1})", n1, n2);
                Console.WriteLine("Return: {0}", result);
                return result;
            }
        }
    }

    3 承载服务,承载服务有几种方式,同时又设计到协议的绑定问题,

      绑定分类:BasicHttpBinding  最基础的http绑定,
            NetTcpbingding  TCP的  

            NetNamePipeBinding  IPC,也就是进程间通信,没用过。。

            WSHttpBinding  这个是特殊的http/Https协议 加了其他东西的

            NetMsmqBindiing,这个是消息队列,我没用过,这玩意好像需要额外装微软的消息队列才可以用

      这里我基本就用wshttpbinding来实现,

      承载方式:1)用控制台程序,直接用servicehost来承载服务,自己构造终结点:

                //服务的地址
                Uri baseAddress = new Uri("http://localhost:8000/GettingStarted/");
                //承载服务的宿主
                ServiceHost selfHost = new ServiceHost(typeof(Calculator), baseAddress);
    
                try
                {
                    selfHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "Calculator");
                    ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                    smb.HttpGetEnabled = true;
                    selfHost.Description.Behaviors.Add(smb);
                    selfHost.Open();
                    Console.WriteLine("The service is ready.");
                    Console.WriteLine("input<exit> to terminate service.");
                    Console.WriteLine();
                    while ("exit" == Console.ReadLine())
                    {
                        selfHost.Close();
                    }
                }
                catch (CommunicationException ex)
                {
                    Console.WriteLine(ex.Message);
                    selfHost.Abort();
                    Console.ReadLine();
                }

        2) 用IIS承载,这里又两种方式,通过internet的方式 这个可以直接在vs中调试的,选中svc文件点调试会弹出一个wcf的客户端测试程序,可以直接进行测试,但是这个客户端不能测试异步,只能测同步

        这中方式主要是需要配置一个web.config文件,部署的话,直接在IIS添加网站服务程序,把生成的DLL和web.config放在一个目录下应该跟这个调试是一样的(这种方式IIS5 6 只支持HTTP)

        还可以通过WAS(进程激活服务,支持的协议比上边多,这个就没有深入研究了···)

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
    
      <appSettings>
        <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
      </appSettings>
      <system.web>
        <compilation debug="true" targetFramework="4.5.2" />
        <httpRuntime targetFramework="4.5.2"/>
      </system.web>
      <system.serviceModel>
        <services>
          <service name="GettingStartedLib.Calculator" behaviorConfiguration="MyServiceTypeBehaviors" >
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:8001/"/>
              </baseAddresses>
            </host>
            <endpoint address="CalculatorService" binding="wsHttpBinding" contract="Calculator">
            </endpoint>
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="MyServiceTypeBehaviors" >
              <!-- 将下列元素添加到服务行为配置中。 -->
              <serviceMetadata httpGetEnabled="true" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
      <system.webServer>
        <!--<modules runAllManagedModulesForAllRequests="true"/>-->
        <!--
            若要在调试过程中浏览 Web 应用程序根目录,请将下面的值设置为 True。
            在部署之前将该值设置为 False 可避免泄露 Web 应用程序文件夹信息。
          -->
        <directoryBrowse enabled="true"/>
      </system.webServer>
    
    </configuration>

      3)通过windows服务程序承载,这个内部起始也是servicehost来实现,只不过是挂在windows服务程序上,需要自己实现一个windows服务,也就是继承servicebase类,重写onstart,在onstart中用servicehost加载服务,在stop中停止服务,同时需要配置文件就是程序的配置文件app.config记得生成到目录下,配置终结点。服务类生成的程序需要安装,还需要继承install实现一个安装类,把生成的服务程序安装到windows系统服务去,然后就可以在服务中启动服务,

    这个安装是在管理员权限下进入对应的.netframework目录下运行installutil path(程序目录) 这里用的是4.5 ,就是v4.0。。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using GettingStartedLib;
    using System.ServiceModel.Description;
    using System.ServiceModel;
    using System.ServiceProcess;
    using System.Configuration.Install;
    using System.ComponentModel;
    
    namespace WcfConsole
    {
        public class serviceCalss : ServiceBase
        {
            public ServiceHost serviceHost = null;
            public serviceCalss()
            {
                ServiceName = "WCFWindowsServiceSample";
    
            }
            protected override void OnStart(string[] args)
            {
                if (serviceHost != null)
                {
                    serviceHost.Close();
                }
                serviceHost = new ServiceHost(typeof(Calculator));
    
                serviceHost.Open();
            }
    
            protected override void OnStop()
            {
                if (serviceHost != null)
                {
                    serviceHost.Close();
                    serviceHost = null;
                }
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
    
                ServiceBase.Run(new serviceCalss());
    
                //服务的地址
                Uri baseAddress = new Uri("http://localhost:8000/GettingStarted/");
                //承载服务的宿主
                ServiceHost selfHost = new ServiceHost(typeof(Calculator), baseAddress);
    
                //try
                //{
                //    selfHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "Calculator");
                //    ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                //    smb.HttpGetEnabled = true;
                //    selfHost.Description.Behaviors.Add(smb);
                //    selfHost.Open();
                //    Console.WriteLine("The service is ready.");
                //    Console.WriteLine("input<exit> to terminate service.");
                //    Console.WriteLine();
                //    while ("exit" == Console.ReadLine())
                //    {
                //        selfHost.Close();
                //    }
                //}
                //catch (CommunicationException ex)
                //{
                //    Console.WriteLine(ex.Message);
                //    selfHost.Abort();
                //    Console.ReadLine();
                //}
            }
        }
    
        [RunInstaller(true)]
        public class ProjectInstaller : Installer
        {
            private ServiceProcessInstaller process;
            private ServiceInstaller service;
    
            public ProjectInstaller()
            {
                process = new ServiceProcessInstaller();
                process.Account = ServiceAccount.LocalSystem;
                service = new ServiceInstaller();
                service.ServiceName = "WCFWindowsServiceSample";
                Installers.Add(process);
                Installers.Add(service);
            }
        }
    }

    对应的配置文件

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <startup> 
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
        </startup>
      <system.serviceModel>
        <services>
          <!-- This section is optional with the new configuration model
               introduced in .NET Framework 4. -->
          <service name="GettingStartedLib.Calculator"
                   behaviorConfiguration="CalculatorServiceBehavior">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:8000/"/>
              </baseAddresses>
            </host>
            <endpoint address=""
                      binding="wsHttpBinding"
                      contract="Calculator" />
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="CalculatorServiceBehavior">
              <serviceMetadata httpGetEnabled="true"/>
              <serviceDebug includeExceptionDetailInFaults="False"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>

    4 服务端承载好了,就可以用客户端调用服务了,又两种方式

      客户端直接引用已经运行的服务,vs会自动生成一个对应的client类,里边又设置好的服务路径和接口之类的,也可以自己指定路径,只用他的函数,记得close

               // CalculatorClient client = new CalculatorClient();
                var client = myChannelFactory.CreateChannel();
    
    
                double value1 = 100.00D;
                double value2 = 15.99D;
                double result = client.Add(value1, value2);
                Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

      也可以用ChannelFactory<TChannel>类来构造一个client,这种模式是引用服务的契约接口,

         var myBinding = new WSHttpBinding();
                EndpointAddress myEndpoint = new EndpointAddress("http://localhost:8000/GettingStarted/");
                //EndpointAddress myEndpoint = new EndpointAddress("http://localhost:8000/"); 
                ChannelFactory<ICalculator> myChannelFactory = new ChannelFactory<ICalculator>(myBinding, myEndpoint);

      这里边都可以用配置文件来设置终结点,也就是绑定类型和地址,配置方式与服务端类似

    5,6就是配置和调用,这里就不说了

    这里只是简单的wcf实例,

    实际还有内容没有涉及:

    1 不同的绑定类型,怎么选择,网上有个图是判断什么情况选择对应的绑定类型,其实就是选择协议

    2 加密,因为之间的程序用的是basichttpbingding就是就是基本的http绑定,客户端没用引用服务端,服务端以web服务的形式公开服务,客户端直接以http请求的形式来与服务端通信,这样客户端cs和bs可以公用一个服务端,但是没有加密,传输的内容是完全公开的··讲道理web服务这玩意本来就是发过去给人看的·公开应该也没啥好像····,面试的时候问到这个问题直接懵逼了···这里暂时没写 ··这玩意好像挺麻烦的···

    3 这里在4.5的环境下编写的,服务公开以后会自动生成对应的异步执行方法,与之前的方式不同,之前是老式的beginxxx的异步方式,返回一个Iasyncresult的结果,这里是4.5的async/await的形式来执行异步操作

    4 wcf服务是可以兼容asp.net ,也可以返回json格式的对象··这个可以通过设置方法的操作特性可以设置

    5 wcf服务支持双工,这个就很流弊了,不过讲道理tcp这种本身就支持双工,没具体研究

    6 在双工模式下支持回调,这个意思好像是客户端请求完成再出发一个回调服务么··· 没研究···

    。。。。。。

  • 相关阅读:
    电脑一族,打电脑时候的健康的坐姿
    根据时间戳,增量同步数据的解决办法
    写在前面
    《T-GCN: A Temporal Graph Convolutional Network for Traffic Prediction》 论文解读
    关于Graph Convolutional Network的初步理解
    图形学_opengl纹理映射
    推荐算法_CIKM-2019-AnalytiCup 冠军源码解读_2
    推荐算法_CIKM-2019-AnalytiCup 冠军源码解读
    leetcode_雇佣 K 名工人的最低成本(优先级队列,堆排序)
    图形学_Bezier曲线
  • 原文地址:https://www.cnblogs.com/onegarden/p/7134426.html
Copyright © 2011-2022 走看看