I'm building a SOAP webservice API to allow our customers to integrate their external apps with our systems. This requires the webservice(s) to have a lot of operations, and many different .NET classes to serialize.
What I have done so far is split the API into multiple webservices (.asmx files using VS.NET).
This way the names of the operations can be a bit shorter (e.g. CompanyHandler.Save(...) instead of SuperHandler.SaveCompany(...)) and the actual files becomes more manageable when developing the API, since I don't need a 100'000 line file with all the code.
To make the parameterlists and return values of the service easy to use I have made a set of classes which act as simple data holders with no methods.
The problem arises when I make a sample client (in my case also in .NET).
When I add a reference to the webservice (using VS.NET or wsdl.exe) the data holder classes are auto-generated for each service that references them (as part of the WS proxy/wrapper).
So if both the PersonHandler and CompanyHandler uses a Person object in a return or parameter value it causes problems. If the proxies are generated in the same namespace there is an obvious problem with an "ambigious reference" and if the are created in seperate namespaces it makes the client app unnecessarily complicated and means that you have two 100% identitical classes in two different namespaces (so you can't e.g. use the Person class returned from CompanyHandler.GetPersonsWorkingAtCompany(...) to call PersonHandler.SavePerson(...)).
See the included code section for an example which illustrates the problem.
//// FICTITIOUS EXAMPLES OF SAMPLE CLIENT////-- Example 1 - Ambigious reference problem --//Will not compile. "Person" is an ambigious reference since it is generated both for the PersonHandler and the CompanyHandler webservice proxyint companyId = 32;CompanyHandler companyHandler = new CompanyHandler();PersonHandler personHandler = new PersonHandler();Person personsForCompany companyHandler.GetPersonsWorkingAtCompany(companyId);Person somePerson = personsForCompany;somePerson.Name = "James Brown";somePerson.Email = "firstname.lastname@example.org";personHandler.SavePerson(somePerson);//-- Example 2 - Using namespaces which cause "class mismatch" --//Will not compile. We can not call SavePerson with the somePerson object since it is another "Person" class than the one returned by GetPersonsForCompanyint companyId = 32;Company.CompanyHandler companyHandler = new Company.CompanyHandler();Person.PersonHandler personHandler = new Person.PersonHandler();Company.Person personsForCompany companyHandler.GetPersonsWorkingAtCompany(companyId);Company.Person somePerson = personsForCompany;somePerson.Name = "James Brown";somePerson.Email = "email@example.com";personHandler.SavePerson(somePerson); //will not compile, somePerson is wrong class for SavePerson even though they are based on the same class in the code for the webservice that is called
No, I had not found those links. I tried googling all sorts of word-combos, but they all drowned in "how to set up your first SOAP WS" articles.
"creating a seperate dll"
I also briefly considered that. But I would really rather not add additional plumbing and complexity to the client end.
"use an interface"
I'm fairly sure the ".NET to SOAP XML" serialization will strip that info away. I might give it a try though - just to make sure.
"change from Web Services to WCF"
That does in fact solve it (combined with setting specific namespace on the serialization attribute.
But I need the API to be easy for the client developers to use, even if they do not have much experience with WS-tech (also I would imagine that many WS-enabled programming environments are lacking such a feature).
I think I will try to change the services so the classes are only used in one service, since that would save me all kinds of trouble keeping things up to date, and explaning the issue to client programmers.
Thanks for your help. At least now I know that I'm not missing some obvious solution and what my work-around options are.