Rolosoft.comRolosoft PayPal IPN Easy for .NET
Use Ipn Easy with WCF, NetMsmqBinding and Windows Workflow (WF)
Rolosoft.com: PayPal IPN Easy for .NET

Integration of IPN Easy for .NET with Windows Communication Framework (WCF) is only possible when using the Enterprise edition of the component.

By using WCF integration, it is possible for IPN Easy for .NET to be used with WCF supported bindings such as:

The Enterprise edition of IPN Easy for .NET includes WCF compatible service and data contracts for easy out of the box WCF implementation.

Some of the possible applications of using WCF with IPN Easy for .NET are:

The following example shows how to use IPN Easy for .NET with WCF using NetMsmqBinding. Then, on the receiving side, we show how to host and invoke a Workflow (WF) in a windows service.

Configure MSMQ binding
  1. Configure MSMQ service binding in .config file as follows:

    CopyXML
    <system.serviceModel>
      <bindings>
        <netMsmqBinding>
          <binding name="ThisMsmqBinding" receiveRetryCount="20" maxRetryCycles="0" retryCycleDelay="00:00:05" maxReceivedMessageSize="1073741824">
            <readerQuotas maxArrayLength="1073741824" />
            <security>
              <transport msmqAuthenticationMode="None" msmqProtectionLevel="None" />
            </security>
          </binding>
          <binding name="PoisonBinding" receiveRetryCount="0" maxRetryCycles="1" retryCycleDelay="00:00:05" receiveErrorHandling="Fault">
            <security>
              <transport msmqAuthenticationMode="None" msmqProtectionLevel="None" />
            </security>
          </binding>
        </netMsmqBinding>
      </bindings>
    </system.serviceModel>
Implement MSMQ and MSMQ channel submitter class
  1. Create a private, transactional queue called paypaltransactions.

    Grant appropriate read/write permissions to this queue using the Windows Message Queuing admin tool. If you are using IPN Easy for .NET hosted in IIS, you need to grant the NETWORK SERVICE account READ/WRITE permissions to the queue.

    If you are running Vista, Windows 7, Server 2008 or higher, you may also need to grant permissions to MSDTC as follows:

    • Start > Run > dcomcnfg.exe
    • Component Services > My Computer > Distributed Transaction Coordinator
    • Right click Local DTC
    • Security tab
    • Check "Network DTC Access"
    • Check "Allow Inbound"
    • Check "Allow Outbound"
  2. Create a WCF submitter implementation based on the service contract interface IIpnReceivedContract

    An example is as follows:

    Code/Submitters/PayPal/WcfQueuingPaypalIpnSubmitterSubmitter.cs
    CopyC#
    using System;
    using System.ServiceModel;
    using Rolosoft.IpnEasy.Net;
    using Rolosoft.IpnEasy.Net.PayPal;
    
    
    namespace MyProject.Code.Submitters.PayPal
    {
    
        public class WcfQueuingPaypalIpnSubmitterSubmitter:IIpnReceivedContract
        {
    -        #region Privates
             private readonly IIpnReceivedContract _channel;
             #endregion
    
    -        #region Ctors
     
             public WcfQueuingPaypalIpnSubmitterSubmitter(string server)
             {
                 //sEndpointAddress is the location of the MSMQ.
                 var sEndpointAddress = "net.msmq://localhost/paypaltransactions";
                 var endpointAddress = new EndpointAddress(new Uri(sEndpointAddress));
     
                 var clientBinding = new NetMsmqBinding("ThisMsmqBinding");
     
                 var channelFactory = new ChannelFactory<IIpnReceivedContract>(clientBinding, endpointAddress);
                 _channel = channelFactory.CreateChannel();
     
             }
     
             #endregion
    
    -        #region Implementation of IIpnReceivedContract
     
             /// <summary>
             /// <para>
             /// The Service Contract interface for WCF implementations of PayPal IPN integration.*
             /// </para>
             /// <para>
             /// Submit IPN data to queue and for onward processing.
             /// </para>
             /// </summary>
             /// <param name="transaction">PayPal IPN transaction data</param>
             /// <param name="log">The <see cref="T:Rolosoft.IpnEasy.Net.Log"/> of the PayPal IPN interaction</param>
             public void SubmitIpn(Transaction transaction, Log log)
             {
                 if (_channel == null) return;
                 if (transaction == null) return;
                 _channel.SubmitIpn(transaction, log);
             }
     
             #endregion
        }
    }
    CopyVB.NET
    Imports System.ServiceModel
    Imports Rolosoft.IpnEasy.Net
    Imports Rolosoft.IpnEasy.Net.PayPal
    
    
    Namespace MyProject.Code.Submitters.PayPal
    
        Public Class WcfQueuingPaypalIpnSubmitterSubmitter
            Implements IIpnReceivedContract
    -        #Region "Privates"
             Private ReadOnly _channel As IIpnReceivedContract
             #End Region
    
    -        #Region "Ctors"
     
             Public Sub New(server As String)
                 'sEndpointAddress is the location of the MSMQ.
                 Dim sEndpointAddress = "net.msmq://localhost/paypaltransactions"
                 Dim endpointAddress = New EndpointAddress(New Uri(sEndpointAddress))
     
                 Dim clientBinding = New NetMsmqBinding("ThisMsmqBinding")
     
                 Dim channelFactory = New ChannelFactory(Of IIpnReceivedContract)(clientBinding, endpointAddress)
     
                 _channel = channelFactory.CreateChannel()
             End Sub
     
             #End Region
    
    -        #Region "Implementation of IIpnReceivedContract"
     
             ''' <summary>
             ''' <para>
             ''' The Service Contract interface for WCF implementations of PayPal IPN integration.*
             ''' </para>
             ''' <para>
             ''' Submit IPN data to queue and for onward processing.
             ''' </para>
             ''' </summary>
             ''' <param name="transaction">PayPal IPN transaction data</param>
             ''' <param name="log">The <see cref="T:Rolosoft.IpnEasy.Net.Log"/> of the PayPal IPN interaction</param>
             Public Sub SubmitIpn(transaction As Transaction, log As Log)
                 If _channel Is Nothing Then
                     Return
                 End If
                 If transaction Is Nothing Then
                     Return
                 End If
                 _channel.SubmitIpn(transaction, log)
             End Sub
     
             #End Region
        End Class
    End Namespace
PayPal IPN receiver
  1. PayPal IPN can be configured to post IPN messages to any public URL. For further information on configuring PayPal IPN messages, please refer to the appropriate PayPal documentation.

    For testing purposes, you could use the PayPal IPN Test Tool from the PayPal developer sandbox.

    The following example shows a web handler that is hosted in an ASP.NET web application.

    PayPal/Ipn.ashx
    CopyC#
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.Web;
    using System.Web.Configuration;
    using System.Web.Services;
    using Resources;
    using MyProject.Code.Submitters.PayPal;
    using Rolosoft.IpnEasy.Net.PayPal;
    
    
    namespace MyProject.PayPal
    {
        /// <summary>
        /// Receives PayPal IPN notifications and submits messages to MSMQ for processing
        /// </summary>
        [WebService(Namespace = "http://tempuri.org")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        public class Ipn : IHttpHandler
        {
    
    -        #region Privates
             private readonly IpnEasy.Net.Ipn _ipnEasy;
             #endregion
    
    -        #region Ctors
     
             public Ipn()
             {
                 _ipnEasy = new IpnEasy.Net.Ipn();
                 _ipnEasy.TransactionReceived += IpnEasyTransactionReceived;
             }
     
     
             #endregion
    
    -        #region Events
     
             static void IpnEasyTransactionReceived(object sender, TransactionEventArgs e)
             {
                 var info = e.Transaction;
                 //submit to VALID queue for normal processing
                 var submitter = new WcfQueuingPaypalIpnSubmitterSubmitter(".");
                 submitter.SubmitIpn(info,e.Log);
             }
     
             #endregion
    
    -        #region Methods
     
             public void ProcessRequest(HttpContext context)
             {
                 context.Response.ContentType = "text/plain";
                 _ipnEasy.Validate();
             }
     
     
             #endregion
    
    -        #region Properties
     
             public bool IsReusable
             {
                 get{return false;}
             }
     
             #endregion
    
        }
    }
    CopyVB.NET
    Imports System.Diagnostics
    Imports System.Globalization
    Imports System.Web
    Imports System.Web.Configuration
    Imports System.Web.Services
    Imports Resources
    Imports MyProject.Code.Submitters.PayPal
    Imports Rolosoft.IpnEasy.Net.PayPal
    
    
    Namespace MyProject.PayPal
        ''' <summary>
        ''' Receives PayPal IPN notifications and submits messages to MSMQ for processing
        ''' </summary>
        <WebService([Namespace] := "http://tempuri.org")> _
        <WebServiceBinding(ConformsTo := WsiProfiles.BasicProfile1_1)> _
        Public Class Ipn
            Implements IHttpHandler
    
    -        #Region "Privates"
             Private ReadOnly _ipnEasy As IpnEasy.Net.Ipn
             #End Region
    
    -        #Region "Ctors"
     
             Public Sub New()
                 _ipnEasy = New IpnEasy.Net.Ipn()
                 AddHandler _ipnEasy.TransactionReceived, AddressOf IpnEasyTransactionReceived
             End Sub
     
     
             #End Region
    
    -        #Region "Events"
     
             Private Shared Sub IpnEasyTransactionReceived(sender As Object, e As TransactionEventArgs)
                 Dim info = e.Transaction
                 'submit to VALID queue for normal processing
                 Dim submitter = New WcfQueuingPaypalIpnSubmitterSubmitter(".")
                 submitter.SubmitIpn(info, e.Log)
             End Sub
     
             #End Region
    
    -        #Region "Methods"
     
             Public Sub ProcessRequest(context As HttpContext) Implements IHttpHandler.ProcessRequest
                 context.Response.ContentType = "text/plain"
                 _ipnEasy.Validate()
             End Sub
     
     
             #End Region
    
    -        #Region "Properties"
     
             Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
                 Get
                     Return False
                 End Get
             End Property
     
             #End Region
    
        End Class
    End Namespace
    Note:

    If you are using the PayPal developer sandbox IPN test tool, your IPN listener must be visible from the internet.

    It may be possible to configure your router to use NAT port redirection to allow you to use the PayPal sandbox IPN test tool to send IPN messages to your local development machine. If you need assistance with this, please consult your network administrator.

WCF receiver
  1. The following illustration shows how to create a WCF listener based on the NetMsmqBinding implementation in this example.

  2. Create a new project (e.g. a windows service or .exe).

  3. Add a project reference to IPN Easy for .NET.

  4. Modify your project .config file with service binding configuration as follows:

    CopyXML
    <system.serviceModel>
        <bindings>
          <netMsmqBinding>
            <binding name="ThisMsmqBinding" maxRetryCycles="0" receiveRetryCount="20" retryCycleDelay="00:00:05" maxReceivedMessageSize="1073741824">
              <readerQuotas maxArrayLength="1073741824"/>
              <security>
                <transport msmqAuthenticationMode="None" msmqProtectionLevel="None"/>
              </security>
            </binding>
          </netMsmqBinding>
        </bindings>
      </system.serviceModel>
  5. Create Code\Watchers\PayPalIpnItemFoundEventArgs.cs

    CopyC#
    using System;
    using Rolosoft.IpnEasy.Net;
    using Rolosoft.IpnEasy.Net.PayPal;
    
    
    namespace MyProject.Code.Watchers
    {
        class PayPalIpnItemFoundEventArgs: EventArgs
        {
    
    -        #region Ctors
     
             public PayPalIpnItemFoundEventArgs(Transaction transaction,Log log)
             {
                 PayPalTransaction = transaction;
                 Log = log;
             }
     
             #endregion
    
    -        #region Properties
     
             public Transaction PayPalTransaction { get; set; }
     
             public Log Log { get; set; }
     
             #endregion
    
        }
    }
    CopyVB.NET
    Imports Rolosoft.IpnEasy.Net
    Imports Rolosoft.IpnEasy.Net.PayPal
    
    
    Namespace MyProject.Code.Watchers
        Class PayPalIpnItemFoundEventArgs
            Inherits EventArgs
    
    -        #Region "Ctors"
     
             Public Sub New(transaction As Transaction, log__1 As Log)
                 PayPalTransaction = transaction
                 Log = log__1
             End Sub
     
             #End Region
    
    -        #Region "Properties"
     
             Public Property PayPalTransaction() As Transaction
                 Get
                     Return m_PayPalTransaction
                 End Get
                 Set
                     m_PayPalTransaction = Value
                 End Set
             End Property
             Private m_PayPalTransaction As Transaction
     
             Public Property Log() As Log
                 Get
                     Return m_Log
                 End Get
                 Set
                     m_Log = Value
                 End Set
             End Property
             Private m_Log As Log
     
             #End Region
    
        End Class
    End Namespace
  6. Create Code\Watchers\PayPalIpnItemWatcher.cs

    CopyC#
    -#region Usings
     
     using System;
     using Rolosoft.IpnEasy.Net;
     using Rolosoft.IpnEasy.Net.PayPal;
     
     #endregion
    
    namespace MyProject.Code.Watchers
    {
        internal abstract class PayPalIpnItemWatcher
        {
    -        #region Events
     
             public static event EventHandler<PayPalIpnItemFoundEventArgs> PayPalIpnReceived;
     
             #endregion
    
    -        #region Methods
     
             protected virtual void OnPayPalIpnReceived(Transaction transaction,Log log)
             {
                 if (transaction == null)
                     return;
                 if (PayPalIpnReceived != null)
                     PayPalIpnReceived(this, new PayPalIpnItemFoundEventArgs(transaction,log));
             }
     
             public abstract void StartWatching();
     
             public abstract void StopWatching();
     
             #endregion
        }
    }
    CopyVB.NET
    -#Region "Usings"
     
     Imports Rolosoft.IpnEasy.Net
     Imports Rolosoft.IpnEasy.Net.PayPal
     
     #End Region
    
    Namespace MyProject.Code.Watchers
        Friend MustInherit Class PayPalIpnItemWatcher
    -        #Region "Events"
     
             Public Shared Event PayPalIpnReceived As EventHandler(Of PayPalIpnItemFoundEventArgs)
     
             #End Region
    
    -        #Region "Methods"
     
             Protected Overridable Sub OnPayPalIpnReceived(transaction As Transaction, log As Log)
                 If transaction Is Nothing Then
                     Return
                 End If
                 RaiseEvent PayPalIpnReceived(Me, New PayPalIpnItemFoundEventArgs(transaction, log))
             End Sub
     
             Public MustOverride Sub StartWatching()
     
             Public MustOverride Sub StopWatching()
     
             #End Region
        End Class
    End Namespace
  7. Create Code\Watchers\WcfQueuingPayPalIpnItemWatcher.cs

    CopyC#
    -#region Usings
     
     using System;
     using System.ServiceModel;
     using Rolosoft.IpnEasy.Net;
     using Rolosoft.IpnEasy.Net.PayPal;
     
     
     #endregion
    
    namespace MyProject.Code.Watchers
    {
        [ServiceBehavior]
        internal class WcfQueuingPayPalIpnItemWatcher : PayPalIpnItemWatcher, IIpnReceivedContract , IDisposable
        {
    -        #region Privates
     
             private readonly ServiceHost _serviceHost;
             private bool _disposed;
     
             #endregion
    
    -        #region Ctors
     
             public WcfQueuingPayPalIpnItemWatcher()
             {
                 _serviceHost = new ServiceHost(typeof (WcfQueuingPayPalIpnItemWatcher));
             }
     
             #endregion
    
    -        #region Methods
     
    -        #region IDisposable Members
     
             public void Dispose()
             {
                 Dispose(true);
                 GC.SuppressFinalize(this);
             }
     
             #endregion
     
    -        #region IIpnReceivedContract Members
     
             /// <summary>
             /// <para>
             /// The Service Contract interface for WCF implementations of PayPal IPN integration.*
             /// </para>
             /// <para>
             /// Submit IPN data to queue and for onward processing.
             /// </para>
             /// </summary>
             /// <param name="transaction">PayPal IPN transaction data</param>
             /// <param name="log">The <see cref="T:Rolosoft.IpnEasy.Net.Log"/> of the PayPal IPN interaction</param>
             [OperationBehavior(TransactionAutoComplete = true)]
             public void SubmitIpn(Transaction transaction, Log log)
             {
                 OnPayPalIpnReceived(transaction, log);
             }
     
             #endregion
     
             public override void StartWatching()
             {
                 //sEndpointAddress is the location of the MSMQ.
                 var sEndpointAddress = "net.msmq://localhost/paypaltransactions";
                 var endpointUri = new Uri(sEndpointAddress);
     
                 var serviceBinding = new NetMsmqBinding("ThisMsmqBinding");
     
                 _serviceHost.AddServiceEndpoint(typeof(IIpnReceivedContract), serviceBinding, endpointUri);
     
                 _serviceHost.Open();
             }
     
             public override void StopWatching()
             {
                 if (_serviceHost != null)
                     _serviceHost.Close();
             }
     
     
             public void Close()
             {
                 Dispose();
             }
     
             ~WcfQueuingPayPalIpnItemWatcher()
             {
                 Dispose();
             }
     
             protected virtual void Dispose(bool disposing)
             {
                 if (!disposing)
                     return;
                 if (_disposed)
                     return;
                 if (_serviceHost == null)
                     return;
                 _serviceHost.Close();
                 _disposed = true;
             }
     
             #endregion
        }
    }
    CopyVB.NET
    -#Region "Usings"
     
     Imports System.ServiceModel
     Imports Rolosoft.IpnEasy.Net
     Imports Rolosoft.IpnEasy.Net.PayPal
     
     
     #End Region
    
    Namespace MyProject.Code.Watchers
        <ServiceBehavior> _
        Friend Class WcfQueuingPayPalIpnItemWatcher
            Inherits PayPalIpnItemWatcher
            Implements IIpnReceivedContract
            Implements IDisposable
    -        #Region "Privates"
     
             Private ReadOnly _serviceHost As ServiceHost
             Private _disposed As Boolean
     
             #End Region
    
    -        #Region "Ctors"
     
             Public Sub New()
                 _serviceHost = New ServiceHost(GetType(WcfQueuingPayPalIpnItemWatcher))
             End Sub
     
             #End Region
    
    -        #Region "Methods"
     
    -        #Region "IDisposable Members"
     
             Public Sub Dispose() Implements IDisposable.Dispose
                 Dispose(True)
                 GC.SuppressFinalize(Me)
             End Sub
     
             #End Region
     
    -        #Region "IIpnReceivedContract Members"
     
             ''' <summary>
             ''' <para>
             ''' The Service Contract interface for WCF implementations of PayPal IPN integration.*
             ''' </para>
             ''' <para>
             ''' Submit IPN data to queue and for onward processing.
             ''' </para>
             ''' </summary>
             ''' <param name="transaction">PayPal IPN transaction data</param>
             ''' <param name="log">The <see cref="T:Rolosoft.IpnEasy.Net.Log"/> of the PayPal IPN interaction</param>
             <OperationBehavior(TransactionAutoComplete := True)> _
             Public Sub SubmitIpn(transaction As Transaction, log As Log)
                 OnPayPalIpnReceived(transaction, log)
             End Sub
     
             #End Region
     
             Public Overrides Sub StartWatching()
                 'sEndpointAddress is the location of the MSMQ.
                 Dim sEndpointAddress = "net.msmq://localhost/paypaltransactions"
                 Dim endpointUri = New Uri(sEndpointAddress)
     
                 Dim serviceBinding = New NetMsmqBinding("ThisMsmqBinding")
     
                 _serviceHost.AddServiceEndpoint(GetType(IIpnReceivedContract), serviceBinding, endpointUri)
     
                 _serviceHost.Open()
             End Sub
     
             Public Overrides Sub StopWatching()
                 If _serviceHost IsNot Nothing Then
                     _serviceHost.Close()
                 End If
             End Sub
     
     
             Public Sub Close()
                 Dispose()
             End Sub
     
             Protected Overrides Sub Finalize()
                 Try
                     Dispose()
                 Finally
                     MyBase.Finalize()
                 End Try
             End Sub
     
             Protected Overridable Sub Dispose(disposing As Boolean)
                 If Not disposing Then
                     Return
                 End If
                 If _disposed Then
                     Return
                 End If
                 If _serviceHost Is Nothing Then
                     Return
                 End If
                 _serviceHost.Close()
                 _disposed = True
             End Sub
     
             #End Region
        End Class
    End Namespace
  8. The WCF listener is now ready for use. In the following example we show how to host the WCF listener in a Windows Service and invoke a Windows Workflow (WF) on receipt of a PayPal IPN.

    Create Code\Services\PaymentWorkRouter.cs

    CopyC#
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.ServiceProcess;
    using System.Threading;
    using System.Workflow.Runtime;
    using MyProject.Code.Watchers;
    using MyProject.WorkFlows.PayPalIpnWorkflow; //This code sample is not available. Please implement your own workflow
    
    namespace MyProject.Services.PaymentWorkRouter.Services
    {
        partial class PayPalIpnListener : ServiceBase
        {
    -        #region Privates
     
             //Note: Define your own configuration section handler to set up WF connections, tracking and persistence services.
             private const string ConfigSectionName = "MyRuntime";
     
             private readonly PayPalIpnItemWatcher _watcher;
     
             #endregion
    
    
    -        #region Ctors
     
             public PayPalIpnListener()
             {
                 _watcher = new WcfQueuingPayPalIpnItemWatcher();
                 PayPalIpnItemWatcher.PayPalIpnReceived += PayPalIpnItemWatcherPayPalIpnReceived;
                 InitializeComponent();
             }
     
             #endregion
    
    
    -        #region Methods
     
             static void PayPalIpnItemWatcherPayPalIpnReceived(object sender, PayPalIpnItemFoundEventArgs e)
             {
                 using (var reset = new AutoResetEvent(false))
                 {
                     using (var runtime = new WorkflowRuntime(ConfigSectionName))
                     {
                         runtime.WorkflowCompleted += delegate { reset.Set(); };
                         runtime.WorkflowTerminated += delegate { reset.Set(); };
                         runtime.WorkflowAborted += delegate { reset.Set(); };
     
                         // Pass the PayPal IPN transaction data into the workflow
                         var parms = new Dictionary<string, object>
                                         {
                                             {"PayPalTransaction", e.PayPalTransaction}
                                         };
     
                         //Note: Please implment your own workflow and invoke it here.
                         var instance = runtime.CreateWorkflow(typeof (IpnManager), parms);
     
                         // Start the workflow & process the IPN
                         instance.Start();
                         reset.WaitOne();
                     }
                 }
             }
     
             protected override void OnStart(string[] args)
             {
                 _watcher.StartWatching();
                 base.OnStart(args);
             }
     
             protected override void OnStop()
             {
                 _watcher.StopWatching();
                 WriteLineConsole("Stopped looking for work");
                 base.OnStop();
             }
     
             protected override void OnPause()
             {
                 _watcher.StopWatching();
                 base.OnPause();
             }
     
             protected override void OnContinue()
             {
                 _watcher.StartWatching();
                 base.OnContinue();
             }
             #endregion
        }
    }
    CopyVB.NET
    Imports System.Collections.Generic
    Imports System.Diagnostics
    Imports System.ServiceProcess
    Imports System.Threading
    Imports System.Workflow.Runtime
    Imports MyProject.Code.Watchers
    Imports MyProject.WorkFlows.PayPalIpnWorkflow
    'This code sample is not available. Please implement your own workflow
    Namespace MyProject.Services.PaymentWorkRouter.Services
        Partial Class PayPalIpnListener
            Inherits ServiceBase
    -        #Region "Privates"
     
             'Note: Define your own configuration section handler to set up WF connections, tracking and persistence services.
             Private Const ConfigSectionName As String = "MyRuntime"
     
             Private ReadOnly _watcher As PayPalIpnItemWatcher
     
             #End Region
    
    
    -        #Region "Ctors"
     
             Public Sub New()
                 _watcher = New WcfQueuingPayPalIpnItemWatcher()
                 AddHandler PayPalIpnItemWatcher.PayPalIpnReceived, AddressOf PayPalIpnItemWatcherPayPalIpnReceived
                 InitializeComponent()
             End Sub
     
             #End Region
    
    
    -        #Region "Methods"
     
             Private Shared Sub PayPalIpnItemWatcherPayPalIpnReceived(sender As Object, e As PayPalIpnItemFoundEventArgs)
                 Using reset = New AutoResetEvent(False)
                     Using runtime = New WorkflowRuntime(ConfigSectionName)
                         runtime.WorkflowCompleted += Function() Do
                             reset.[Set]()
                         End Function
                         runtime.WorkflowTerminated += Function() Do
                             reset.[Set]()
                         End Function
                         runtime.WorkflowAborted += Function() Do
                             reset.[Set]()
                         End Function
     
                         ' Pass the PayPal IPN transaction data into the workflow
                         Dim parms = New Dictionary(Of String, Object)() From { _
                             {"PayPalTransaction", e.PayPalTransaction} _
                         }
     
                         'Note: Please implment your own workflow and invoke it here.
                         Dim instance = runtime.CreateWorkflow(GetType(IpnManager), parms)
     
                         ' Start the workflow & process the IPN
                         instance.Start()
                         reset.WaitOne()
                     End Using
                 End Using
             End Sub
     
             Protected Overrides Sub OnStart(args As String())
                 _watcher.StartWatching()
                 MyBase.OnStart(args)
             End Sub
     
             Protected Overrides Sub OnStop()
                 _watcher.StopWatching()
                 WriteLineConsole("Stopped looking for work")
                 MyBase.OnStop()
             End Sub
     
             Protected Overrides Sub OnPause()
                 _watcher.StopWatching()
                 MyBase.OnPause()
             End Sub
     
             Protected Overrides Sub OnContinue()
                 _watcher.StartWatching()
                 MyBase.OnContinue()
             End Sub
             #End Region
        End Class
    End Namespace