0

I have spent 5 hours on this, and I've already been up 30 hours writing this contract-first spec ("aggressive" deadline, ergo stupid) and I cannot see what I'm missing.

I do not want a one-way operation as I expect faults. I have already built a simple WCF service and examined the WSDL that it generates and it does round trip to a void method but I've been staring at it so long (and WSDL 1.1 is so annoying at the best of times - roll on 2.0 please) that I can no longer see what the magic trick is.

Can anyone provide some very simple WSDL explaining the magic? I'm targetting both jax-ws 2.2 and WCF 3.5/4.0 with this WSDL. I am hand-writing the WSDL and every time I try to build proxies (in java or .net) it always builds a method with the return message. I'm losing it.

x0n
  • 51,312
  • 7
  • 89
  • 111

1 Answers1

4

A "void" method doesn't necessarily mean that it's a one-way operation. The two operations below are different:

[ServiceContract]
public interface ITest
{
    [OperationContract(IsOneWay = true)]
    void Process1();
    [OperationContract]
    void Process2();
}

The first one is really a one-way operation - any exceptions / faults thrown by the server will not be propagated to the client, while in the second one, although it doesn't "return" anything, if the server throws an exception (e.g., a FaultException), the exception will be returned back to the caller.

Update: to answer the question posed in the title, the WSDL parser decides to generate a void operation (at least the one used by WCF) if the schema for the output message of the operation is empty.

For example, in the code below:

public class StackOverflow_8316567
{
    [ServiceContract]
    public interface ITest
    {
        [OperationContract(IsOneWay = true)]
        void Process1();
        [OperationContract]
        void Process2();
        [OperationContract]
        int Add(int x, int y);
    }
    public class Service : ITest
    {
        public void Process1() { }
        public void Process2() { }
        public int Add(int x, int y) { return x + y; }
    }
    static Binding GetBinding()
    {
        var result = new BasicHttpBinding();
        return result;
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(ITest), GetBinding(), "");
        host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
        host.Open();
        Console.WriteLine("Host opened");

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}

If you run it and browse to http://localhost:8000/service?wsdl you'll see that:

  1. The operation Process1 (under wsdl:portType/wsdl:operation) only has an input message
  2. both Add and Process2 (r/r operations) have both an input and the output messages

Now, the message part for the output message for those 2 operations reference their schema in the imported schema (at http://localhost:8000/service?xsd=xsd0). You can see that:

  1. The schema for the response for the Process2 operation (complex type Process2Response) is an empty element (i.e., an empty sequence)
  2. The schema for the response for the Add operation (AddResponse) is a sequence containing one element (an xs:int value).

So the processor will generate a void method for Process2 (since it doesn't return anything) and a non-void method for Add.

carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
  • Thanks for the reply, but did you even read the question title, or the body? "How does a WSDL parser decide to generate a void method with a request/reply operation" and "I do not want a one-way pattern as I expect faults." – x0n Nov 29 '11 at 20:03
  • 1
    Yes, I read it. You mentioned that you "do not want a one-way pattern" because you expect faults. I said that just because it generated a void method, it doesn't mean that you can't receive faults - and this is why I added the example. I'll expand the answer with a direct answer to your question, though. – carlosfigueira Nov 29 '11 at 23:16
  • I tried to duplicate just the empty sequence pattern last night and it still generated a method with the enclosing complex type as the return. I did verify the same way you did earlier this morning and it is indeed as you say, but there's clearly something extra in my wsdl that's f**king it up. Accepted. – x0n Nov 29 '11 at 23:58
  • 1
    Figured it out - it appears that with doc/lit wrapped, the wrapper element has be in the same xmlns as the message or svcutil won't generate a void method. annoying. wsimport also doesn't like this model. – x0n Nov 30 '11 at 15:45