How does a WSDL parser decide to generate a void method for a Request/Reply operation?

StackOverflow https://stackoverflow.com/questions/8316567

سؤال

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.

هل كانت مفيدة؟

المحلول

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top