使用 WCF 服务模型接收 Oracle E-Business Suite 数据库更改通知

本主题演示如何将 Oracle 电子商务适配器配置为从 Oracle 数据库接收查询通知消息。 若要演示通知,请考虑一个表 ACCOUNTACTIVITY,其中包含“已处理”列。 向此表插入新记录时,“状态”列的值设置为“n”。 可以通过使用 SQL 语句注册通知来将适配器配置为接收通知,该语句检索“已处理”列为“n”的所有记录。 为此,可以为 NotificationStatement 绑定属性指定 SQL 语句。 适配器客户端收到通知后,可以包含对 Oracle 数据库执行任何后续任务的逻辑。 在此示例中,为简单起见,适配器客户端列出了表中“已处理”列为“n”的所有记录。

使用 Oracle 电子商务适配器绑定属性配置通知

下表汇总了用于配置从 Oracle 电子商务套件接收通知的 Oracle 电子商务适配器绑定属性。 必须在运行 .NET 应用程序时指定这些绑定属性才能接收通知。

Binding 属性 说明
InboundOperationType 指定要执行的入站操作。 若要接收通知消息,请将此项设置为 “通知”。
NotificationPort 指定 ODP.NET 必须打开的端口号,以侦听来自 Oracle 数据库的数据库更改通知。
NotificationStatement 指定用于注册查询通知的 Select 语句。 仅当指定 Select 语句的结果集发生更改时,适配器才会收到通知消息。
NotifyOnListenerStart 指定在启动侦听器时适配器是否向适配器客户端发送通知。

有关这些属性的更完整说明,请参阅 阅读有关 BizTalk Adapter for Oracle E-Business Suite 绑定属性的信息。 有关如何使用 Oracle 电子商务适配器从 Oracle 电子商务套件接收通知的完整说明,请阅读本主题的其余部分。

使用 WCF 服务模型配置通知

若要使用 WCF 服务模型接收通知,必须:

  • 从适配器公开的元数据生成 WCF 服务协定 (接口) 通知 操作。 为此,可以使用添加适配器服务引用插件。

  • 为 ACCOUNTACTIVITY 表上的 Select 操作生成 WCF 客户端。 为此,可以使用添加适配器服务引用插件。

  • 从此接口实现 WCF 服务。

  • 使用服务主机 (System.ServiceModel.ServiceHost) 托管此 WCF 服务。

关于本主题中使用的示例

本主题中的示例接收 ACCOUNTACTIVITY 表的通知。 示例提供了用于生成表的脚本。 有关示例的详细信息,请参阅 Oracle EBS 适配器的示例。 基于本主题 的示例 Notification_ServiceModel 也随 Oracle 电子商务适配器示例一起提供。

WCF 服务协定和类

可以使用添加适配器服务引用插件创建 WCF 服务协定 (接口) 和 通知 操作的支持类。 有关生成 WCF 服务协定的详细信息,请参阅 为 Oracle 电子商务套件解决方案项目生成 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 电子商务适配器接收查询通知。

接收查询通知

  1. 使用添加适配器服务引用插件生成 WCF 客户端,以便对 ACCOUNTACTIVITY 表执行 Select 操作。 在收到通知消息后,将使用此客户端执行 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("********************************************");
            }
        }
    }
    
    
  2. 使用“添加适配器服务引用”插件生成 WCF 服务协定, (通知 操作的接口) 和帮助程序类。

    有关详细信息,请参阅 为 Oracle 电子商务套件解决方案项目生成 WCF 客户端或 WCF 服务协定。 可以选择在生成服务协定和帮助程序类时指定绑定属性。 这可以保证在生成的配置文件中正确设置它们。

  3. 从步骤 2 中生成的接口和帮助程序类实现 WCF 服务。 如果处理从通知操作收到的数据时遇到错误,此类的 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();
    
        }
    }
    
  4. 必须实现以下类才能传递 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;
        }
    }
    
  5. 创建 OracleEBSBinding ,并通过指定绑定属性将适配器配置为接收查询通知。 可以在代码中显式执行此操作,也可以在配置中以声明方式执行此操作。 至少必须指定 InboundOperationTypeNotificationStatement 绑定属性。

    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 防火墙才能接收通知消息。

  6. 通过实例化在步骤 4 中创建的 NotificationCredentials 类来指定 Oracle 电子商务套件凭据。

    NotificationCredentials credentials = new NotificationCredentials();
    credentials.UserName.UserName = "<Enter user name here>";
    credentials.UserName.Password = "<Enter password here>";
    
  7. 创建在步骤 3 中创建的 WCF 服务的实例。

    // create service instance
    NotificationService service = new NotificationService();
    
  8. 使用 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);
    
    
  9. 将服务终结点添加到服务主机。 为此,请按以下步骤操作:

    • 使用在步骤 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);
      
  10. 若要接收通知消息,请打开服务主机。

    // Open the service host to begin receiving notifications
    serviceHost.Open();
    
  11. 若要停止接收通知,请关闭服务主机。

    serviceHost.Close();
    

示例

以下示例演示用于接收 ACCOUNTACTIVITY 表的通知消息的 .NET 应用程序。

注意

以下代码片段实例化 TableOperation.cs 类并调用 TableOp 方法。 步骤 1 中介绍了 类和 方法。

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();
            }

        }
    }
}

另请参阅

使用 WCF 服务模型开发 Oracle 电子商务套件应用程序