Workflow Applications

Application types

The following application types are covered in this section:

  • Web procedures

  • Asynchronous web procedures

The following application types are not covered in this section:

  • Incoming webhooks

  • Non-interactive clients

  • SOAP web services

  • WCF services

  • Web applications

How it works

When an action using a workflow application is launched, WorkflowGen sends the parameters in a JSON or XML file (depending on the context format previously chosen during the creation of the application) to the application using the HTTP protocol. The application uses the JSON or XML file to get the parameters and executes its operations. Once the application is done, a JSON or XML file with the OUT parameters is sent back to WorkflowGen. JSON is supported by Webproc and Webproc Async applications. For web services, the SOAP protocol is used to communicate with the application. Web services that don’t use the SOAP protocol to communicate with WorkflowGen application will be referred as WebProc applications.

Note: The JSON context is supported as of WorkflowGen version 7.0.0.

Requirements for .NET development

.NET Framework version

The WorkflowGen.My assembly requires .NET Framework 4.

WorkflowGen.My assembly

In order to implement a custom workflow application using the .NET Framework, you must have the latest version of WorkflowGen.My 3.x referenced in your project. To directly reference an assembly in your web project, do the following:

  1. Create a \bin directory under your project root folder (e.g. \wfgen\wfapps\sdk\MyProject\bin).

  2. Copy the "WorkflowGen.My.dll" file to this folder.

  3. Right-click on your project name and choose Add reference...

  4. Click Browse.

  5. Navigate to the \bin directory you created and choose the "WorkflowGen.My.dll" file, then click OK. WorkflowGen.My is now referenced in your project.

You can also put this assembly in your GAC (Global Assembly Cache) in order to have only one centralized reference, instead of referring to a copy of the assembly in each project. To install the assembly in your GAC, do the following:

  1. Copy "WorkflowGen.My.dll" to DRIVE:\Windows\system32.

  2. Open a command prompt and browse to DRIVE:\Program Files (x86)\Microsoft Visual Studio 14.0\SDK\v3.5\Bin.

  3. Enter the command gacutil /i c:\windows\system32\WorkflowGen.My.dll, then press ENTER. WorkflowGen.My is now in your GAC.

If you want to use an assembly from the GAC, you should drop your assemblies into a local folder, and then add a reference to the assembly from this folder. You may want to set the Copy Local property to False for that assembly if you don't want the assembly to be copied locally to your project folders. At runtime, the application will automatically use the assembly from the GAC.

Important: WorkflowGen.My.dll 3.4.0 and later requires Newtonsoft.Json.dll in the same BIN or GAC.

Configuration settings (app.config or web.config)

The WorkflowGen.My assembly does not require any particular configuration settings.

Deploying a custom assembly

There are some considerations when deploying a custom assembly SDK workflow application in WorkflowGen, namely the assembly location, the reference to WorkflowGen.My, and references to other software libraries.

Assembly location

There are two ways of deploying an assembly file in WorkflowGen.

Method 1: Reference by assembly’s full name

The assembly file must be copied to the three bin folders containing the WorkflowGen executable files: \wfgen\bin, \wfgen\ws\bin, and DRIVE:\Program Files\Advantys\WorkflowGen\Services\bin.

Method 2: Reference by assembly’s path (full physical path with file name)

The assembly file can be copied to a custom folder such as DRIVE:\MyWorkflowApps\Assembly.dll, and then use that specific path in the workflow application’s definition.

Important: If your custom assembly has dependencies, they must be located in the same folder as the assembly.

Reference to WorkflowGen.My

WorkflowGen.My v3.1.0 and earlier

WorkflowGen.My versions 3.1.0 and earlier are strong-named, which means your assembly must be built with and use the same version as your target WorkflowGen. This requires recompiling your assembly whenever you upgrade WorkflowGen to a newer version.

You can use one of the following workarounds to overcome this requirement:

  1. Install the required WorkflowGen.My version in the system's global assembly cache (GAC). For instructions on how to do this, see the How to: Install an assembly into the global assembly cache Microsoft article. OR

  2. Add a delegate to handle the assembly resolve event in order to load the current WorkflowGen.My version. For instructions on how to do this, see the How to add an assembly resolve event delegate to overcome WorkflowGen.My dependency issue when deploying custom assembly SDK workflow application article on the WorkflowGen Forum & Knowledge Base. OR

  3. Add a web configuration setting to redirect the required version to the current version of WorkflowGen.My. For more information, see the <assemblyBinding> Element for <runtime> Microsoft article.

Note: If your assembly is built with WorkflowGen.My v3.1.0 or earlier, it can be used in WorkflowGen version 6.2.0 and later if one of the above workarounds has been implemented.

WorkflowGen.My v3.2.0 and later

As of version 3.2.0, WorkflowGen.My is no longer strong-named in order to allow non-specific version dependency when referenced by your assembly. You can simply deploy your assembly file using one of the two methods in the Assembly location section above in WorkflowGen 6.2.0 and later.

Note: If your assembly is built with WorkflowGen.My v3.2.0 or later, it can be used in WorkflowGen versions prior to 6.2.0 if you have implemented either workaround 2 or 3 above.

References to other software libraries

If your assembly uses third-party libraries, then these must also be deployed into the three WorkflowGen executable \bin folders. Alternatively, they can be installed into the system’s global assembly cache (GAC) if they are strong-named assemblies.

WorkflowContext

WorkflowContext is a JSON or XML data structure used to exchange parameters with WorkflowGen. The context format is used by both web procedures and asynchronous web procedures.

For an example of an XML ADO.NET dataset context, see WorkflowContext in the Web services API section.

As of WorkflowGen 7.0.0, the application can build ContextParameters instances from JSON strings. The JSON should respect the following structure:

JSON example:

{
"ReplyToUrl": "",
  "Parameters": [
    {
      "Name": "DATE",
      "DataType": "DATETIME",
      "Direction": "IN",
      "TextValue": null,
      "NumericValue": null,
      "DateTimeValue": "2017-01-06T14:23:00Z",
      "FileValue": null
    },
    {
      "Name": "FILE",
      "DataType": "FILE",
      "Direction": "IN",
      "TextValue": null,
      "NumericValue": null,
      "DateTimeValue": null,
      "FileValue": {
        "Name": "TestFile.txt",
        "ContentType": "text/plain",
        "Size": 616,
        "Url": "C:\TestFile.txt"
      }
    },     
    {
      "Name": "NUMBER",
      "DataType": "NUMERIC",
      "Direction": "IN",
      "TextValue": null,
      "NumericValue": 20.54,
      "DateTimeValue": null,
      "FileValue": null
    },
    {
      "Name": "TEXT",
      "DataType": "TEXT",
      "Direction": "IN",
      "TextValue": "This is a test",
      "NumericValue": null,
      "DateTimeValue": null,
      "FileValue": null
    }
  ]
}

WorkflowContext creation with WorkflowGen.My

Loading the WorkflowGen context

In order to manipulate a WorkflowGen context, it is necessary to load it into a ContextParametersobject instance. Usually, you will receive the context in a string variable. Follow these steps to load the WorkflowGen context into a new ContextParameters object instance.

To load the context, you only have to build a new ContextParameters instance. The following sample code loads the context from a workflowGenContext string:

C#

ContextParameters contextHandler = new ContextParameters(workflowGenContext);

Reading a data parameter from the context

You can access any data parameter in the WorkflowGen context by using the contextHandler (ContextParameters instance) that you created in the previous section.

When you access a single parameter, you store it in a ContextParameter object to manipulate it.

Get a particular parameter from the context

To access a particular parameter from the context, use the ContextParameters indexer. The following example accesses a DATE_EXAMPLE parameter in the previously loaded context:

C#

ContextParameter dateParameter = contextHandler["DATE_EXAMPLE"];

Get the ContextParameter value

To access the value of the context parameter, use the Value property of the ContextParameter instance that you retrieved in the previous section.

C#

ContextParameter dateParameter = contextHandler["DATE_PARAMETER"];
DateTime dateValue = (DateTime)dateParameter.Value;

The dateValue variable now contains the DATE_EXAMPLE parameter value.

Filtering the ContextParameters collection

Suppose that you would like to iterate over all the "IN" parameters of the ContextParameters instance. You could do this by using a filter, and then by using the collection enumerator. Don't forget to remove the filter afterward, or else you won't be able to access the other parameters.

C#

contextHandler.ApplyFilter(ContextParameter.Directions.In, ContextParameters.ComparisonOperators.Equals);
foreach (ContextParameter inParameter in contextHandler)
{
   // Do something here with each "inParameter" variable
}
contextHandler.RemoveFilter();

Modifying a parameter value in the context

After you have stored your data parameter in a ContextParameter, you can modify its value.

C#

ContextParameter dateParameter = contextHandler["DATE_PARAMETER"];
dateParameter.Value = System.DateTime.Now;
contextHandler.Update("DATE_PARAMETER");

Note: If you try to modify a parameter with the wrong data type, you will only receive an exception when you try to serialize the context back to a JSON or XML string.

Adding a parameter to the context

In order to add a parameter to the context, you need to build a new ContextParameter instance, define its name and direction, and then add it to the ContextParameters instance you already have.

C#

ContextParameter newOutParameter = new ContextParameter(typeof(DateTime), DateTime.Now);
newOutParameter.Name = "SAMPLE_OUT_PARAM";
newOutParameter.Direction = ContextParameter.Directions.Out;
contextHandler.Add(newOutParameter);
contextHandler.Update();

Working with file parameters

File parameters need to be put into a ContextFileReference instance. The following is an example that extracts a file parameter value into a ContextFileReference, then modifies the file parameter so that it points to another sample file.

C#

ContextParameters cps = new ContextParameters(context);
ContextFileReference cfr = new ContextFileReference();
FileInfo fi = new FileInfo(@"c:\TestFile.txt");
cfr.Name = fi.Name;
cfr.Description = fi.Name;
cfr.Path = fi.FullName;
cfr.OriginalPath = fi.FullName;
cfr.ContentType = "text/plain";
cfr.DateLastModified = fi.LastWriteTimeUtc;
cfr.Size = fi.Length;
cps["FILE_OUT"].Value = cfr;
cps.Update();

Web procedure development using an ASP.NET XML web service

Overview

The most widely-used type of WorkflowGen integration is the web procedure. Web procedures are used to receive a WorkflowGen context as a parameter, manipulate it, and then return the modified context to WorkflowGen.

Note: As of WorkflowGen 7.0.0, the term "web services" is only used to refer to web services using the SOAP protocol; all others are referred to as web procedures.

Creating the web procedure

Suggested development tools

  • Visual Studio Standard or Professional 2013 or later

Web procedure installation directory

We strongly suggest that you put all of your web services in the \wfgen\wfapps\WebServices\MyWebProc folder.

Be aware that if you modify your WorkflowGen process and you need to modify the associated MyWebProc because of those changes, you should duplicate MyWebProc beforehand and create another IIS application, otherwise the two versions of the process will use the same modified MyWebProc.

Creating the application in IIS

The web service directory must be declared as an application in IIS in order to be recognized as a .NET web service application. To declare your web service directory as an IIS application, do the following:

For IIS 7 and later

  1. Open Internet Information Services (IIS) Manager.

  2. Navigate to your web form location, which should be under the Default Web Site node, under \wfgen\wfapps\webservices\MyWebProc.

  3. Right-click on MyWebProc and choose Convert to Application.

  4. Select the application pool used by your site and another specific application pool.

  5. Click OK.

Creating a web procedure workflow application using an ASP.NET XML web service

You can create a web procedure using an ASP.NET web service, but this Visual Studio template is only available for .NET versions 2.0 to 3.5.

  1. Open Visual Studio.

  2. Select File > New Web Site.

  3. Choose ASP.NET Web Service (available for .NET Framework versions 2.0 to 3.5).

  4. Choose File system from the Location drop-down list.

  5. Click Browse and choose the location of your ASP.NET website.

  6. Click OK.

Obtaining detailed error messages

In order to be able to see complete error messages, change the following properties in the "web.config" file:

Make sure this line is set to true:

<compilation debug="true" />

Make sure this is not commented and that the mode="Off":

<customErrors mode="Off" defaultRedirect="GenericErrorPage.htm">
    <error statusCode="403" redirect="NoAccess.htm" />
    <error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>

Authorize GET and POST protocols

In order to use a web service with WorkflowGen, the GET and POST protocols must be enabled in the "web.config" file of the web service. The following are the necessary nodes to insert in your "web.config", in the system.web node:

<webServices>
    <protocols>
        <add name="HttpGet"/>
        <add name="HttpPost"/>
    </protocols>
</webServices>

Configure the IIS rendering framework version in the "web.config" file

You will need to revert to the behavior of having only .aspx pages trigger request validation by adding the following code to your "web.config" file:

<httpRuntime requestValidationMode="2.0" />

Basic implementation

Overview

In order to demonstrate how to implement a web procedure that process a context from WorkflowGen, we'll build a simple web service that converts an amount in Euros to an amount in U.S. dollars.

Reference

You must add a reference to WorkflowGen.My.dll in your web project, and then add a "using" statement (for the WorkflowGen.My.Data namespace of the WorkflowGen.My assembly. For example:

C#

using WorkflowGen.My.Data;

Specifying your class signature

If you want to receive a JSON formatted context, you should add the following signature, located in the "App_Code\Service.cs" file, to your web procedure's Service class (note that ScriptService signatures aren't required for other context formats). Your service class should look like this:

[WebService(Namespace = "http://tempuri.org/")]
[System.Web.Script.Services.ScriptService]
public class Service : System.Web.Services.WebService

Specifying your web method signature

Only the methods that have the WebMethod attribute can be remotely executed. The default web method signature which is created with your web service should look like this:

C#

[WebMethod]
public string HelloWorld()

We'll modify this signature name and add a parameter, which will be the WorkflowGen context. Any web procedure you create will only need this one context parameter for each web method you create.

C#

[WebMethod(Description="Convert the amount in Euro into an amount in U.S. Dollars.")]
public string Convert(string WFGEN_CONTEXT)

If you web procedure response returns the context with JSON format, you can add the [ScriptMethod] signature to your web methods. In this case, the context will be returned by the method using the JSON format (enclosed by { }).

C#

[WebMethod(Description="Convert the amount in Euro into an amount in U.S. Dollars.")]
[System.Web.Script.Services.ScriptMethod(ResponseFormat = System.Web.Script.Services.ResponseFormat.Json)]
public string Convert(string WFGEN_CONTEXT)

Otherwise, you don’t add the [ScriptMethod] signature and convert your returned context directly to JSON in your code. You can use a library such as Newtonsoft.Json to serialize your context.

Note: The parameter name should always be WFGEN_CONTEXT, which is case sensitive.

Variable and constant declarations

Now, we'll declare the variables we need and retrieve the exchange rate from the "web.config" file. This is the necessary code in the "web.config" file to add the ExchangeRate key:

<configuration>
    <appSettings>
        <add key="ExchangeRate" value="1.1975"/>
    </appSettings>
...

C#

// Configuration constants
double exchangeRate;

// Variables and Declaration
double amountEuro;

// Initialize the variables
amountEuro = 0;

// Get values into Configuration constants
exchangeRate =
System.Convert.ToDouble(System.Web.Configuration.WebConfigurationManager.AppSettings["
ExchangeRate"]);

Loading the WorkflowGen context

The next thing to do is create a ContextParameters instance that will be used to work with the WorkflowGen context we are receiving as a parameter.

C#

// Create a new object of ContextParameters and Load the Context
WorkflowGen.My.Data.ContextParameters myWorkflowContextParameters;
myWorkflowContextParameters= new WorkflowGen.My.Data.ContextParameters(WFGEN_CONTEXT);

Managing errors

Our web procedure needs to receive two parameters: AMOUNT_DOLLARS (OUT) and AMOUNT_EURO (IN). If one of these parameters is missing, we have to inform the end-user that they forgot to pass these parameters to the web service. The only way to stop the web procedure execution and to send an error message back to WorkflowGen is to throw a new SoapException. We'll now verify if the user provided the AMOUNT_EURO parameter before getting the value from it. If the user did not provide it, we send a new SoapException to WorkflowGen with a clear message.

C#

// Check whether parameter exists
if (myWorkflowContextParameters.Contains("AMOUNT_EURO"))
{
    ...
}
// If no Euro amount then generate an error
else
{
    throw new SoapException("SDK_WEBSERVICETEST Error: 'AMOUNT_EURO' parameter is required", SoapException.ServerFaultCode);
}

Retrieving the AMOUNT_EURO parameter from the context

We'll now get the AMOUNT_EURO value into our amountEuro double variable, and at the same time, we will verify that the value is not null, if so, we will send another exception.

C#

// Get the value of 'AMOUNT_EURO' if not null
if (myWorkflowContextParameters["AMOUNT_EURO"].Value != null)
{
    // Get the value of 'AMOUNT_EURO' into the amountEuro variable
    amountEuro = (double)myWorkflowContextParameters["AMOUNT_EURO"].Value;
}
else
{
    // If Euro amount is null generate an error
    throw new SoapException("SDK_WEBSERVICETEST Error: 'AMOUNT_EURO' parameter must not be null", SoapException.ServerFaultCode);
}

Modifying the AMOUNT_DOLLARS parameter with the new value

We will now modify the AMOUNT_DOLLARS parameter with the AMOUNT_EURO value modified using the exchangeRate variable.

C#

// Check whether parameter exists
if (myWorkflowContextParameters.Contains("AMOUNT_DOLLARS"))
{
    // Convert
    myWorkflowContextParameters["AMOUNT_DOLLARS"].Value = amountEuro * exchangeRate;
}
// If no Dollars amount then generate an error
else
{
    throw new SoapException("SDK_WEBSERVICETEST Error: 'AMOUNT_DOLLARS' parameter is required", SoapException.ServerFaultCode);
}

// Updating the context parameters
myWorkflowContextParameters.Update();

Returning the modified context to WorkflowGen

Now that we have processed the context, we need to return the context back to WorkflowGen. Here is the necessary code to return the context depending on the context format you choose when creating or editing your WorkflowGen application:

C#

// Return the WorkflowGen context in JSON format
return myWorkflowContextParameters.GetJson();

OR

// Return the WorkflowGen context in XML format
return myWorkflowContextParameters.GetXml();

Asynchronous web procedure development in .NET Framework

Overview

The asynchronous procedures allow a WorkflowGen system action to be run asynchronously, meaning that the action is initiated at some point in time during the workflow and can be completed at a later instance by an external application.

This type of asynchronous processing can be used in cases where a system action, like a Web service, can time out or cause the UI to hang while processing a large volume of information.

This section will explain how to develop an asynchronous web procedure application by using WorkflowGen.My v3.3. The development will have two different parts: a web procedure that receives and processes the context, and a listener to complete and close the open action (a console application in this example).

Creating the asynchronous website

Suggested development tools

  • Visual Studio Standard or Professional 2013 or later

Website installation directory

We strongly suggest that you put all your asynchronous web procedure SDK in the \wfgen\wfapps\WebServices\sdk\MyWebProcAsync folder.

Creating the application in IIS

The website directory must be declared as an IIS application in order to be recognized as a .NET website application. Follow these instructions to declare your website directory as an IIS application:

For IIS 7 and later

  1. Open Internet Information Services (IIS) Manager.

  2. Navigate to your web form location, which should be placed under the Default Web Site node, under wfgen/wfapps/WebServices/sdk/MyWebProcAsync.

  3. Right-click on MyWebProcAsync and choose Convert to Application.

  4. Select the application pool used by your site and another specific application pool.

  5. Click OK.

Create the project with Visual Studio

Creating the project

  1. Open Visual Studio.

  2. Select File > New Web Site.

  3. Choose ASP.NET Web Site.

  4. Chose File system from the Location drop-down list.

  5. Click Browse and choose the location of your ASP.NET website.

  6. Click OK.

Obtaining detailed error messages

In order to be able to see complete error messages, change the following properties in the "web.config" file:

  1. Make sure this line is set to "true":

    ```

    ```

  2. Make sure this is not commented and that the mode="Off".

    <customErrors mode="Off" defaultRedirect="GenericErrorPage.htm">
         <error statusCode="403" redirect="NoAccess.htm" />
         <error statusCode="404" redirect="FileNotFound.htm" />
    </customErrors>

Basic implementation

Overview

In order to demonstrate how we can implement an asynchronous web procedure application, we have developed a simple ASP.NET website example that receives a context containing three IN parameters: ACTION_ID, REQUEST_ID, and AMOUNT_EURO, and the OUT parameter AMOUNT_DOLLARS. The web application processes the incoming parameters, in order to convert the AMOUNT_EURO value into dollars.

You must add a reference to "WorkflowGen.My.dll" in your web project, then add a using statement for the WorkflowGen.My.Data namespace of the WorkflowGen.My assembly.

C#

using WorkflowGen.My.Data;
Defining Page_Load event

We'll use the Page_Load event in code-behind to immediately start the asynchronous web procedure. Inside the Page_Load event, you should get the application string context and make the needed conversion to get a JSON or XML string. Be aware that WorkflowGen will send the context to your external application formatted in dependence of your chosen context format and context type when creating or editing your application in WorkflowGen application form.

For example, if you choose JSON context with application/json content type, your incoming payload will have the following structure:

{
    WFGEN_CONTEXT:{
        "ReplyToUrl":"http://localhost/wfgen/show.aspx?QUERY=APPLICATION_COMPLETE\u0026ID_PROCESS_INST=1655\u0026ID_ACTIVITY_INST=1\u0026ENCTYPE=application%2fjson\u0026ID_APP_TYPE=WEBPROCASYNC",
    "Parameters":[{
        "Name":"ACTION_ID",
        "DataType":"NUMERIC",
        "Direction":"IN",
        "TextValue":null,
        "NumericValue":1,
        "DateTimeValue":null,
        "FileValue":null
        },
        {
        "Name":"AMOUNT_DOLLARS",
        "DataType":"NUMERIC",
        "Direction":"OUT",
        "TextValue":null,
        "NumericValue":200,
        "DateTimeValue":null,
        "FileValue":null
    },
    ]
    }
}

In this case, you can read the HTTP Request body content, and convert it to a valid JSON string (in this example we use the Newtonsoft.Json library to serialize/deserialize JSON files). Afterwards, we pass the correctly formatted context into a method named StartAsynchronousAction that will process the context parameters.

C#

protected void Page_Load(object sender, EventArgs e)
{
    string input;
    using (StreamReader reader = new StreamReader(Request.InputStream))
    {
        input = reader.ReadToEnd();
    }
    JSON content type
    JObject context = JObject.Parse(input);

    string WFGEN_CONTEXT = (string)context["WFGEN_CONTEXT"];

    // Start the asynchronous processing
    StartAsynchronousAction(WFGEN_CONTEXT);
}
public void StartAsynchronousAction(string WFGEN_CONTEXT)

In the case of ADO.NET DataSet WorkflowGen Context, the context is obtained directly from the HTTP Request and passed to the StartAsynchronousAction method.

C#

protected void Page_Load(object sender, EventArgs e)
{
    // Start the asynchronous processing
    StartAsynchronousAction(Request["WFGEN_CONTEXT"]);
}

public void StartAsynchronousAction(string WFGEN_CONTEXT)

Using the "web.config" to store your configurations

It is suggested to use the "web.config" file to store all the configurations, instead of hard coding them directly in your website's code-behind. In this case, you should add the ExchangeRate key and its value in the "web.config" file to use it in the application currency conversion:

<appSettings>
    <add key="ExchangeRate" value="2.0"/>
</appSettings>

If you will be storing your application context in a database, you will need to add the connectionString node to the "web.config" file:

<connectionStrings>
    <add name="WebProcAsyncConnectionString:  connectionString="[ADD YOUR DATABASE CONNECTION STRING]"/
</connectionStrings>

This is the code that declares all the variables needed for the asynchronous web procedure, and then gets the "web.config" values to populate some of these variables.

C#

// Variables and declaration
double exchangeRate;
double amountEuro;
string encType;
string replyTo;
string fileDelete;
string result;
string requestId;
string actionId;

In this example, some variables takes their values from the database.

// Initialize the variables
encType = Request.QueryString["WFGEN_ENCTYPE"];
replyTo = Request.QueryString["WFGEN_REPLY_TO"];

fileDelete = "Y";
amountEuro = 0;
result = "";
requestId = "";
actionId = "";

// Get values from Configuration constants
exchangeRate = System.Convert.ToDouble(System.Web.Configuration.WebConfigurationManager.AppSettings["ExchangeRate"]);

Building a context

We now need to build a new context to send to WorkflowGen to complete the asynchronous action. Here is the necessary code to create a new context:

C#

// Create a new WorkflowGen object for context parameters
WorkflowGen.My.Data.ContextParameters myWorkflowContextParameters = new
WorkflowGen.My.Data.ContextParameters();

// Load the context into a ContextParameters object
WorkflowGen.My.Data.ContextParameters context
WorkflowGen = new WorkflowGen.My.Data.ContextParameters(WFGEN_CONTEXT);

You can get the IN parameter values from the ContextParameters instance:

C#

if (contextWorkflowGen.Contains("AMOUNT_EURO"))
{
    // Get the value of 'AMOUNT_EURO' if not null
    if (contextWorkflowGen["AMOUNT_EURO"].Value != null)
    {
        amountEuro = (double)contextWorkflowGen["AMOUNT_EURO"].Value;
    }
else
    {...}
}

Then, the application processes the currency exchange and saves the final value into the AMOUNT_DOLLARS OUT parameter.

C#

if (contextWorkflowGen.Contains("AMOUNT_DOLLARS"))
{
    // Convert euros to dollar amount
    contextWorkflowGen["AMOUNT_DOLLARS"].Value = amountEuro * exchangeRate;
}
else
{...}

// Updating the context parameters
myWorkflowContextParameters.Update();

If the asynchronous web procedure chosen context format is JSON (the default context format), the application result will use this file format:

result = contextWorkflowGen.GetJson();

If the context format is XML ADO.NET DataSet, the returned value will be formatted as XML.

result = base.Server.UrlEncode(contextWorkflowGen.GetXml());

In this example, the variables needed to complete the application will be saved in a database, to be used by the Asynchronous Web Procedure listener.

// Update the database with the request information
UpdateDatabase(requestId, actionId, encType, replyTo, result, fileDelete);

Building the asynchronous web procedure listener

After having created the website used to launch the asynchronous web procedure, we need to develop a listener that will complete the web request, sending the context back to WorkflowGen. In this case, we have developed a console application for this purpose.

The application uses the same database as the web procedure previously developed, and gets the database parameters from there.

C#

// Use the OleDb connection provider
OleDbConnection connection = new OleDbConnection((ConfigurationManager.ConnectionStrings["WebProcAsyncConnectionString"]).ToString());

// Build a command with the SQL query string
OleDbCommand command = new OleDbCommand(ConfigurationManager.AppSettings["WebProcAsyncSql"], connection);

// Open the connection
connection.Open();

// Execute the reader
OleDbDataReader reader = command.ExecuteReader();

// Read the rows are returned by the reader
while (reader.Read())
{
    // Read the database columns
    replyTo = reader["REPLY_TO"].ToString();
    encType = reader["ENCTYPE"].ToString();
    result = reader["RESULT"].ToString();
    requestNumber = reader["ID_REQUEST"].ToString();
}

The application sets the status to CLOSE for the asynchronous web procedure in the database.

using (OleDbConnection connection = new OleDbConnection((ConfigurationManager.ConnectionStrings["WebProcAsyncConnectionString"]).ToString()))
{
    // Build a command with the SQL query string
    OleDbCommand command = new OleDbCommand("UPDATE WF_ASYNC SET REQUEST_STATUS = 'CLOSED' WHERE ID_REQUEST ='" + requestNumber + "'", connection);

    // Open the connection
    connection.Open();

    // Execute the update
    command.ExecuteNonQuery();
}

The console application then sends the context back to WorkflowGen.

// Initialize method variables
string wfgBaseUrl = "";
string wfgDomain = "";
string wfgUserName = "";
string wfgPassword = "";
string response = null;
string postData = "";
byte[] buffer;

System.Net.HttpWebRequest httpWebRequest = null;
System.Net.HttpWebResponse httpWebResponse = null;
System.Net.NetworkCredential myCred = null;
System.Text.ASCIIEncoding encoding = null;
System.IO.Stream myStream = null;
System.IO.StreamReader myReader = null;

try
{
    // Get all the parameters from the config file
    wfgBaseUrl = ConfigurationManager.AppSettings["WorkflowGenBaseUrl"].ToString();
    wfgDomain = ConfigurationManager.AppSettings["WorkflowGenDomain"].ToString();
    wfgUserName = ConfigurationManager.AppSettings["WorkflowGenUsername"].ToString();
    wfgPassword = ConfigurationManager.AppSettings["WorkflowGenPassword"].ToString();

    // Submit the parameters
    myCred = new System.Net.NetworkCredential(wfgUserName, wfgPassword, wfgDomain);

    // Build the Http Request object
    httpWebRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(replyTo);

    // Set context content  
    postData += "WFGEN_RESULT=" + result;

    // Set authentication information
    httpWebRequest.Credentials = myCred;
    httpWebRequest.Method = "POST";

    // Set the encoding
    encoding = new System.Text.ASCIIEncoding();
    buffer = encoding.GetBytes(postData);

    // Set the content type of the data being posted
    httpWebRequest.ContentType = encType;

    // Set the content length of the string being posted
    httpWebRequest.ContentLength = postData.Length;

    // Try block to handle exception
    try
    {
        // Send the context
        myStream = httpWebRequest.GetRequestStream();
        myStream.Write(buffer, 0, buffer.Length);

        // Close the stream
        myStream.Close();

        // Get the response from WorkflowGen
        httpWebResponse = (System.Net.HttpWebResponse)httpWebRequest.GetResponse();

        // Check if any error has occured in WFG
        if (httpWebResponse.ContentLength !=  0)
        {
            // Read the response stream
            myReader = new System.IO.StreamReader(httpWebResponse.GetResponseStream());
            response = myReader.ReadToEnd();

            // Write degbugging information to the log
            WriteDebugLog("Error returned by WFG: " + response);
            return false;
        }

        // Close the response object
        httpWebResponse.Close();
    }
catch (WebException e)
{
...}

Note that the POST method content would have the following structure:

"WFGEN_RESULT=" + [string context]

and the context has to be formatted according to the asynchronous web procedure content type. In the case of JSON, the JSON string has to respect the JSON parameter structure explained earlier.

Starting the process and sending the context

After having created the context, we need to make a web request to WorkflowGen to start the remote process, and we also need to post the context to the new process instance. Here is the necessary code:

C#

// Call WorkflowGen to instantiate the process
// Prepare the URL
appUrl = workflowGenLaunchUrl + "&L=" + language + "&PROCESS=" + processName + "&REQUESTER_USERNAME=" + requesterUsername + "&TEST=" + test;

// Submit the parameters
myCred = new System.Net.NetworkCredential(workflowGenUsername,workflowgenUserPassword, workflowGenUserDomain);
myCache = new System.Net.CredentialCache();
myCache.Add(new Uri(workflowGenLaunchUrl), "Basic", myCred);

// Prepare a request
httpWebReq = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(appUrl);
httpWebReq.Method = "POST";

// Set authentication information
httpWebReq.Credentials = myCache;

// Set CONTEXT content
postData = "CONTEXT=" + HttpUtility.UrlEncode(workflowContextXml.ToString());
encoding = new System.Text.ASCIIEncoding();
buffer = encoding.GetBytes(postData);

// Set the content type of the data being posted.
httpWebReq.ContentType = "application/x-www-form-urlencoded";

// Set the content length of the string being posted.
httpWebReq.ContentLength = postData.Length;

// Send the CONTEXT
myStream = httpWebReq.GetRequestStream();
myStream.Write(buffer, 0, buffer.Length);

// Close the Stream object.
myStream.Close();

Managing errors

After starting the process, you might receive errors from WorkflowGen if something is not working as expected. Here is the necessary code to display the WorkflowGen error so that you can debug your RemoteLaunch application:

C#

// Try block to handle exception
try
{
    // Check the WorkflowGen response status
    httpWebResp = (System.Net.HttpWebResponse)httpWebReq.GetResponse();
}

// Catch the exception
catch (WebException e)
{
    // Display the error message
    Response.Write(e.ToString());
    return;
}

respCode = "OK"; // response code variable

// Check the response status code is OK
if (respCode != httpWebResp.StatusCode.ToString())
{
    // Display the Error details
    Response.Write("Error:" + httpWebResp.StatusCode);
}
else
{
    // Gets the stream associated with the response
    httpWebResp = (System.Net.HttpWebResponse)httpWebReq.GetResponse();
    myReader = new System.IO.StreamReader(httpWebResp.GetResponseStream());
    response = myReader.ReadToEnd();
    httpWebResp.Close();

// Display response message
Response.Write(response);
}

Managing errors

It is advised to prepare your code to get errors in case they occur; especially when the context is sent, it is useful to know all details in case of error.

C#

try
{
    // Send the context
...}
catch (WebException e)
{
    // Read the error message
    httpWebResponse = (System.Net.HttpWebResponse)e.Response;
    myReader = new System.IO.StreamReader(httpWebResponse.GetResponseStream());
    response = myReader.ReadToEnd();

    // Write error details to the log file
    WriteDebugLog("Error while sending response to the server: " + response);
    return false;
}

Last updated