简体   繁体   中英

How do I return a string from WCF Workflow (WF4) when invoked by a Interface with ChannelFactory?

If I have a workflow hosted (WF4 + WCF) and running in IIS implementing the following interface:

[ServiceContract]
public interface IMessageService
{   
     [OperationContract]
     string SendMessage(string message);
}

(Using RecieveActivity and SendReply from System.ServiceModel.Activities )

And invoke it like this:

    var channel = new ChannelFactory<IMessageService>().CreateChannel(<init params>);
    string answer = channel.SendMessage("Testmessage");

Then answer is always null. If I consume the workflow through the WcfTestClient I can see there is an returned xml object.

How can I make the workflow return a string to populate answer ?

(I'd like to avoid the "Add a ServiceReference and return a lot of xml-approach")

You need a [return] attribute to specify how to find the result.

In the SendReplyToReceive you can choose between sending back a Message or Parameters . In my experience, you need to choose Parameters but only send back one. Assuming you give the return parameter the name "result" then you need this attribute on your interface contract:

[return: MessageParameter(Name = "result")]

Here is a full example of one of mine;

namespace NewOrbit.ExVerifier.Model.Workflow.Case
{
    using System;
    using System.ServiceModel;

    using NewOrbit.ExVerifier.Model.Workflow;

    [ServiceContract(Namespace = "urn://exverifier.neworbit.co.uk/")]
    public interface ICaseWorkflow
    {
        [OperationContract(Action = "urn://exverifier.neworbit.co.uk/NewOrbit.ExVerifier.Model.Workflow.Case.ICaseWorkflow/Start",
            ReplyAction = "urn://exverifier.neworbit.co.uk/NewOrbit.ExVerifier.Model.Workflow.Case.ICaseWorkflow/StartReply")]
        [return: MessageParameter(Name = "result")]
        WorkflowInstanceIdentifier Start(int caseID);

        [OperationContract(Action = "urn://exverifier.neworbit.co.uk/NewOrbit.ExVerifier.Model.Workflow.Case.ICaseWorkflow/ApplicationStateChanged",
            ReplyAction = "urn://exverifier.neworbit.co.uk/NewOrbit.ExVerifier.Model.Workflow.Case.ICaseWorkflow/ApplicationStateChangedReply")]
        [return: MessageParameter(Name = "result")]
        bool ApplicationStateChanged(Guid instanceID, int applicationID);

        [OperationContract(Action = "urn://exverifier.neworbit.co.uk/NewOrbit.ExVerifier.Model.Workflow.Case.ICaseWorkflow/Cancel",
            ReplyAction = "urn://exverifier.neworbit.co.uk/NewOrbit.ExVerifier.Model.Workflow.Case.ICaseWorkflow/CancelReply")]
        [return: MessageParameter(Name = "result")]
        bool Cancel(Guid instanceID);
    }
}

Incidentally, in your example I am not sure how you are getting away with not specifying the OperationContract but great that you are - they are a real pain because the format you have to specify them in is different in the contract and in the workflow.

Also, just in case you don't know and it can cause some really subtle bugs: The parameters you pass in are recognised by name, so it is imprtant that the name you specify for inbound parameters in your interface is the same as in your workflow. Obvious when you think about it but can catch you out. Oh, and avoid method names that are too long as they will break as well with misleading error messages.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM