使用 SELECT 语句和 WCF 服务模型轮询 Oracle 电子商务套件
可以通过使用 SELECT 语句连续轮询 Oracle 电子商务套件中的接口表、接口视图、表和视图,将 Oracle 电子商务适配器配置为接收定期的数据更改消息。 可以将 SELECT 语句指定为轮询语句,适配器会定期执行该语句来轮询 Oracle 电子商务套件。 还可以指定执行轮询语句后适配器执行的投票后 PL/SQL 代码块。
若要启用轮询,必须指定某些绑定属性,如本主题中所述。 有关适配器如何支持轮询的详细信息,请参阅 支持使用轮询的入站调用。
使用 Oracle E-Business Suite 适配器绑定属性配置轮询操作
下表汇总了用于配置适配器以接收数据更改消息的 Oracle 电子商务适配器绑定属性。 在运行轮询应用程序时,必须指定这些绑定属性。
Binding 属性 | 说明 |
---|---|
InboundOperationType | 指定是要执行 轮询 还是 通知 入站操作。 默认值为 轮询。 |
PolledDataAvailableStatement | 指定适配器执行的 SQL 语句,以确定是否有任何数据可用于轮询。 仅当记录可用时,才会执行为 PollingInput 绑定属性指定的 SELECT 语句。 |
PollingInterval | 指定 Oracle 电子商务适配器执行为 PolledDataAvailableStatement 绑定属性指定的语句的时间间隔(以秒为单位)。 默认为 30 秒。 轮询间隔确定连续轮询之间的时间间隔。 如果在指定的时间间隔内执行语句,适配器将在此间隔内休眠剩余时间。 |
PollingInput | 指定轮询语句。 若要使用 SELECT 语句轮询,必须为此绑定属性指定 SELECT 语句。 默认值为 NULL。 必须指定 PollingInput 绑定属性的值才能启用轮询。 仅当有可供轮询的数据(由 PolledDataAvailableStatement 绑定属性确定)时,才会执行轮询语句。 |
PollingAction | 指定轮询操作的操作。 可以使用添加适配器服务引用 Visual Studio 插件从为操作生成的服务接口确定轮询操作。 |
PostPollStatement | 指定在执行 PollingInput 绑定属性指定的语句后执行的语句块。 |
PollWhileDataFound | 指定 Oracle E-Business 适配器是否忽略轮询间隔并持续执行轮询语句(如果数据在要轮询的表中可用)。 如果表中没有可用的数据,适配器将还原为按指定的轮询间隔执行轮询语句。 默认值为 false。 |
有关这些属性的更完整说明,请参阅 阅读有关 BizTalk Adapter for Oracle E-Business Suite 绑定属性的信息。 有关如何使用 Oracle 电子商务适配器轮询 Oracle 数据库的完整说明,请进一步阅读。
本主题如何演示轮询
在本主题中,为了演示 Oracle 电子商务适配器如何支持使用 SELECT 语句接收数据更改消息,请在 Application Object Library 应用程序中轮询 MS_SAMPLE_EMPLOYEE 接口表。 运行示例随附的 create_apps_artifacts.sql 脚本以在 Oracle 电子商务套件中创建这些对象时,会创建此表。
为了演示轮询操作,我们执行以下操作:
为 PolledDataAvailableStatement 绑定属性指定 SELECT 语句,以确定 (MS_SAMPLE_EMPLOYEE) 轮询的接口表具有任何数据的位置。 在此示例中,可以将此绑定属性设置为:
SELECT COUNT (*) FROM MS_SAMPLE_EMPLOYEE
这可确保适配器仅在MS_SAMPLE_EMPLOYEE接口表具有一些记录时执行轮询语句。
为 PollingInput 绑定属性指定 SELECT 语句。 此语句检索MS_SAMPLE_EMPLOYEE接口表中的所有行。 在此示例中,可以将此绑定属性设置为:
SELECT * FROM MS_SAMPLE_EMPLOYEE FOR UPDATE
注意
有关 SELECT 语句中使用的 FOR UPDATE 子句的信息,请参阅 从 Oracle 电子商务套件接收基于轮询的数据更改消息。
将 DELETE 语句指定为 PostPollStatement 绑定属性的一部分。 此语句将删除MS_SAMPLE_EMPLOYEE接口表中的所有数据。 在此示例中,可以将此绑定属性设置为:
DELETE FROM MS_SAMPLE_EMPLOYEE
发生这种情况后,下次执行为 PollingInput 指定的语句时,它将不会提取任何数据。
在将更多数据添加到MS_SAMPLE_EMPLOYEE接口表之前,不会收到任何轮询消息,因此必须使用新记录重新填充MS_SAMPLE_EMPLOYEE接口表。 为此,可以运行示例随附的 insert_apps_data.sql 脚本。 运行此脚本后,下一个轮询操作将提取插入到表中的新记录。
在 WCF 服务模型中配置轮询
若要使用 Oracle 电子商务适配器和 WCF 服务模型轮询接口表,必须:
为MS_SAMPLE_EMPLOYEE接口表上的 轮询 操作生成 WCF 服务协定 (接口) 。 为此,可以使用添加适配器服务引用插件。
从此接口实现 WCF 服务。
使用服务主机 (System.ServiceModel.ServiceHost) 托管此 WCF 服务。
关于本主题中使用的示例
本主题中的示例轮询MS_SAMPLE_EMPLOYEE接口表。 示例提供了用于生成表的脚本。 有关示例的详细信息,请参阅 Oracle EBS 适配器的示例。 基于本主题 的示例 SelectPolling_ServiceModel 也随 Oracle 电子商务适配器示例一起提供。
WCF 服务协定和类
可以使用添加适配器服务引用插件创建 WCF 服务协定, (接口) 和 轮询 操作的支持类。 有关生成 WCF 服务协定的详细信息,请参阅 为 Oracle 电子商务套件解决方案项目生成 WCF 客户端或 WCF 服务协定。
WCF 服务协定 (接口)
以下代码显示 wcf 服务协定 (接口) 针对MS_SAMPLE_EMPLOYEE接口表的 轮询 操作生成的接口。
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://schemas.microsoft.com/OracleEBS/", ConfigurationName="InterfaceTables_FND_APPS_MS_SAMPLE_EMPLOYEE")]
public interface InterfaceTables_FND_APPS_MS_SAMPLE_EMPLOYEE {
// CODEGEN: Generating message contract since the wrapper namespace (https://schemas.microsoft.com/OracleEBS/2008/05/InterfaceTables/FND/APPS/MS_SAMPLE_EMPLOYEE) of message Poll
// does not match the default value (https://schemas.microsoft.com/OracleEBS/)
[System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="InterfaceTables/Poll/FND/APPS/MS_SAMPLE_EMPLOYEE")]
void Poll(Poll request);
}
消息协定
下面是MS_SAMPLE_EMPLOYEE接口表上的 轮询 操作的消息协定。
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="Poll", WrapperNamespace="http://schemas.microsoft.com/OracleEBS/2008/05/InterfaceTables/FND/APPS/MS_SAMPLE" +
"_EMPLOYEE", IsWrapped=true)]
public partial class Poll {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/OracleEBS/2008/05/InterfaceTables/FND/APPS/MS_SAMPLE" +
"_EMPLOYEE", Order=0)]
public schemas.microsoft.com.OracleEBS._2008._05.TableViewRecord.APPS.MS_SAMPLE_EMPLOYEE.SelectRecord[] DATA;
public Poll() {
}
public Poll(schemas.microsoft.com.OracleEBS._2008._05.TableViewRecord.APPS.MS_SAMPLE_EMPLOYEE.SelectRecord[] DATA) {
this.DATA = DATA;
}
}
WCF 服务类
添加适配器服务引用插件还会生成一个文件,该文件包含从服务协定 (接口) 实现的 WCF 服务类的存根。 文件的名称为 OracleEBSBindingService.cs。 可以插入逻辑以直接在此类中处理 轮询 操作。 以下代码显示由添加适配器服务引用插件生成的 WCF 服务类。
namespace OracleEBSBindingNamespace {
public class OracleEBSBindingService : InterfaceTables_FND_APPS_MS_SAMPLE_EMPLOYEE {
// CODEGEN: Generating message contract since the wrapper namespace (https://schemas.microsoft.com/OracleEBS/2008/05/InterfaceTables/FND/APPS/MS_SAMPLE_EMPLOYEE) of message Poll
// does not match the default value (https://schemas.microsoft.com/OracleEBS/)
public virtual void Poll(Poll request) {
throw new System.NotImplementedException("The method or operation is not implemented.");
}
}
}
使用 SELECT 语句接收轮询操作的入站消息
本部分介绍如何编写 .NET 应用程序以使用 Oracle 电子商务适配器接收入站轮询消息。
使用 SELECT 语句接收轮询消息
使用添加适配器服务引用插件为MS_SAMPLE_EMPLOYEE接口表上的 轮询 操作生成 WCF 服务协定 (接口) 和帮助程序类。 有关详细信息,请参阅 为 Oracle 电子商务套件解决方案项目生成 WCF 客户端或 WCF 服务协定。 可以选择在生成服务协定和帮助程序类时指定绑定属性。 这可以保证在生成的配置文件中正确设置它们。
从步骤 1 中生成的接口和帮助程序类实现 WCF 服务。 如果处理从 轮询 操作收到的数据时遇到错误,此类的 Poll 方法可能会引发异常以中止 轮询 事务;否则, 方法不返回任何内容。 必须按如下所示对 WCF 服务类进行特性化:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
在 Poll 方法中,可以直接实现应用程序逻辑。 可以在 OracleEBSBindingService.cs 中找到此类。 此示例中的此代码子类为 OracleEBSBindingService 类。 在此代码中,轮询消息接收并写入控制台。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class PollingService : OracleEBSBindingNamespace.OracleEBSBindingService { public override void Poll(Poll request) { Console.WriteLine("\nNew Polling Records Received"); Console.WriteLine("*************************************************"); Console.WriteLine("Emp No\tName\tDesignation\tSalary"); for (int i = 0; i < request.DATA.Length; i++) { Console.WriteLine("{0}\t{1}\t{2}\t{3}", request.DATA[i].EMP_NO, request.DATA[i].NAME, request.DATA[i].DESIGNATION, request.DATA[i].SALARY); } Console.WriteLine("*************************************************"); Console.WriteLine("\nHit <RETURN> to stop polling"); } }
必须实现以下类,以避免将凭据作为 URI 的一部分传递。 在应用程序的后一部分中,将实例化此类以传递凭据。
class PollingCredentials : ClientCredentials, IServiceBehavior { public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { bindingParameters.Add(this); } public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } protected override ClientCredentials CloneCore() { ClientCredentials clone = new PollingCredentials(); clone.UserName.UserName = this.UserName.UserName; clone.UserName.Password = this.UserName.Password; return clone; } }
创建 OracleEBSBinding 并通过指定绑定属性来配置轮询操作。 可以在代码中显式执行此操作,也可以在配置中以声明方式执行此操作。 至少必须指定 InboundOperationType、 PolledDataAvailableStatement、 PollingInput 和 PollingAction 绑定属性。
OracleEBSBinding binding = new OracleEBSBinding(); binding.InboundOperationType = InboundOperation.Polling; binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM MS_SAMPLE_EMPLOYEE"; binding.PollingInput = "SELECT * FROM MS_SAMPLE_EMPLOYEE FOR UPDATE"; binding.PollingAction = "InterfaceTables/Poll/FND/APPS/MS_SAMPLE_EMPLOYEE"; binding.PostPollStatement = "DELETE FROM MS_SAMPLE_EMPLOYEE";
由于轮询接口表,因此还必须设置应用程序上下文。 有关应用程序上下文和设置应用程序上下文所需的绑定属性的详细信息,请参阅 设置应用程序上下文。
binding.OracleUserName = "myOracleEBSUserName"; binding.OraclePassword = "myOracleEBSPassword"; binding.OracleEBSResponsibilityName = "myOracleEBSResponsibility";
通过实例化在步骤 3 中创建的 PollingCredentials 类来指定 Oracle 电子商务套件凭据。
PollingCredentials credentials = new PollingCredentials(); credentials.UserName.UserName = "<Enter user name here>"; credentials.UserName.Password = "<Enter password here>";
创建在步骤 2 中创建的 WCF 服务的实例。
// create service instance PollingService service = new PollingService();
使用 WCF 服务和基本连接 URI 创建 System.ServiceModel.ServiceHost 的实例。 基连接 URI 不能包含入站 ID(如果已指定)。 还必须在此处传递凭据。
// Enable service host Uri[] baseUri = new Uri[] { new Uri("oracleebs://ebs_instance_name") }; ServiceHost serviceHost = new ServiceHost(service, baseUri); serviceHost.Description.Behaviors.Add(credentials);
将服务终结点添加到服务主机。 为此,请按以下步骤操作:
使用在步骤 4 中创建的绑定。
指定包含凭据的连接 URI,并根据需要指定入站 ID。
将协定指定为“InterfaceTables_FND_APPS_MS_SAMPLE_EMPLOYEE”以轮询MS_SAMPLE_EMPLOYEE接口表。
// Add service endpoint: be sure to specify InterfaceTables_FND_APPS_MS_SAMPLE_EMPLOYEE as the contract Uri ConnectionUri = new Uri("oracleebs://ebs_instance_name"); serviceHost.AddServiceEndpoint("InterfaceTables_FND_APPS_MS_SAMPLE_EMPLOYEE", binding, ConnectionUri);
若要接收轮询数据,请打开服务主机。 每当查询返回结果集时,适配器都将返回数据。
// Open the service host to begin polling serviceHost.Open();
若要终止轮询,请关闭服务主机。
重要
适配器将继续轮询,直到服务主机关闭。
serviceHost.Close();
示例
以下示例演示轮询MS_SAMPLE_EMPLOYEE接口表的轮询应用程序。 PollingInput 属性包含 select 语句,该语句从MS_SAMPLE_EMPLOYEE表读取所有数据,post 轮询语句删除同一表中的所有数据。 第一个轮询消息提供MS_SAMPLE_EMPLOYEE接口表中的所有记录。 后续轮询消息将不包含任何记录,因为 post 轮询语句会删除记录。 在将更多数据添加到MS_SAMPLE_EMPLOYEE接口表之前,你不会收到任何轮询消息。 因此,必须使用新记录重新填充MS_SAMPLE_EMPLOYEE接口表。 为此,可以运行示例随附的 insert_apps_data.sql 脚本。 运行此脚本后,下一个轮询操作将提取插入到表中的新记录。 适配器将继续轮询,直到你通过按 <RETURN>
关闭服务主机。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Adapters.OracleEBS;
using Microsoft.ServiceModel.Channels;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.Collections.ObjectModel;
namespace SelectPolling_ServiceModel
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class PollingService : OracleEBSBindingNamespace.OracleEBSBindingService
{
public override void Poll(Poll request)
{
Console.WriteLine("\nNew Polling Records Received");
Console.WriteLine("*************************************************");
Console.WriteLine("Emp No\tName\tDesignation\tSalary");
for (int i = 0; i < request.DATA.Length; i++)
{
Console.WriteLine("{0}\t{1}\t{2}\t{3}",
request.DATA[i].EMP_NO,
request.DATA[i].NAME,
request.DATA[i].DESIGNATION,
request.DATA[i].SALARY);
}
Console.WriteLine("*************************************************");
Console.WriteLine("\nHit <RETURN> to stop polling");
}
}
class PollingCredentials : ClientCredentials, IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
bindingParameters.Add(this);
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{ }
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{ }
protected override ClientCredentials CloneCore()
{
ClientCredentials clone = new PollingCredentials();
clone.UserName.UserName = this.UserName.UserName;
clone.UserName.Password = this.UserName.Password;
return clone;
}
}
class Program
{
static void Main(string[] args)
{
ServiceHost serviceHost = null;
try
{
Console.WriteLine("Sample started...");
Console.WriteLine("Press any key to start polling...");
Console.ReadLine();
OracleEBSBinding binding = new OracleEBSBinding();
binding.InboundOperationType = InboundOperation.Polling;
binding.PolledDataAvailableStatement = "SELECT COUNT (*) FROM MS_SAMPLE_EMPLOYEE";
binding.PollingInput = "SELECT * FROM MS_SAMPLE_EMPLOYEE FOR UPDATE";
binding.PollingAction = "InterfaceTables/Poll/FND/APPS/MS_SAMPLE_EMPLOYEE";
binding.PostPollStatement = "DELETE FROM MS_SAMPLE_EMPLOYEE";
binding.OracleUserName = "myOracleEBSUserName";
binding.OraclePassword = "myOracleEBSPassword";
binding.OracleEBSResponsibilityName = "myOracleEBSResponsibility";
// This URI is used to specify the address for the ServiceEndpoint
// It must contain the InboundId that was used to generate
// the WCF service callback interface
Uri ConnectionUri = new Uri("oracleebs://ebs_instance_name");
// This URI is used to initialize the ServiceHost. It cannot contain
// an InboundID; otherwise,an exception is thrown when
// the ServiceHost is initialized.
Uri[] baseUri = new Uri[] { new Uri("oracleebs://ebs_instance_name") };
PollingCredentials credentials = new PollingCredentials();
credentials.UserName.UserName = "<Enter user name here>";
credentials.UserName.Password = "<Enter password here>";
Console.WriteLine("Opening service host...");
PollingService service = new PollingService();
serviceHost = new ServiceHost(service, baseUri);
serviceHost.Description.Behaviors.Add(credentials);
serviceHost.AddServiceEndpoint("InterfaceTables_FND_APPS_MS_SAMPLE_EMPLOYEE", binding, ConnectionUri);
serviceHost.Open();
Console.WriteLine("Service host opened...");
Console.WriteLine("Polling started...");
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Exception :" + e.Message);
Console.ReadLine();
/* If there is an error it will be specified in the inner exception */
if (e.InnerException != null)
{
Console.WriteLine("InnerException: " + e.InnerException.Message);
Console.ReadLine();
}
}
finally
{
// IMPORTANT: you must close the ServiceHost to stop polling
if (serviceHost.State == CommunicationState.Opened)
serviceHost.Close();
else
serviceHost.Abort();
}
}
}
}