Search code examples
c#workflow-foundation-4workflow-foundation

Human based task in windows workflow foundation


I am trying to build a simple leave request application in windows workflow foundation 4.5, it throws the following exception as the workflow tries to complete without waiting for approveRequest activity.

Two SendParameters objects with same ServiceContractName and OperationName 'ApplyLeave' have different parameter names.

Can you please suggest me what is missing?

using System;
using System.ServiceModel.Activities;
using System.Activities;
using System.ServiceModel;
using System.Activities.Statements;

namespace DemoWF
{
    public class _25_LeaveRequest
    {
        public WorkflowService GetInstance()
        {
            WorkflowService service;
            Variable<int> empID = new Variable<int> { Name = "empID" };
            Variable<int> requestID = new Variable<int> { Name = "requestID" };

        Receive receiveLeaveRequest = new Receive
        {
            ServiceContractName = "ILeaveRequestService",
            OperationName = "ApplyLeave",
            CanCreateInstance = true,
            Content = new ReceiveParametersContent
            {
                Parameters ={
                    {"empID",new OutArgument<int>(empID)}
                }
            }
        };

        SendReply replyLeaveRequestID = new SendReply
        {
            Request = receiveLeaveRequest,
            Content = new SendParametersContent
            {
                Parameters ={
                            {"requestID",new InArgument<int>(requestID)},
                        },
            },
        };

        Receive approveRequest = new Receive
        {
            ServiceContractName = "ILeaveRequestService",
            OperationName = "ApproveLeave",
            CanCreateInstance = true,
            Content = new ReceiveParametersContent
            {
                Parameters ={
                    {"requestID",new OutArgument<int>(requestID)}
                }
            }
        };

        SendReply sendApproval = new SendReply
        {
            Request = receiveLeaveRequest,
            Content = new SendParametersContent
            {
                Parameters ={
                            {"approved",new InArgument<int>(0)},
                        },
            },
        };

        Sequence workflow = new Sequence()
        {
            Variables = { empID, requestID },
            Activities = {
                new WriteLine{Text="WF service is starting..."},
                receiveLeaveRequest,
                new WriteLine{
                    Text=new InArgument<string>(aec=> "Emp ID="+empID.Get(aec).ToString())
                },
                new Assign<int>{
                    Value=new InArgument<int>(5),
                    To=new OutArgument<int>(requestID)
                },
                new WriteLine{
                    Text=new InArgument<string>(aec=> "Request ID="+requestID.Get(aec).ToString())
                },
                replyLeaveRequestID,
                approveRequest,
                new WriteLine{Text="Approved"},
                sendApproval
            },
        };

        service = new WorkflowService
        {
            Name = "AddService",
            Body = workflow
        };
        return service;
    }
}

}

and hosted as mentioned below

namespace DemoWF
{
    class Program
    {
        static void Main(string[] args)
        {
            LeaveRequest();
        }

        private static void LeaveRequest()
        {
            _25_LeaveRequest receiveAndReplyWorkflow = new _25_LeaveRequest();
            WorkflowService wfService = receiveAndReplyWorkflow.GetInstance();
            Uri address = new Uri("http://localhost:8000/WFServices");
            WorkflowServiceHost host = new WorkflowServiceHost(wfService, address);

            try
            {
                Console.WriteLine("Opening Service...");
                host.Open();

                Console.WriteLine("WF service is listening on " + address.ToString() + ", press any key to close");
                Console.ReadLine();
            }
            catch (Exception e)
            {
                Console.WriteLine("some thing bad happened" + e.StackTrace);
            }
            finally
            {
                host.Close();
            }
        }
    }
}

Solution

  • You probably have two methods with the same name which receive two parameters. However since you sending objects to your WF service, those can be cast to either one of those methods and so the WF service can not know which one of them to execute.

    As first step you should change your 'Leave' method overloads signature in your service, so instead of having:

    public object ApplyLeave(SomeType1 t1, SomeType2 t2) {...}
    public object ApplyLeave(SomeType3 t3, SomeType4 t4) {...}
    

    Make it:

    public object ApplyLeaveA(SomeType1 t1, SomeType2 t2) {...}
    public object ApplyLeaveB(SomeType3 t3, SomeType4 t4) {...}
    

    And in your code call the exact method you want to use.