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());
}
}
}

注释的就是进化前的代码

效果就出来了  就是这样啦

 








 


 

 

 

posted @ 2012-04-06 14:25  leidc  阅读(619)  评论(0编辑  收藏  举报