使用 WCF 服务模型接收 Oracle 电子商务套件数据库更改通知

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

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

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

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

有关这些属性的更完整说明,请参阅 了解用于 Oracle 电子商务套件的 BizTalk 适配器绑定属性。 有关如何使用 Oracle 电子商务适配器接收来自 Oracle 电子商务套件的通知的完整说明,请参阅本主题的其余部分。

使用 WCF 服务模型配置通知

若要使用 WCF 服务模型接收通知,必须执行以下操作:

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

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

  • 实现此接口中的 WCF 服务。

  • 使用服务主机 (system.servicemodel) 承载此 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 服务的存根(stub)。 该文件的名称为 OracleEBSBindingService。 您可以插入逻辑来直接将 通知 操作处理到此类中。 下面的代码显示了 "添加适配器服务引用" 插件生成的 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. 使用 "添加适配器服务引用" 插件为ACCOUNTACTIVITY表上的SELECT操作生成 WCF 客户端。 接收通知消息后,将使用此客户端执行选择操作。 向你的项目添加新类 TableOperation,并添加以下代码片段以执行选择操作。

    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中生成的接口和 helper 类实现 WCF 服务。 如果在处理从通知操作接收的数据时遇到错误,则此类的通知方法可能会引发异常来中止操作;否则,该方法不会返回任何内容。 必须按如下所示对 WCF 服务类进行属性:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    

    通知 方法中,可以直接实现应用程序逻辑。 可以在 OracleEBSBindingService 中找到此类。 此示例中的此代码为 OracleEBSBindingService 类的子类。 在此代码中,收到的通知消息将写入控制台。 此外,还将调用TableOperation类中的TableOp方法来执行选择操作。

    [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 Firewall 才能接收通知消息。

  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 的实例。 还必须在此处指定凭据。

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

示例

下面的示例演示了一个 .NET 应用程序,用于接收 ACCOUNTACTIVITY 表的通知消息。

注意

以下代码片段将实例化 TableOperation 类,并调用 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 电子商务套件应用程序