freddes.se

…because I'm a nerd

Service interfaces using XSD (cont’d MVC Web Service part 1)

with one comment

visualstudiologoThe other day I got a question from a colleague of mine, regarding the XML schema usage when defining a web service interface, like the one defined in series. The question was something like this: “How will the consumer of the web service react if the, from the XSD file, auto-generated class used as in and return parameters is updated?” I couldn’t give a straight answer, other than that I assumed it would be transparent to the consumer as long as no nodes were changed or removed and only new nodes were added to the schema. I decided to give it a try, using a really simple XSD and a couple of really simple web methods. I will give a schematic picture of the scenario that I will test out later on.

Scenario

The following scenario will be tested, using a Windows Forms application as consumer and a couple of ASP.NET Web Service applications to host the web methods: xsd_versions_scenario
I will implement two web services, using two different versions of the same XSD to generate the class to be used as web method parameters. The XSDs to be used will look like this, version 1 first followed by version 1.1:
inout_v1 inout_v1_1
As you can see, version 1.1 has an extra City node. To generate the classes use the xsd tool. Look at the syntax in . The scenario picture above shows what I am about to implement together with the following:

  1. The consumer will contain a web/service reference to Svc1. The endpoint address will point out Svc1 and the consumer will invoke web methods with an in parameter and return value of the type generated from XSD version 1.
  2. The same web/service reference as in 1 will be used but the endpoint address will point out Svc1.1. The same methods will be invoked using this endpoint.
  3. The consumer will contain a web/service reference to Svc1.1. The endpoint address will point out Svc1.1 and the consumer will invoke method with an in parameter and return value of the type generated from XSD version 1.1.
  4. The same web/service reference as in 3 will be used but the endpoint address will point out Svc1. The same methods will be invoked using this endpoint.

Implementing and testing

As always I start by adding an empty Visual Studio solution. I add two ASP.NET Web Service applications, one for XSD version 1 and one for version 1.1. After that I add a Windows Forms application to funtion as a consumer of the web services. To make use of the classes generated by the xsd tool I add the generated files using “Add existing item…”. The two web services will contain the following methods:

        [WebMethod]
        public XSDScenario.InOutType GetData()
        {
            XSDScenario.InOutType retVal = new XSDScenario.InOutType()
            {
                Name = "Kalle (v1)",
                PersonalID = 111
            };

            return retVal;
        }

        [WebMethod]
        public bool VerifyData(XSDScenario.InOutType input)
        {
            if (input != null)
            {
                if (input.Name.Length > 0 && input.PersonalID > 0)
                    return true;
                else
                    return false;
            }
            else
            {
                return false;
            }
        }
        [WebMethod]
        public XSDScenario.InOutType GetData()
        {
            XSDScenario.InOutType retVal = new XSDScenario.InOutType()
            {
                Name = "Kalle (v1.1)",
                City = "Stockholm",
                PersonalID = 111
            };

            return retVal;
        }

        [WebMethod]
        public bool VerifyData(XSDScenario.InOutType input)
        {
            if (input != null)
            {
                if (input.Name.Length > 0 && input.PersonalID > 0)
                {
                    if (input.City != null)
                        return input.City.Length > 0;
                    else
                        return true;
                }
                else
                    return false;
            }
            else
            {
                return false;
            }
        }

In version 1.1 the method VerifyData contains an extra if statement making the method return true even if the City property of the input parameter is null. The form on the consumer side will look like this:
the_consumer_form
The form above makes it possible to test all four cases stated above. The result will be partly presented below. Before this let’s take a look at some of the web method consumer code:

        private void btnInvokeGetData_Click(object sender, EventArgs e)
        {
            if (rbServiceVersion1.Checked)
            {
                // Using service reference proxy for Service version 1
                SvcRef_1.InOutServiceSoapClient ioSC = new SvcRef_1.InOutServiceSoapClient();

                if (rbEndpointVersion1.Checked)
                {
                    // Using Service version 1 endpoint,
                    // e.g. invoking methods on version 1 Service
                    ioSC.Endpoint.Address =
                                new EndpointAddress("http://localhost:49801/InOutService.asmx");
                }
                else
                {
                    // Using Service version 1.1 endpoint,
                    // e.g. invoking methods on version 1.1 Service
                    ioSC.Endpoint.Address =
                                new EndpointAddress("http://localhost:49802/InOutService.asmx");
                }

                // Since we use service reference proxy for version 1
                // the GetData method will return version 1 object.
                SvcRef_1.InOutType ioRet = ioSC.GetData();
            }
            else
            {
                // Using service reference proxy for Service version 1.1
                SvcRef_11.InOutServiceSoapClient ioSC = new SvcRef_11.InOutServiceSoapClient();

                if (rbEndpointVersion1.Checked)
                {
                    // Using Service version 1 endpoint,
                    // e.g. invoking methods on version 1 Service
                    ioSC.Endpoint.Address =
                                new EndpointAddress("http://localhost:49801/InOutService.asmx");
                }
                else
                {
                    // Using Service version 1.1 endpoint,
                    // e.g. invoking methods on version 1.1 Service
                    ioSC.Endpoint.Address =
                                new EndpointAddress("http://localhost:49802/InOutService.asmx");
                }

                // Since we use service reference proxy for version 1.1
                // the GetData method will return version 1.1 object.
                SvcRef_11.InOutType ioRet = ioSC.GetData();
            }
        }

        private void btnInvokeVerifyData_Click(object sender, EventArgs e)
        {
            if (rbServiceVersion1.Checked)
            {
                SvcRef_1.InOutType parameter = new SvcRef_1.InOutType()
                {
                    Name = textBoxName.Text,
                    PersonalID = Convert.ToInt32(textBoxPersonalID.Text)
                };

                // Using service reference proxy for Service version 1
                SvcRef_1.InOutServiceSoapClient ioSC = new SvcRef_1.InOutServiceSoapClient();

                if (rbEndpointVersion1.Checked)
                {
                    // Using Service version 1 endpoint,
                    // e.g. invoking methods on version 1 Service
                    ioSC.Endpoint.Address =
                                new EndpointAddress("http://localhost:49801/InOutService.asmx");
                }
                else
                {
                    // Using Service version 1.1 endpoint,
                    // e.g. invoking methods on version 1.1 Service
                    ioSC.Endpoint.Address =
                                new EndpointAddress("http://localhost:49802/InOutService.asmx");
                }

                bool dataValid = ioSC.VerifyData(parameter);
            }
            else
            {
                SvcRef_11.InOutType parameter = new SvcRef_11.InOutType()
                {
                    City = textBoxCity.Text,
                    Name = textBoxName.Text,
                    PersonalID = Convert.ToInt32(textBoxPersonalID.Text)
                };

                // Using service reference proxy for Service version 1.1
                SvcRef_11.InOutServiceSoapClient ioSC = new SvcRef_11.InOutServiceSoapClient();

                if (rbEndpointVersion1.Checked)
                {
                    // Using Service version 1 endpoint,
                    // e.g. invoking methods on version 1 Service
                    ioSC.Endpoint.Address =
                                new EndpointAddress("http://localhost:49801/InOutService.asmx");
                }
                else
                {
                    // Using Service version 1.1 endpoint,
                    // e.g. invoking methods on version 1.1 Service
                    ioSC.Endpoint.Address =
                                new EndpointAddress("http://localhost:49802/InOutService.asmx");
                }

                bool dataValid = ioSC.VerifyData(parameter);
            }
        }

Result

I will present the results using the following pictures:
ref_version_1 The top row shows the return parameter when consuming the GetData web method. The bottom row shows the server side parameter when invoking the VerifyData method.ref_version_1_1 As above, the top row shows the return parameter when consuming the GetData web method. The bottom row shows the server side parameter when invoking the VerifyData method.

Summary

Under these circumstances my answer was correct, when I said that the web services and consumers will still function as long as nothing is changed or removed but only new nodes are added to the XSD, meaning that the parameter objects will be extended with new fields. It is pretty hard to explain the result, but it is easy to implement the scenario defined here. Please try to do it yourself and be amused by the result! Good Luck!

Related articles

Written by Fredde

December 29th, 2008 at 11:09 pm

One Response to 'Service interfaces using XSD (cont’d MVC Web Service part 1)'

Subscribe to comments with RSS or TrackBack to 'Service interfaces using XSD (cont’d MVC Web Service part 1)'.

  1. This is quite a up-to-date info. I’ll share it on Digg.

Leave a Reply