zoukankan      html  css  js  c++  java
  • wcf学习三(手工编写wcf服务)

    wcf并不限于使用Http协议。在iis上使用wcf,就让wcf拥有了webservice一样的软肋,可以说是扼杀其特长的用法。通常我们可以利用手工服务编写的wcf服务来承载我们需求的应用

    直接给例子:

                1:建一个名为:LearingWCF的解决方案  2:在该解决方案下建立一个名为:WCFServer的控制台应用程序  然后在该控制台下面添加一个System.ServiceModel命名空间的引用。 与wcf有关的类都位于整个命名空间下。应该编写的代码如下:

    View Code
    namespace WCFServer
    {
    [ServiceContract]
    public interface IShopping
    {
    [OperationContract]
    float GetPrice(float price, int count);
    }
    public class ShoppingService:IShopping {
    public float GetPrice(float price, int count)
    {
    return price * count * 0.9f;
    }
    }
    class Program
    {
    static void Main(string[] args)
    {
    ServiceHost host = new ServiceHost(typeof(ShoppingService), new Uri("http://localhost:12345/shoppingWCF"));
    host.AddServiceEndpoint(typeof(IShopping), new BasicHttpBinding(), "");
    //ServiceHost host = new ServiceHost(typeof(ShoppingService));
    host.Open();
    Console.WriteLine("侦听服务已经在本机12345端口开启");
    Console.ReadLine();
    host.Close();
    }
    }
    }


    解释1:其中每一个功能都称之为一个"操作契约",这些,均需要显示使用相应的关键字标志在接口和方法上。即:[ServiceContract]和[OperationContract]特性,然后 我们使用一个类继承自该接口  以方便"实现"这些服务

          2:在main函数中,首先声明ServiceHost对象,他代表提供主机服务。有三个构造函数 可以跳转到msdn去了解属性和方法受保护的方法:a:ServiceHost            初始化 ServiceHost 类的新实例. b:ServiceHost(Object, Uri())  使用服务的实例及其指定的基址初始化 ServiceHost 类的新实例。公共方法 c: ServiceHost(Type, Uri())  使用服务的类型及其指定的基址初始化 ServiceHost 类的新实例。

                上面的代码中 ServiceHost host = new ServiceHost(typeof(ShoppingService), new Uri("http://localhost:12345/shoppingWCF")); 第一个参数指示了购物服务(ShoppingService)发布给用户,第二个参数指明了该服务发布在本机的12345端口,服务名为:shoppingWCF 此时依然使用的是http协议。

                                 host.AddServiceEndpoint(typeof(IShopping), new BasicHttpBinding(), "");  //添加端点 指定了哪一个服务,绑定于那个端口  第三个为空 指的是端口与主机发布的端口相同。 open 开启监听 close方法停止监听 

    很简单的服务端就这样了 下面写一个更简单的客户端 直接在改解决方案下添加一个winform项目起名为:WCFClient.界面如图:

    一样的引入System.ServiceModel 编写代码如下:

    View Code
    namespace WCFClient
    {
    [ServiceContract]
    public interface IShopping
    {
    [OperationContract]
    float GetPrice(float price, int count);
    }



    public partial class Form1 : Form
    {
    public Form1()
    {
    InitializeComponent();
    }

    private void btnRun_Click(object sender, EventArgs e)
    {
    ChannelFactory<IShopping> chFactory = new ChannelFactory<IShopping>(new BasicHttpBinding(), new EndpointAddress("http://localhost:12345/shoppingWCF"));
    IShopping wcfclient = chFactory.CreateChannel();
    float result = wcfclient.GetPrice(55.99f,20);
    MessageBox.Show(result.ToString());
    }
    }
    }

    ChannelFactory类 指定网络通讯的方式—我们称之为"绑定",以及向谁去通讯—我们称之为"端点",还有请求的服务契约 

    ChannelFactory<IShopping> chFactory = new ChannelFactory<IShopping>(new BasicHttpBinding(), new EndpointAddress("http://localhost:12345/shoppingWCF"));
    //指定绑定的为基础http绑定,端点为服务端的12345端口,而契约则是我们的IShopping接口
    在解决方案上点击右键,属性,将解决方案中的两个项目设置为一起启动 如图

    然后按下F5 就会出现效果了
    
    
    反思一下 将一个接口写两遍是不是有点怪啊  那就改写一下  如图吧:

    其中接口的方法如下 
    View Code
    using System.ServiceModel;

    namespace Contract
    {
    [ServiceContract]
    public interface IShopping
    {
    [OperationContract]
    float GetPrice(float price, int count);
    }

    }
    然后在客户端和服务端添加引用就可以了,后面针对这个问题还会继续解决的。
    
    
    //下面我们针对问题来解决 就是利用幕后英雄--配置文件 可以利用微软为我们准备了一个设计器vs2010如图

    然后选择新建服务
    浏览服务端的exe文件如图:

    然后打开下一步

    继续下一步如图选择服务约定 如图

    然后下一步就不截图了 直接写了  选择通信模式 (http的) 继续下一步 选择互操作模式 选择第一个(基本web服务互操作性) 继续下一步总结地址为:

    http://localhost:12345/shoppingWCF   然后下一步 跳转到完成 把生成的文件保存到WCFServer的跟目录下面 
    
    app.config的默认名称不要修改 里面的代码如下
    View Code
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
    <system.serviceModel>
    <services>
    <service name="WCFServer.ShoppingService">
    <endpoint address="http://localhost:12345/shoppingWCF" binding="basicHttpBinding"
    bindingConfiguration="" name="shoppingWCF" contract="Contract.IShopping" />
    </service>
    </services>
    </system.serviceModel>
    </configuration>

    由于配置用指定了端点,所以源代码就没有必要指定了,修改后的服务器代码如下
    	static void Main(string[] args)
    		{
    			//ServiceHost host = new ServiceHost(typeof(ShoppingService), new Uri("http://localhost:12345/shoppingWCF"));
    			//host.AddServiceEndpoint(typeof(IShopping), new BasicHttpBinding(), "");
    			ServiceHost host = new ServiceHost(typeof(ShoppingService));
    			host.Open();
    			Console.WriteLine("侦听服务已经在本机12345端口开启");
    			Console.ReadLine();
    			host.Close();
    		}
    执行之后效果一样,但是代码量小了,易读性提高了,以后修改只用修改配置文件的端点就可以 或者修改tcp/ip协议 无需对程序做任何修改
    //习惯之后可以直接写配置文件 网上介绍的很多 这里就不解释了 知道怎么来的 然后去写就容易多了
    既然服务端可以通过配置文件解决来实现代码的简化,并提高部署的灵活性,那么客户端肯定也可以拥有同样的功能  也就是所谓的元数据交换点,就是将 地址 绑定 契约 公布出来 需要使用 
    System.ServiceModel.Description这个命名空间
    服务端的代码改写成 
    	ServiceHost host = new ServiceHost(typeof(ShoppingService));
    //元数据交换行为
    	ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); //控制服务元数据和相关信息发布
    	behavior.HttpGetEnabled = true;
    	host.Description.Behaviors.Add(behavior);
    	host.AddServiceEndpoint(typeof(IMetadataExchange),MetadataExchangeBindings.CreateMexHttpBinding(),"mex");//后面的就一样了
    然后在利用wcf服务配置编译器就是配置如图:添加一个终结点shoppingWCFMex

    然后添加一个服务行为如图

    然后保存 生成的配置文件里面的代码就成了这样的

    View Code
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
    <system.serviceModel>
    <behaviors>
    <serviceBehaviors>
    <behavior name="mexBehavior">
    <serviceMetadata httpGetEnabled="true" />
    </behavior>
    </serviceBehaviors>
    </behaviors>

    <services>
    <service behaviorConfiguration="mexBehavior" name="WCFServer.ShoppingService">
    <endpoint address="http://localhost:12345/shoppingWCF" binding="basicHttpBinding"
    bindingConfiguration="" name="shoppingWCF" contract="Contract.IShopping" />

    <endpoint address="mex" binding="mexHttpBinding" bindingConfiguration=""
    name="shoppingWCFMex" contract="IMetadataExchange" />
    <host>
    <baseAddresses>
    <add baseAddress="http://localhost:12345/shoppingWCF" />
    </baseAddresses>
    </host>
    </service>
    </services>
    </system.serviceModel>
    </configuration>


    当然习惯了 可以直接写配置文件就可以了 此时服务的代码又变成了最短的

    代码如下

    View Code
        static void Main(string[] args)
    {
    //ServiceHost host = new ServiceHost(typeof(ShoppingService), new Uri("http://localhost:12345/shoppingWCF"));
    //host.AddServiceEndpoint(typeof(IShopping), new BasicHttpBinding(), "");//1最原始
    ServiceHost host = new ServiceHost(typeof(ShoppingService));
    //ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); //控制服务元数据和相关信息发布
    //behavior.HttpGetEnabled = true;
    //host.Description.Behaviors.Add(behavior);
    //host.AddServiceEndpoint(typeof(IMetadataExchange),MetadataExchangeBindings.CreateMexHttpBinding(),"mex"); 2代码的改变
    host.Open();
    Console.WriteLine("侦听服务已经在本机12345端口开启");
    Console.ReadLine();
    host.Close();


    最后处理客户端的事情 肯定不用添加接口的引用了 利用"代理类"来处理 也不需要管道了

    在vs2010的程序中找到visual studio Tools —— visual  studio 命令提示,运行之后输入  

    svcutil http://loacalhost:12345/shoppingWCF/mex/  -config:d:\app.config  -out:d:\code.cs 

    如图:

    然后将生成的code.cs 和app.config复制到到客户端下面(上面的app不小心写成aap)

    然后客户端的后台代码变成了

    View Code
    namespace WCFClient
    {
    //[ServiceContract]
    //public interface IShopping
    //{
    // [OperationContract]
    // float GetPrice(float price, int count);
    //}

    public partial class Form1 : Form
    {
    public Form1()
    {
    InitializeComponent();
    }

    private void btnRun_Click(object sender, EventArgs e)
    {
    //ChannelFactory<IShopping> chFactory = new ChannelFactory<IShopping>(new BasicHttpBinding(), new EndpointAddress("http://localhost:12345/shoppingWCF"));
    //IShopping wcfclient = chFactory.CreateChannel();
    //float result = wcfclient.GetPrice(55.99f,20);
    //MessageBox.Show(result.ToString());

    ShoppingClient client = new ShoppingClient();
    float result = client.GetPrice(55.99f,20);
    MessageBox.Show(result.ToString());
    }
    }
    }

    注释的就是进化前的代码

    效果就出来了  就是这样啦

    
    
    
    





     

    
    
    
    
    
  • 相关阅读:
    在EasyDarwin进行实时视频转发的两种模式
    Windows服务中读取配置文件的方法
    reactor设计模式
    用Darwin实现流媒体转发程序(附源码)
    Windows服务中读取配置文件的方法
    c# 参数 this
    基于DSS的先侦听后推送式流媒体转发
    用live555做本地视频采集转发,附源码
    Darwin在转发流过程中对推送端断开的处理问题
    基于live555的流媒体代理转发服务器
  • 原文地址:https://www.cnblogs.com/leidc/p/2433462.html
Copyright © 2011-2022 走看看