本主题演示如何将 Oracle E-Business 适配器配置为从 Oracle 数据库接收查询通知消息。 若要演示通知,设想一个具有“已处理”列的表 ACCOUNTACTIVITY。 将新记录插入此表时,“状态”列的值将设置为“n”。 可以通过使用 SQL 语句注册通知,将适配器配置为接收通知,该 SQL 语句检索所有“已处理”列为“n”的记录。 为此,可以指定 NotificationStatement 绑定属性的 SQL 语句。 适配器客户端收到通知后,可以包含在 Oracle 数据库上执行任何后续任务的逻辑。 在此示例中,为了简单起见,适配器客户端会列出表中“已处理”列标记为“n”的所有记录。
通过 Oracle 电子商务适配器绑定属性来配置通知
下表汇总了用于配置从 Oracle E-Business Suite 接收通知的 Oracle E-Business 适配器绑定属性。 在运行 .NET 应用程序以接收通知时,必须指定这些绑定属性。
Binding 属性 | DESCRIPTION |
---|---|
InboundOperationType | 指定要执行的入站操作。 若要接收通知消息,请将此项设置为 “通知”。 |
NotificationPort | 指定 ODP.NET 必须打开的端口号,以侦听 Oracle 数据库中的数据库更改通知。 |
NotificationStatement | 指定用于注册查询通知的 Select 语句。 仅当指定 Select 语句的结果集更改时,适配器才会收到通知消息。 |
NotifyOnListenerStart | 指定适配器在启动侦听器时是否向适配器客户端发送通知。 |
有关这些属性的更完整说明,请参阅 有关 Oracle 电子商务套件绑定属性的 BizTalk 适配器的信息。 有关如何使用 Oracle 电子商务适配器从 Oracle E-Business Suite 接收通知的完整说明,请阅读本主题的其余部分。
使用 WCF 服务模型配置通知
若要使用 WCF 服务模型接收通知,必须:
为通知操作生成从适配器公开的元数据的WCF服务合约(接口)。 为此,可以使用“添加适配器服务引用插件”。
为 ACCOUNTACTIVITY 表的 Select 操作生成 WCF 客户端。 为此,可以使用“添加适配器服务引用插件”。
从此接口实现 WCF 服务。
使用服务主机(System.ServiceModel.ServiceHost)托管此 WCF 服务。
关于本主题中使用的示例
本主题中的示例接收 ACCOUNTACTIVITY 表的通知。 生成表的脚本随示例一起提供。 有关示例的详细信息,请参阅 Oracle EBS 适配器的示例。 Oracle E-Business 适配器示例中还提供了一个示例 Notification_ServiceModel,它基于本主题。
WCF 服务协定和类
可以使用“添加适配器服务引用插件”来创建用于通知操作的 WCF 服务协定(接口)和支持类。 有关生成 WCF 服务协定的详细信息,请参阅 为 Oracle E-Business Suite 解决方案项目生成 WCF 客户端或 WCF 服务协定。
WCF 服务协定(接口)
以下代码展示了为 通知 操作生成的 WCF 服务协定(接口)。
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://schemas.microsoft.com/OracleEBS/", ConfigurationName="Notification_")]
public interface Notification_ {
// CODEGEN: Generating message contract since the wrapper namespace (https://schemas.microsoft.com/OracleEBS/2008/05/Notification/) of message Notification
// does not match the default value (https://schemas.microsoft.com/OracleEBS/)
[System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="Notification")]
void Notification(Notification request);
}
消息合同
下面是通知操作的消息协议。
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="Notification", WrapperNamespace="http://schemas.microsoft.com/OracleEBS/2008/05/Notification/", IsWrapped=true)]
public partial class Notification {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/OracleEBS/2008/05/Notification/", Order=0)]
public schemas.microsoft.com.OracleEBS._2008._05.Notification.NotificationDetails[] Details;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/OracleEBS/2008/05/Notification/", Order=1)]
public string Info;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/OracleEBS/2008/05/Notification/", Order=2)]
public string[] ResourceNames;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/OracleEBS/2008/05/Notification/", Order=3)]
public string Source;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://schemas.microsoft.com/OracleEBS/2008/05/Notification/", Order=4)]
public string Type;
public Notification() {
}
public Notification(schemas.microsoft.com.OracleEBS._2008._05.Notification.NotificationDetails[] Details, string Info, string[] ResourceNames, string Source, string Type) {
this.Details = Details;
this.Info = Info;
this.ResourceNames = ResourceNames;
this.Source = Source;
this.Type = Type;
}
}
WCF 服务类
添加适配器服务引用插件还会生成一个文件,该文件包含从服务协定(接口)实现的 WCF 服务类的存根。 文件的名称OracleEBSBindingService.cs。 可以在此类中直接插入逻辑以处理通知操作。 以下代码显示了由“添加适配器服务引用插件”生成的 WCF 服务类。
namespace OracleEBSBindingNamespace {
public class OracleEBSBindingService : Notification_ {
// CODEGEN: Generating message contract since the wrapper namespace (https://schemas.microsoft.com/OracleEBS/2008/05/Notification/) of message Notification
// does not match the default value (https://schemas.microsoft.com/OracleEBS/)
public virtual void Notification(Notification request) {
throw new System.NotImplementedException("The method or operation is not implemented.");
}
}
}
使用 WCF 服务模型接收查询通知
本部分提供有关如何编写 .NET 应用程序以使用 Oracle 电子商务适配器接收查询通知的说明。
接收查询通知
使用“添加适配器服务引用插件”生成 WCF 客户端,以在 ACCOUNTACTIVITY 表上执行“Select”操作。 在收到通知消息后,你将使用此客户端执行选择操作。 将一个新类 TableOperation.cs 添加到您的项目中,并添加以下代码片段以执行 Select 操作。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Notification_ServiceModel { class TableOperation { public void TableOp() { ////////////////////////////////////////////////////////////////////// // CREATING THE CLIENT AND SETTING CLIENT CREDENTIALS ////////////////////////////////////////////////////////////////////// Tables_APPS_ACCOUNTACTIVITYClient client = new Tables_APPS_ACCOUNTACTIVITYClient(); client.ClientCredentials.UserName.UserName = "<Enter user name here>"; client.ClientCredentials.UserName.Password = "<Enter password here>"; //////////////////////////////////////////////////////////////////// // OPENING THE CLIENT ////////////////////////////////////////////////////////////////////// try { Console.WriteLine("Opening the client ..."); client.Open(); } catch (Exception ex) { Console.WriteLine("Exception: " + ex.Message); throw; } //////////////////////////////////////////////////////////////////////////////////////// // SELECTING THE LAST INSERTED VALUES //////////////////////////////////////////////////////////////////////////////////////// Console.WriteLine("The application will now select the last inserted record"); schemas.microsoft.com.OracleEBS._2008._05.TableViewRecord.APPS.ACCOUNTACTIVITY.SelectRecord[] selectRecords; try { selectRecords = client.Select("*", "WHERE PROCESSED = 'n'"); } catch (Exception ex) { Console.WriteLine("Exception: " + ex.Message); throw; } Console.WriteLine("The details of the newly added records are:"); Console.WriteLine("********************************************"); for (int i = 0; i < selectRecords.Length; i++) { Console.WriteLine("Transaction ID : " + selectRecords[i].TID); Console.WriteLine("Account ID : " + selectRecords[i].ACCOUNT); Console.WriteLine("Processed Status : " + selectRecords[i].PROCESSED); Console.WriteLine(); } Console.WriteLine("********************************************"); } } }
使用“Add Adapter Service Reference Plug-in”生成 通知作业的 WCF 服务协定(接口)和帮助类。
有关详细信息,请参阅 为 Oracle 电子商务套件解决方案项目生成 WCF 客户端或 WCF 服务协定。 可以选择在生成服务协定和帮助程序类时指定绑定属性。 这可以保证在生成的配置文件中正确设置它们。
从步骤 2 中生成的接口和帮助程序类实现 WCF 服务。 如果在处理从Notification操作接收的数据时遇到错误,此类的Notification方法可能会引发异常以中止操作;否则,该方法不返回任何内容。 必须按如下所示将 WCF 服务类属性化:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
在 Notification 方法中,可以直接实现应用程序逻辑。 可以在OracleEBSBindingService.cs中找到此类。 此示例中的此代码子类为 OracleEBSBindingService 类。 在此代码中,收到的通知消息将写入控制台。 此外,调用 TableOperation 类中的 TableOp 方法来执行 Select作。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class NotificationService : OracleEBSBindingNamespace.OracleEBSBindingService { public override void Notification(Notification request) { Console.WriteLine("\nNew Notification Received"); Console.WriteLine("*************************************************"); Console.WriteLine(request.Info); Console.WriteLine(request.Source); Console.WriteLine(request.Type); Console.WriteLine("*************************************************"); TableOperation Ops = new TableOperation(); Ops.TableOp(); } }
必须实现下列类才能传递 Oracle 电子商务套件的凭据。 在应用程序的后期部分中,您将实例化这个类以传递凭证。
class NotificationCredentials : 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 NotificationCredentials(); clone.UserName.UserName = this.UserName.UserName; clone.UserName.Password = this.UserName.Password; return clone; } }
创建 OracleEBSBinding 并配置适配器,以通过指定绑定属性来接收查询通知。 可以在代码中显式执行此作,也可以在配置中以声明方式执行此作。 至少必须指定 InboundOperationType 和 NotificationStatement 绑定属性。
OracleEBSBinding binding = new OracleEBSBinding(); binding.InboundOperationType = InboundOperation.Notification; binding.NotificationStatement = "SELECT TID,ACCOUNT,PROCESSED FROM APPS.ACCOUNTACTIVITY WHERE PROCESSED = 'n'"; binding.NotifyOnListenerStart = true; binding.NotificationPort = 10;
重要
NotificationPort 绑定属性的值必须设置为必须添加到 Windows 防火墙例外列表的相同端口号。 有关如何将端口添加到 Windows 防火墙例外列表的说明,请参阅 https://go.microsoft.com/fwlink/?LinkID=196959。
重要
如果未设置 NotificationPort 绑定属性,适配器将假定此绑定属性的默认值为 -1。 在这种情况下,必须完全禁用 Windows 防火墙才能接收通知消息。
通过实例化在步骤 4 中创建的 NotificationCredentials 类来指定 Oracle E-Business Suite 凭据。
NotificationCredentials credentials = new NotificationCredentials(); credentials.UserName.UserName = "<Enter user name here>"; credentials.UserName.Password = "<Enter password here>";
创建在步骤 3 中创建的 WCF 服务的实例。
// create service instance NotificationService service = new NotificationService();
使用 WCF 服务和基本连接 URI 创建 System.ServiceModel.ServiceHost 的实例。 还必须在此处指定凭据。
// Enable service host Uri[] baseUri = new Uri[] { new Uri("oracleebs://ebs_instance_name") }; ServiceHost serviceHost = new ServiceHost(service, baseUri); serviceHost.Description.Behaviors.Add(credentials);
将服务终结点添加到服务主机。 为此,请按以下步骤操作:
使用在步骤 5 中创建的绑定。
指定包含凭据的连接 URI,并根据需要指定入站 ID。
将协定指定为“Notification_”。
// Add service endpoint: be sure to specify Notification_ as the contract Uri ConnectionUri = new Uri("oracleebs://ebs_instance_name?"); serviceHost.AddServiceEndpoint("Notification_", binding, ConnectionUri);
若要接收通知消息,请打开服务主机。
// Open the service host to begin receiving notifications serviceHost.Open();
若要停止接收通知,请关闭服务主机。
serviceHost.Close();
示例:
以下示例演示一个 .NET 应用程序,用于接收 ACCOUNTACTIVITY 表的通知消息。
注释
以下代码片段实例化 TableOperation.cs 类并调用 TableOp 方法。 "步骤 1 中介绍了类 (class) 和方法 (method)。"
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 Notification_ServiceModel
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class NotificationService : OracleEBSBindingNamespace.OracleEBSBindingService
{
public override void Notification(Notification request)
{
Console.WriteLine("\nNew Notification Received");
Console.WriteLine("*************************************************");
Console.WriteLine(request.Info);
Console.WriteLine(request.Source);
Console.WriteLine(request.Type);
Console.WriteLine("*************************************************");
TableOperation Ops = new TableOperation();
Ops.TableOp();
}
}
class NotificationCredentials : 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 NotificationCredentials();
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 receiving notifications...");
Console.ReadLine();
OracleEBSBinding binding = new OracleEBSBinding();
binding.InboundOperationType = InboundOperation.Notification;
binding.NotificationStatement = "SELECT TID,ACCOUNT,PROCESSED FROM APPS.ACCOUNTACTIVITY WHERE PROCESSED = 'n'";
binding.NotifyOnListenerStart = true;
binding.NotificationPort = 10;
// 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") };
NotificationCredentials credentials = new NotificationCredentials();
credentials.UserName.UserName = "<Enter user name here>";
credentials.UserName.Password = "<Enter password here>";
Console.WriteLine("Opening service host...");
NotificationService service = new NotificationService();
serviceHost = new ServiceHost(service, baseUri);
serviceHost.Description.Behaviors.Add(credentials);
serviceHost.AddServiceEndpoint("Notification_", binding, ConnectionUri);
serviceHost.Open();
Console.WriteLine("Service host opened...");
Console.WriteLine("Waiting for notification...");
Console.WriteLine("\nHit <RETURN> to stop receiving notification");
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();
}
}
}
}