G
Guest
Hi,
Am new to web services, so apologies for the basic nature of the question -
and apologies in advance if this is the wrong newsgroup. We're building a
new web service and I'm looking around for documentation on a number of
issues, including versioning of web service interfaces...
I've spent the last few hours looking through books, Google, MSDN and
surprisingly I have found little or nothing that explains/shows how to
practically handle the evolution of a web service's interface over time. One
would have thought that this would be one topic where there would be an
abundance of information.
Our requirements for versioning a web service interface are:
(a) To ensure that a previously published interface never changes, so that
older clients still work: this can be further classified to include (i)
changes to method signatures, and (ii) changes to custom types passed in/out
to these methods
(b) To ensure that new interfaces are a superset of any existing old
interfaces, with the additional requirement that no code is repeated, so the
methods in the new interfaces that are the same as the old interface, simply
delegate calls to existing methods rather than repeating code.
(c) To keep the URL to the WSDL the same for all versions - in my opinion, a
WSDL is a description of a web service, and not the description of a version
of a webservice - I have seen many implementations of web service versioning
that simply use a different WSDL for each version - although it somewhat
works, I'm not sure that this is the ideal solution.
(d) To make all the changes in C# code (using attribute decoration), without
having to resort to directly modifying WSDL's or XSD files, especially after
auto-generation - in other words, we want to be able to use the built-in
web-service-related attributes within Visual Studio.NET to decorate our code
and not poke around modifying system-generated files...
The little that I've found, I list below along with why the
solution/explanation is not ideal (based on my understanding) for our
particular needs - both of them were written (wholly or partly) by Scott
Seely sometime in 2002:
(1)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnservice/html/service10152002.asp
This is a good article however with regards to adding new code it opts for
either having two ASMX files or manually editing the WSDL both of which are
not very attractive. For changing method signatures, it opts again for
having two separate ASMX files which again is not attractive.
(2)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnservice/html/service04032002.asp
Again another good article, however no references are made to the use of
attributes within C# code - the main thrust of this article is that
versioning should be done via the TargetNamespace
([WebService(Namespace="http://www.somecompany.com/Version1")]), which from
within VS.NET can be set as an attribute of the just above the Service class
(which inherits from System.Web.Services.WebService). From reading this, I
got the idea to put a new version of the web service into a second class
(within the same overall C# class (not XML!) namespace) also inheriting from
System.Web.Services.WebService, but this time decorate that class with a
different TargetNameSpace, for example
[WebService(Namespace="http://www.somecompany.com/Version2")] - this way, I
could have two separate classes representing each web service versions, with
each class being decorated by a versioned TargetNamespace, whilst still
sharing the same ASMX/URL.
The sample code I came up with is below (business logic has been replaced
with Apples and Pears and Oranges for IP reasons, however the mechanics are
the same). What I found is that when I run the service, only the methods
from the first class that is declared show up as being methods on the service
- the second class with the separate target namespace appears to be
completely ignored.
When I request a WSDL from the service, this also appears to reflect the
fact that the second class is completely ignored - what am I doing wrong?
Have I adopted the wrong approach? Is what I'm looking for (the 4 points (a)
to (d) above) impossible to achieve? Is there something very basic that I'm
missing?
Frankly, I find it hard to believe that there are no more than the two
complete articles listed above available on the net for web service
versioning using .NET, however I can't find any more! Any pointers to
documentation, in-code attributes, suggestions to fix my approach above or
even sample code etc for me to read up on would be extremely welcome...
Kind regards
Patrick
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Code pasted below:
using System;
using System.Web;
using System.Web.Services;
using System.ComponentModel;
using System.Web.Services.Protocols;
namespace SomeWebService
{
[Serializable()]
public class Apple
{
public string name;
public int age;
public Apple()
{
name = @"";
}
}
[Serializable()]
public class Pear
{
public string name;
public int age;
public Pear()
{
name = @"";
}
}
[Serializable()]
public class Orange
{
public string name;
public int age;
public Orange()
{
name = @"";
}
}
/// <summary>
/// Summary description for Service.
/// </summary>
[WebService(Namespace="http://www.somecompany.com/V1")]
public class Service1 : System.Web.Services.WebService
{
public Service1()
{
InitializeComponent();
}
#region Component Designer generated code
//Required by the Web Services Designer
private IContainer components = null;
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if(disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion
[WebMethod]
public Apple[] GetAppleList()
{
Apple[] apples = new Apple[ 3 ];
Apple a = new Apple();
a.name = @"Granny Smith";
a.age = 3;
apples[0] = a;
a = new Apple();
a.name = @"Golden Shine";
a.age = 4;
apples[1] = a;
a = new Apple();
a.name = @"Crunchy Green";
a.age = 5;
apples[2] = a;
return apples;
}
[WebMethod]
public Pear[] GetPearList()
{
Pear[] pears = new Pear[ 2 ];
Pear p = new Pear();
p.name = @"Avocado";
p.age = 9;
pears[0] = p;
p = new Pear();
p.name = @"Fruity Pear";
p.age = 10;
pears[1] = p;
return pears;
}
}
/// <summary>
/// Summary description for Service.
/// </summary>
[WebService(Namespace="http://www.somecompany.com/V2")]
public class Service2 : System.Web.Services.WebService
{
public Service2()
{
InitializeComponent();
}
#region Component Designer generated code
//Required by the Web Services Designer
private IContainer components = null;
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if(disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion
[WebMethod]
public Apple[] GetAppleList()
{
Service1 s = new Service1();
return s.GetAppleList();
}
[WebMethod]
public Pear[] GetPearList()
{
Service1 s = new Service1();
return s.GetPearList();
}
[WebMethod]
public Orange[] GetOrangeList()
{
Orange[] oranges = new Orange[ 2 ];
Orange o = new Orange();
o.name = @"Mandarin";
o.age = 9;
oranges[0] = o;
o = new Orange();
o.name = @"Tangarine";
o.age = 10;
oranges[1] = o;
return oranges;
}
}
}
Am new to web services, so apologies for the basic nature of the question -
and apologies in advance if this is the wrong newsgroup. We're building a
new web service and I'm looking around for documentation on a number of
issues, including versioning of web service interfaces...
I've spent the last few hours looking through books, Google, MSDN and
surprisingly I have found little or nothing that explains/shows how to
practically handle the evolution of a web service's interface over time. One
would have thought that this would be one topic where there would be an
abundance of information.
Our requirements for versioning a web service interface are:
(a) To ensure that a previously published interface never changes, so that
older clients still work: this can be further classified to include (i)
changes to method signatures, and (ii) changes to custom types passed in/out
to these methods
(b) To ensure that new interfaces are a superset of any existing old
interfaces, with the additional requirement that no code is repeated, so the
methods in the new interfaces that are the same as the old interface, simply
delegate calls to existing methods rather than repeating code.
(c) To keep the URL to the WSDL the same for all versions - in my opinion, a
WSDL is a description of a web service, and not the description of a version
of a webservice - I have seen many implementations of web service versioning
that simply use a different WSDL for each version - although it somewhat
works, I'm not sure that this is the ideal solution.
(d) To make all the changes in C# code (using attribute decoration), without
having to resort to directly modifying WSDL's or XSD files, especially after
auto-generation - in other words, we want to be able to use the built-in
web-service-related attributes within Visual Studio.NET to decorate our code
and not poke around modifying system-generated files...
The little that I've found, I list below along with why the
solution/explanation is not ideal (based on my understanding) for our
particular needs - both of them were written (wholly or partly) by Scott
Seely sometime in 2002:
(1)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnservice/html/service10152002.asp
This is a good article however with regards to adding new code it opts for
either having two ASMX files or manually editing the WSDL both of which are
not very attractive. For changing method signatures, it opts again for
having two separate ASMX files which again is not attractive.
(2)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnservice/html/service04032002.asp
Again another good article, however no references are made to the use of
attributes within C# code - the main thrust of this article is that
versioning should be done via the TargetNamespace
([WebService(Namespace="http://www.somecompany.com/Version1")]), which from
within VS.NET can be set as an attribute of the just above the Service class
(which inherits from System.Web.Services.WebService). From reading this, I
got the idea to put a new version of the web service into a second class
(within the same overall C# class (not XML!) namespace) also inheriting from
System.Web.Services.WebService, but this time decorate that class with a
different TargetNameSpace, for example
[WebService(Namespace="http://www.somecompany.com/Version2")] - this way, I
could have two separate classes representing each web service versions, with
each class being decorated by a versioned TargetNamespace, whilst still
sharing the same ASMX/URL.
The sample code I came up with is below (business logic has been replaced
with Apples and Pears and Oranges for IP reasons, however the mechanics are
the same). What I found is that when I run the service, only the methods
from the first class that is declared show up as being methods on the service
- the second class with the separate target namespace appears to be
completely ignored.
When I request a WSDL from the service, this also appears to reflect the
fact that the second class is completely ignored - what am I doing wrong?
Have I adopted the wrong approach? Is what I'm looking for (the 4 points (a)
to (d) above) impossible to achieve? Is there something very basic that I'm
missing?
Frankly, I find it hard to believe that there are no more than the two
complete articles listed above available on the net for web service
versioning using .NET, however I can't find any more! Any pointers to
documentation, in-code attributes, suggestions to fix my approach above or
even sample code etc for me to read up on would be extremely welcome...
Kind regards
Patrick
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Code pasted below:
using System;
using System.Web;
using System.Web.Services;
using System.ComponentModel;
using System.Web.Services.Protocols;
namespace SomeWebService
{
[Serializable()]
public class Apple
{
public string name;
public int age;
public Apple()
{
name = @"";
}
}
[Serializable()]
public class Pear
{
public string name;
public int age;
public Pear()
{
name = @"";
}
}
[Serializable()]
public class Orange
{
public string name;
public int age;
public Orange()
{
name = @"";
}
}
/// <summary>
/// Summary description for Service.
/// </summary>
[WebService(Namespace="http://www.somecompany.com/V1")]
public class Service1 : System.Web.Services.WebService
{
public Service1()
{
InitializeComponent();
}
#region Component Designer generated code
//Required by the Web Services Designer
private IContainer components = null;
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if(disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion
[WebMethod]
public Apple[] GetAppleList()
{
Apple[] apples = new Apple[ 3 ];
Apple a = new Apple();
a.name = @"Granny Smith";
a.age = 3;
apples[0] = a;
a = new Apple();
a.name = @"Golden Shine";
a.age = 4;
apples[1] = a;
a = new Apple();
a.name = @"Crunchy Green";
a.age = 5;
apples[2] = a;
return apples;
}
[WebMethod]
public Pear[] GetPearList()
{
Pear[] pears = new Pear[ 2 ];
Pear p = new Pear();
p.name = @"Avocado";
p.age = 9;
pears[0] = p;
p = new Pear();
p.name = @"Fruity Pear";
p.age = 10;
pears[1] = p;
return pears;
}
}
/// <summary>
/// Summary description for Service.
/// </summary>
[WebService(Namespace="http://www.somecompany.com/V2")]
public class Service2 : System.Web.Services.WebService
{
public Service2()
{
InitializeComponent();
}
#region Component Designer generated code
//Required by the Web Services Designer
private IContainer components = null;
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if(disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion
[WebMethod]
public Apple[] GetAppleList()
{
Service1 s = new Service1();
return s.GetAppleList();
}
[WebMethod]
public Pear[] GetPearList()
{
Service1 s = new Service1();
return s.GetPearList();
}
[WebMethod]
public Orange[] GetOrangeList()
{
Orange[] oranges = new Orange[ 2 ];
Orange o = new Orange();
o.name = @"Mandarin";
o.age = 9;
oranges[0] = o;
o = new Orange();
o.name = @"Tangarine";
o.age = 10;
oranges[1] = o;
return oranges;
}
}
}