您的位置:首页 > 其它

跟我一起学WCF(6)——深入解析服务契约[下篇]

2014-10-23 21:08 218 查看

一、引言

  在上一篇博文中,我们分析了如何在WCF中实现操作重载,其主要实现要点是服务端通过ServiceContract的Name属性来为操作定义一个别名来使操作名不一样,而在客户端是通过重写客户端代理类的方式来实现的。在这篇博文中将分享契约继承的实现。

二、WCF服务契约继承实现的限制

  首先,介绍下WCF中传统实现契约继承的一个方式,下面通过一个简单的WCF应用来看看不做任何修改的情况下是如何实现契约继承的。我们还是按照之前的步骤来实现下这个WCF应用程序。

步骤一:实现WCF服务

  在这里,我们定义了两个服务契约,它们之间是继承的关系的,具体的实现代码如下所示:

// 服务契约
[ServiceContract]
public interface ISimpleInstrumentation
{
[OperationContract]
string WriteEventLog();
}

// 服务契约,继承于ISimpleInstrumentation这个服务契约
[ServiceContract]
public interface ICompleteInstrumentation :ISimpleInstrumentation
{
[OperationContract]
string IncreatePerformanceCounter();
}


  上面定义了两个接口来作为服务契约,其中ICompleteInstrumentation继承ISimpleInstrumentation。这里需要注意的是:虽然ICompleteInstrumentation继承于ISimpleteInstrumentation,但是运用在ISimpleInstrumentation中的ServiceContractAttribute却不能被ICompleteInstrumentation继承,这是因为在它之上的AttributeUsage的Inherited属性设置为false,代表ServiceContractAttribute不能被派生接口继承。ServiceContractAttribute的具体定义如下所示:

[AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Interface, Inherited = false,
AllowMultiple = false)]
public sealed class ServiceContractAttribute : Attribute


  接下来实现对应的服务,具体的实现代码如下所示:

// 实现ISimpleInstrumentation契约
public class SimpleInstrumentationService : ISimpleInstrumentation
{
#region ISimpleInstrumentation members
public string WriteEventLog()
{
return "Simple Instrumentation Service is Called";
}
#endregion
}

// 实现ICompleteInstrumentation契约
public class CompleteInstrumentationService: SimpleInstrumentationService, ICompleteInstrumentation
{
public string IncreatePerformanceCounter()
{
return "Increate Performance Counter is called";
}
}


  上面中,为了代码的重用,CompleteInstrumentationService继承自SimpleInstrumentationService,这样就不需要重新定义WriteEventLog方法了。

步骤二:实现服务宿主

  定义完成服务之后,现在就来看看服务宿主的实现,这里服务宿主是一个控制台应用程序,具体实现代码与前面几章介绍的代码差不多,具体的实现代码如下所示:

// 服务宿主的实现,把WCF服务宿主在控制台程序中
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(WCFService.CompleteInstrumentationService)))
{
host.Opened += delegate
{
Console.WriteLine("Service Started");
};

// 打开通信通道
host.Open();
Console.Read();
}

}
}


  宿主程序对应的配置文件信息如下所示:

<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<!--service标签的Name属性是必须,而且必须指定为服务类型,指定格式为:命名空间.服务类名-->
<!--更多信息可以参考MSDN:http://msdn.microsoft.com/zh-cn/library/ms731303(v=vs.110).aspx-->
<service name="WCFService.CompleteInstrumentationService" behaviorConfiguration="metadataBehavior">
<endpoint address="mex" binding="mexHttpBinding" contract="WCFService.ICompleteInstrumentation" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:9003/instrumentationService/"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>


步骤三:实现客户端

  最后,就是实现我们的客户端来对服务进行访问了,这里首先以管理员权限运行宿主应用程序,即以管理员权限运行WCFServiceHostByConsoleApp.exe可执行文件。运行成功之后,你将在控制台中看到服务启动成功的消息,具体运行结果如下图所示:

// 自定义服务契约,使其保持与服务端一样的继承结果
[ServiceContract]
public interface ISimpleInstrumentation
{
[OperationContract]
string WriteEventLog();
}

[ServiceContract]
public interface ICompleteInstrumentation : ISimpleInstrumentation
{
[OperationContract]
string IncreatePerformanceCounter();
}


View Code

第二步:配置文件修改。把客户端配置文件修改为如下所示:

<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:9003/instrumentationService/mex"
binding="mexHttpBinding" contract="ClientConsoleApp.ISimpleInstrumentation"
name="ISimpleInstrumentation" />
<endpoint address="http://localhost:9003/instrumentationService/mex"
binding="mexHttpBinding" contract="ClientConsoleApp.ICompleteInstrumentation"
name="ICompleteInstrumentation" />
</client>
</system.serviceModel>
</configuration>


第三步:实现客户端代码。具体的实现代码如下所示:

class Program
{
static void Main(string[] args)
{
using (ChannelFactory<ISimpleInstrumentation> simpleChannelFactory = new ChannelFactory<ISimpleInstrumentation>("ISimpleInstrumentation"))
{
ISimpleInstrumentation simpleProxy = simpleChannelFactory.CreateChannel();
using (simpleProxy as IDisposable)
{
Console.WriteLine(simpleProxy.WriteEventLog());
}
}
using (ChannelFactory<ICompleteInstrumentation> completeChannelFactor = new ChannelFactory<ICompleteInstrumentation>("ICompleteInstrumentation"))
{
ICompleteInstrumentation completeProxy = completeChannelFactor.CreateChannel();
using (completeProxy as IDisposable)
{
Console.WriteLine(completeProxy.IncreatePerformanceCounter());
}
}

Console.Read();
}
}


  其实,上面的实现代码原理与定义两个客户端代理类是一样的,只是此时把代理类放在客户端调用代码中实现。通过上面代码可以看出,要进行通信,主要要创建与服务端的通信信道,即Channel,上面的是直接通过ChannelFactory<T>的CreateChannel方法来创建通信信道,而通过定义代理类的方式是通过ClientBase<T>的Channel属性来获得当前通信信道,其在ClientBase类本身的实现也是通过ChannelFactory.CreateChannel方法来创建信道的,再把这个创建的信道赋值给Channel属性,以供外面进行获取创建的信道。所以说这两种实现方式的原理都是一样的,并且通过自动生成的代理类也是一样的原理。

四、总结

  到这里,本篇文章分享的内容就结束了,本文主要通过自定义代理类的方式来对契约继承服务的调用。其实现思路与上一篇操作重载的实现思路是一样的,既然客户端自动生成的代码类不能满足需求,那就只能自定义来扩展了。到此,服务契约的分享也就告一段落了,后面的一篇博文继续分享WCF中数据契约。

  本人所有源码下载:WCFServiceContract2.zip
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: