Keyvan Nayyeri

God breathing through me

Invoke a WebService from a Workflow

Last week I wrote about an open source project for WCF activities for Windows Workflow Foundation and mentioned that there is a default activity to invoke webservices from them.  In this post I want to talk about this topic.

Sample WebService

To illustrate my purpose I use a simple webservice to get a birthdate and return the age as integer value.  Code for webservice is shown below.  Later I'll use this webservice to invoke its GetAge() method from my sample workflow.

using System;

using System.Web;

using System.Web.Services;

using System.Web.Services.Protocols;

 

[WebService(Namespace = "http://tempuri.org/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class Service : System.Web.Services.WebService

{

    public Service()

    {

    }

 

    [WebMethod]

    public int GetAge(DateTime BirthDate)

    {

        int diff = DateTime.Now.Year - BirthDate.Year;

        return (DateTime.Now.Month < BirthDate.Month ||

            ((DateTime.Now.Month == BirthDate.Month)

            && (DateTime.Now.Day < BirthDate.Day))) ? --diff : diff;

    }

}

Is it C#?!

InvokeWebService Activity

InvokeWebService is a default activity in Windows Workflow and allows you to invoke webservices from your workflows easily.  You can simply drag and drop this activity to your workflow to start using it.  Once you drop this activity to your workflow Add Web Reference dialogue appears to ask for a webservice address.  You can put your webservice URL to add a web reference.  In this case it will generate the proxy class and configuration files and sets some properties for you automatically.  You can also cancel this dialogue.  In this case you have to write your own code for proxy class and set all properties manually.

InvokeWebService activity requires four (or more) properties to be set for it:

  • ReturnValue: This is a bind property that must be set to a field in workflow to keep the value that is returned from the webservice method.
  • MethodName: Name of webservice method that can be chosen from a drop down list.
  • ProxyClass: Name of the proxy class for the webservice.  Add Web Reference dialogue sets this property automatically but if you don't use this dialogue then you need to create the proxy class manually and set this property yourself.
  • URL: String value of webservice address.
  • Method Parameters: Your webservice may have no, one or more input parameters with different types.  If it has any input parameter then you must specify them as bind properties for activity.  You can choose from existing fields (Bind to an existing member) in workflow or create new field (Bind to a new member).  If you choose to create a new field then it will generate the code for you automatically.

Now I drag and drop an InvokeWebService activity to my sample workflow and use Add Web Reference dialogue to generate my proxy class automatically.  After this, I choose the right name for my MethodName property (GetAge) and create two new members for my ReturnValue (age) and BirthDate (birthDate) parameters.  Windows Workflow generates codes for these two new members automatically.  At this point my activity can work and invoke my webservice to pass the birthDate parameter and get the result and store it in age property.  But I'm interested to invoke webservice based on user's birthdate so I have to get the birthdate from the user and show the result in console.  In order to do this I add two code activities before (codeActivity1) and after (codeActivity2) my invokeWebServiceActivity1 activity.  My final workflow looks like this:

In codeActivity1 I write a simple code to ask for birthdate from user and read the value of birthDate property from console.

private void codeActivity1_ExecuteCode_1(object sender, EventArgs e)

{

    Console.Title = "Age Service";

    Console.WriteLine("Enter your birthdate:");

    this.birthDate = DateTime.Parse(Console.ReadLine());

}

In codeAcitivity2 I write another simple code to write the value of age property in console.

private void codeActivity2_ExecuteCode(object sender, EventArgs e)

{

    Console.WriteLine("You're {0} years old.", age.ToString());

    Console.ReadLine();

}

So the final code for my workflow (with auto-generated codes for input and output parameters) is this:

public sealed partial class Workflow1 : SequentialWorkflowActivity

{

    public Workflow1()

    {

        InitializeComponent();

    }

 

    public static DependencyProperty birthDateProperty =

        DependencyProperty.Register("birthDate", typeof(System.DateTime),

        typeof(InvokeWebserviceSample.Workflow1));

 

    [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]

    [BrowsableAttribute(true)]

    [CategoryAttribute("Parameters")]

    public DateTime birthDate

    {

        get

        {

            return ((System.DateTime)(base.GetValue(InvokeWebserviceSample.Workflow1.birthDateProperty)));

        }

        set

        {

            base.SetValue(InvokeWebserviceSample.Workflow1.birthDateProperty, value);

        }

    }

 

    public static DependencyProperty ageProperty =

        DependencyProperty.Register("age", typeof(System.Int32),

        typeof(InvokeWebserviceSample.Workflow1));

 

    [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]

    [BrowsableAttribute(true)]

    [CategoryAttribute("Parameters")]

    public Int32 age

    {

        get

        {

            return ((int)(base.GetValue(InvokeWebserviceSample.Workflow1.ageProperty)));

        }

        set

        {

            base.SetValue(InvokeWebserviceSample.Workflow1.ageProperty, value);

        }

    }

 

    private void codeActivity1_ExecuteCode_1(object sender, EventArgs e)

    {

        Console.Title = "Age Service";

        Console.WriteLine("Enter your birthdate:");

        this.birthDate = DateTime.Parse(Console.ReadLine());

    }

 

    private void codeActivity2_ExecuteCode(object sender, EventArgs e)

    {

        Console.WriteLine("You're {0} years old.", age.ToString());

        Console.ReadLine();

    }

}

Now if I run my workflow and enter my birthdate, it can show my age correctly:

Output

Sessions

The other aspect of webservices is around sessions.  You know that ASP.NET webservices (ASMX services) support cookies sessions via cookies in HTTP protocol out of the box and you don't need to take care about details in your webservices.  In your workflows sometimes you want to call a webservice several times and need to keep sessions during all these calls.  Thankfully InvokeWebService activity comes with SessionID property.  This property helps you to keep sessions for all your calls to a webservice from different activities.  To use this property you can simply put a unique string as its value for all activities (simply put a GUID to make sure its unique between all activities).  Windows Workflow will do the rest and makes sure that your activities use same sessions during all calls (if webservice itself supports sessions).

+ After some weeks I wrote something with my old blogging style!  Blogging for future was a good experience during the last month!

Now playing: Chris De Burgh - Saint Peter's Gate

3 Comments

DotNetKicks.com
Mar 30, 2007 1:00 AM
#
You've been kicked (a good thing) - Trackback from DotNetKicks.com

Keyvan Nayyeri
Apr 05, 2007 6:41 AM
#
In one of my recent posts I discussed about Invoking a WebService from a Workflow . The other case is

ElsieQ
Mar 17, 2008 1:13 PM
#

Is there an easy way to call a WCF web service from a simple, sequential WWF workflow on .NET 3.0/VS 2005 platform? I know that .NET3.5/VS2008 has made this integration seamless but I'm stuck trying to get it to work on .NET 3.0/ VS2005.

Leave a Comment





Ads Powered by Lake Quincy Media Network