Spring.NET对WCF(Windows Communication Foundation)有很好的支持,Spring.Services程序集下封装了创建和调用WCF的方法。以往,我们使用svc文件来承载WCF;使用自动生产的代理来调用服务。这样便对产生了诸多依赖。而使用Spring.NET则会令应用程序得到良好的改善。
让我们从实例中学习今天的内容:
首先创建服务契约和其实现
public interface IWcfContract
{
[OperationContract]
string GetData( int value);
}
public class ImplementService : IWcfContract
{
public string GetData( int value)
{
return " 你输入的是: " + value;
}
}
把服务契约的实现类加入Spring.NET中管理
创建一个WCF的WCF项目,并引用Common.Logging.dll、Spring.Core.dll、Spring.Data.dll、Spring.Web.dll、Spring.Services.dll(在Spring.NET库下的3.0文件夹里)
Spring.ServiceModel.Activation.ServiceHostFactory类继承自System.ServiceModel.Activation.ServiceHostFactory,用于在BS架构中承载WCF。
建立svc文件
指定Service属性为服务契约的实现类(WcfServer)
配置web.config文件
< services >
< service name ="WcfServer" behaviorConfiguration ="WcfServerBehavior" >
<!-- Service Endpoints -->
< endpoint address ="" binding ="wsHttpBinding" contract ="IContract.IWcfContract" />
< endpoint address ="mex" binding ="mexHttpBinding" contract ="IMetadataExchange" />
</ service >
</ services >
< behaviors >
< serviceBehaviors >
< behavior name ="WcfServerBehavior" >
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->
< serviceMetadata httpGetEnabled ="true" />
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
< serviceDebug includeExceptionDetailInFaults ="false" />
</ behavior >
</ serviceBehaviors >
</ behaviors >
</ system.serviceModel >
指定Service节点的name属性为刚才配置的Spring.NET对象(WcfServer)。
在Global的Application_Start方法中实例化Spring.NET对象(Spring.Context.Support.ContextRegistry.GetContext();)
这样WEB宿主的WCF就搭建成功了。
而在winform或者控制台等程序中无法使用svc文件来承载WCF,但这一点被Spring.NET开发团队考虑到了。Spring.Services程序集下的Spring.ServiceModel.Activation.ServiceHostFactoryObject则是用于非WEB环境的WCF创建。
我们以控制台程序为例,来讲解在非WEB环境的WCF创建:
在控制台程序中创建一项Spring.NET对象的配置
< property name ="TargetName" value ="WcfServer" />
</ object >
指明TargetName属性为实现服务契约的Spring.NET对象(WcfServer)
配置app.config文件,这里为了区别WEB环境,我使用netTcpBinding的绑定方式。
< behaviors >
< serviceBehaviors >
< behavior name ="WcfServerBehavior" >
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->
< serviceMetadata httpGetEnabled ="true" />
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
< serviceDebug includeExceptionDetailInFaults ="false" />
</ behavior >
</ serviceBehaviors >
</ behaviors >
< services >
< service name ="WcfServer" behaviorConfiguration ="WcfServerBehavior" >
< endpoint binding ="netTcpBinding" contract ="IContract.IWcfContract"
bindingConfiguration ="ServerBinding"
address ="net.tcp://localhost:3286/App/Server/" />
< endpoint address ="mex" binding ="mexHttpBinding" contract ="IMetadataExchange" />
< host >
< baseAddresses >
< add baseAddress ="http://localhost:3285/App/Server/" />
</ baseAddresses >
</ host >
</ service >
</ services >
< bindings >
< netTcpBinding >
< binding name ="ServerBinding" >
< security mode ="None" >
< transport clientCredentialType ="None" />
< message clientCredentialType ="None" />
</ security >
</ binding >
</ netTcpBinding >
</ bindings >
</ system.serviceModel >
指明baseAddress是为了便于生成WCF的代理类。
最后在控制台程序的Main方法中实例化Spring.NET容器,这样一个以控制台为宿主的WCF环境便搭建成功了。
然而对于调用WCF,我们通常使用“添加服务应用”的方式来生成WCF的代理类。这样,在整个项目都使用Spring.NET框架的环境下,很难管理WCF的代理类。
为了让Spring.NET来管理WCF的代理类,我们需要配置System.ServiceModel.ChannelFactory<T>这个泛型类,再配置代理类中的factory-method属性。
至于System.ServiceModel.ChannelFactory<T>类,是用来创建和管理客户端用来将消息发送到服务终结点的通道,这里不细讲,请查看MSDN。
< object id ="WebChannelFactory"
type ="System.ServiceModel.ChannelFactory<IContract.IWcfContract>, System.ServiceModel" >
< constructor-arg name ="endpointConfigurationName" value ="WSHttpBinding_IContract" />
</ object >
<!-- 调用web宿主的代理类 -->
< object id ="WebProxy"
type ="IContract.IWcfContract, IContract"
factory-object ="WebChannelFactory"
factory-method ="CreateChannel" singleton ="false" />
<!-- 创建app宿主的信道工厂 -->
< object id ="AppChannelFactory"
type ="System.ServiceModel.ChannelFactory<IContract.IWcfContract>, System.ServiceModel" >
< constructor-arg name ="endpointConfigurationName" value ="NetTcpBinding_IContract" />
</ object >
<!-- 调用app宿主的代理类 -->
< object id ="AppProxy"
type ="IContract.IWcfContract, IContract"
factory-object ="AppChannelFactory"
factory-method ="CreateChannel" />
注意的是System.ServiceModel.ChannelFactory<T>的构造函数中需要指明endpointConfigurationName属性为endpoint的name属性
< endpoint address ="http://localhost:3287/WebHost.svc" binding ="wsHttpBinding"
bindingConfiguration ="WSHttpBinding_IContract" contract ="IContract.IWcfContract"
name ="WSHttpBinding_IContract" />
< endpoint address ="net.tcp://localhost:3286/App/Server/" binding ="netTcpBinding"
bindingConfiguration ="NetTcpBinding_IContract" contract ="IContract.IWcfContract"
name ="NetTcpBinding_IContract" />
</ client >
客户端中调用WCF代理类
{
static void Main( string [] args)
{
IApplicationContext cxt = ContextRegistry.GetContext();
// 调用web宿主
IWcfContract webProxy = (IWcfContract)cxt.GetObject( " WebProxy " );
Console.WriteLine(webProxy.GetData( 1 ));
// 调用app宿主
IWcfContract appProxy = (IWcfContract)cxt.GetObject( " AppProxy " );
Console.WriteLine(appProxy.GetData( 2 ));
Console.ReadLine();
}
}
程序运行的效果: