简介
本文介绍了基于内容的路由使用WCF。基于内容的路由,实现SOA的四个原则,各国可以共享架构和合约,而不是类之一。在面向消息的应用中,客户的需求只操心的消息,它需要提交和一个服务将其路由,即照顾,提交相应的下游WCF服务的消息。因此,到外面的世界,只有路由服务和暴露的合同。这减轻了点需要点通信,使得WCF的行为或像服务总线。背景
背景知识的C#4.0中,WCF 4.0,和ASP.NET需要正确理解的文章。 SOA和ESB的一项基本理论的理解是可取的。使用代码
以下步骤来完成,以实现基于内容的路由使用WCF 4.0:
创建一个空白的Visual Studio 2010的解决方案,名为ContentBasedRouting。添加一个类库项目,叫做CustomerContract。到ICustomer.cs Class1.cs文件重新命名。把在它的下面的代码:using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
using System.Runtime.Serialization;
namespace CustomerContract
{
[ServiceContract]
public interface ICustomer
{
[OperationContract]
string GetCustomerDetails(Customer cust);
}
[DataContract]
public class Customer
{
[DataMember]
public string CustomerID { get; set; }
[DataMember]
public string CustomerName { get; set; }
[DataMember]
public string CustomerCreditRating { get; set; }
}
}
在这里,我们声明的OperationContract的一个的ServiceContract接口ICustomer GetCustomerDetails一个Customer对象作为参数。我们有三个自动属性数据成员声明一个DataContract,和一流的客户。下一步,我们将引用添加到System.ServiceModel.dll,System.ServiceModel.Description.dll,System.Runtime.Serialization.dll和System.ServiceModel.Web.dll。所谓PremiumCustomerService到解决方案中添加一个WCF服务应用程序。还可以创建在IIS 7.0中的虚拟目录指向PremiumCustomerService文件夹的物理路径。svc文件重新命名,以PremiumCustomerService.svc。它应该包含以下代码:{C}转到代码隐藏文件中添加以下代码:using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace PremiumCustomerService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu
// to change the class name "Service1"
// in code, svc and config file together.
public class PremiumCustomerService : CustomerContract.ICustomer
{
public string GetCustomerDetails(CustomerContract.Customer cust)
{
return "Customer ID = " + cust.CustomerID +
" Premium CustomerName = " +
cust.CustomerName + " CustomerCreditRating = " +
cust.CustomerCreditRating;
}
}
}
在这里,我们添加一个类PremiumCustomerService它实现了接口ICustomer,随后实施的方法GetCustomerDetails()。下一步,web.config文件进行修改。下面的应该是web.config文件的内容:<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_ICustomer" portSharingEnabled="true">
<security mode="None" />
</binding>
</netTcpBinding>
<basicHttpBinding>
<binding name="BasicHttpBinding_ICustomer">
<security mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="PremiumCustomerService">
<endpoint address="PremiumCustomerService.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ICustomer"
contract="CustomerContract.ICustomer"/>
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/PremiumCustomerService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below
to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
在这里,我们有PremiumCustomerService定义basicHttpBinding的。现在服务已准备就绪。此时,编译并生成解决方案。现在,我们可以浏览从IIS管理服务和看到的URL http://localhost/PremiumCustomerService/PremiumCustomerService.svc。现在添加另一个WCF服务应用程序名为OrdinaryCustomerService的解决方案。重命名OrdinaryCustomerService.svc。svc文件。该文件的内容应该是以下几点:
修改代码隐藏包含以下代码:<%@ ServiceHost Language="C#" Debug="true"
Service="OrdinaryCustomerService.OrdinaryCustomerService"
CodeBehind="OrdinaryCustomerService.svc.cs" %>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace OrdinaryCustomerService
{
// NOTE: You can use the "Rename" command on the "Refactor"
// menu to change the class name "Service1"
// in code, svc and config file together.
public class OrdinaryCustomerService : CustomerContract.ICustomer
{
public string GetCustomerDetails(CustomerContract.Customer cust)
{
return "Customer ID = " + cust.CustomerID +
" Ordinary CustomerName = " +
cust.CustomerName + " CustomerCreditRating = " +
cust.CustomerCreditRating;
}
}
}
在这里,我们添加了一个类叫做OrdinaryCustomerService实现ICustomer接口,因此GetCustomerDetails()方法。其次,应修改相应的web.config文件包含以下内容:<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_ICustomer" portSharingEnabled="true">
<security mode="None" />
</binding>
</netTcpBinding>
<basicHttpBinding>
<binding name="BasicHttpBinding_ICustomer">
<security mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="OrdinaryCustomerService">
<endpoint address="OrdinaryCustomerService.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ICustomer"
contract="CustomerContract.ICustomer"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/OrdinaryCustomerService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below
to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
我们已经完成了另一个所谓OrdinaryCustomerService的服务。此时,编译和重新构建解决方案。在IIS管理器中,我们可以浏览服务地看到,网址是http://localhost/OrdinaryCustomerService/OrdinaryCustomerService.svc。添加另一个WCF服务应用程序称为客户服务解决方案。现在,这是我们将定义我们的路由服务,过滤器,和XPath表达式。添加System.ServiceModel.Routing.dll参考。CustomerService.svc的内容应该有以下几点:<%@ ServiceHost Language="C#" Debug="true"
Service="System.ServiceModel.Routing.RoutingService,System.ServiceModel.Routing,
version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
在这里,我们正在使用的服务System.ServiceModel.Routing.RoutingService类。这个类是在System.ServiceModel.Routing.dll大会预先确定的。我们将编译和重新构建解决方案。现在,我们目前最重要的一点,即路由服务的web.config文件。这里我们定义一个filterTable服务行为,并添加过滤器和路由元素的XPath表达式。服务,是指根据web.config的客户端部分。 web.config中的内容应如下所示:<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_ICustomer" portSharingEnabled="true">
<security mode="None" />
</binding>
</netTcpBinding>
<basicHttpBinding>
<binding name="BasicHttpBinding_ICustomer">
<security mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint
address="http://localhost/PremiumCustomerService/PremiumCustomerService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICustomer"
contract="*" name="CustomerServiceLibrary_PremiumCustomerService"/>
<endpoint
address="http://localhost/OrdinaryCustomerService/OrdinaryCustomerService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICustomer"
contract="*" name="CustomerServiceLibrary_OrdinaryCustomerService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</client>
<services>
<service behaviorConfiguration="RoutingServiceBehavior"
name="System.ServiceModel.Routing.RoutingService">
<host>
<baseAddresses>
<add baseAddress="http://localhost/CustomerService/"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ICustomer"
contract="System.ServiceModel.Routing.IRequestReplyRouter"
name="RoutingServiceEndpoint">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="RoutingServiceBehavior">
<!-- To avoid disclosing metadata information, set the value below
to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
<routing filterTableName="routingRules" routeOnHeadersOnly="False"/>
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<routing>
<namespaceTable>
<add prefix="cc"
namespace="http://schemas.datacontract.org/2004/07/CustomerContract" />
</namespaceTable>
<filters>
<filter name="PremiumCustomerFilter" filterType="XPath"
filterData="//cc:CustomerCreditRating = 'Good'"/>
<filter name="OrdinaryCustomerFilter"
filterType="XPath" filterData="//cc:CustomerCreditRating = 'Bad'"/>
</filters>
<filterTables>
<filterTable name="routingRules">
<add filterName="PremiumCustomerFilter"
endpointName="CustomerServiceLibrary_PremiumCustomerService"
priority="0"/>
<add filterName="OrdinaryCustomerFilter"
endpointName="CustomerServiceLibrary_OrdinaryCustomerService"
priority="0"/>
</filterTable>
</filterTables>
<backupLists>
<backupList name="CustomerBackupList">
<add endpointName="CustomerServiceLibrary_OrdinaryCustomerService"/>
</backupList>
</backupLists>
</routing>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
在这里,我们看到,我们已经实施了路由,使用过滤器表,过滤器和XPath表达式。过滤器表实施该过滤器使用XPath表达式评估相应的端点的路由规则。 CustomerCreditRating Customer类的公共财产的内容是用来判断该消息随后将提交下游服务的端点。现在我们可以测试服务在IIS管理器中看到的网址是http://localhost/CustomerService/CustomerService.svc。接下来,我们添加Windows窗体应用程序,所谓ProtocolBridgingClient的解决方案,并添加服务引用相应的路由服务:http://localhost/CustomerService/CustomerService.svc。我们还添加了一个System.ServiceModel.dll参考。窗体的代码隐藏文件ProtocolBridgingForm.cs的,应当具备下列代码:using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace ProtocolBridgingClient
{
public partial class ProtocolBridgingForm : Form
{
public ProtocolBridgingForm()
{
InitializeComponent();
}
private void ProtocolBridgingForm_Load(object sender, EventArgs e)
{
try
{
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress(
"http://localhost/CustomerService/CustomerService.svc");
CustomerContract.ICustomer proxy =
ChannelFactory<CustomerContract.ICustomer>.CreateChannel(
binding, address);
CustomerContract.Customer cust1 =
new CustomerContract.Customer { CustomerID = "ar0045855",
CustomerName = "Ambar Ray", CustomerCreditRating = "Good" };
CustomerContract.Customer cust2 =
new CustomerContract.Customer { CustomerID = "am0046067",
CustomerName = "Abhijit Mahato", CustomerCreditRating = "Bad" };
string res1 = proxy.GetCustomerDetails(cust1);
string res2 = proxy.GetCustomerDetails(cust2);
txtCustomer.Text = res1 + "\n" + res2;
}
catch (Exception ex)
{
txtCustomer.Text = (ex.InnerException != null) ?
ex.InnerException.Message + "\t" + ex.Message : ex.Message;
}
}
private void ProtocolBridgingForm_FormClosed(object sender,
FormClosedEventArgs e)
{
GC.Collect();
}
}
}
在窗体的Load事件中,我们首先创建一个basicHttpBinding的对象,然后一个EndpointAddress对象指定的路由服务的URL。然后,我们使用ChannelFactory.CreateChannel()方法创建代理对象。我们创造的客户对象,一个'好'CustomerCreditRating和另一个"坏"CustomerCreditRating的,如前终于得到路由的优质客户服务,后者被路由到普通客户服务。然后,我们调用GetCustomerDetails方法,收集丰富的文本框的输出。兴趣点
这可能是创建一个ESB(企业服务总线)使用WCF的基础。每个架构/合同和相应的下游服务,在各自的架构/合同,我们可以有一个路由器服务。这样,刚刚提交的消息路由到适当的服务,可以帮助确定消息的"行程",在下游系统根据消息的内容。使用现成的开源代码,可以实现消息的映射。因此,具有路由与转化能力,可以创建一个轻量级ESB。