0
votes

I just updated my references to the new ServiceStack from nuget (from 3.9.11 to version 3.9.56) and I could not get my soap clients to work. So I decided to try once again the Hello World solution provided on [github] (https://github.com/ServiceStack/ServiceStack.Examples/tree/master/src/ServiceStack.Hello) which by the way is using an older version (3.9.32).

I added the [DataContract] attributes on the Hello and HelloResponse classes and then I tried to build a C# console client by adding a service reference to my localhost soap12 endpoint (using the Add Service Reference on VS2010, also tried 2012 and 2013). Unfortunately while I do get the OneWayClient and the SyncReplyClient I do not get any of my DTOs generated. Why is that? I tried to build my code with an older version of ServiceStack (using the IService<T> and the Execute method and everything worked fine! Are there any breaking changes that I am not aware of?

P.S. I tried also to recompile the whole ServiceStack.Examples project against the nuget libraries and it failed too. I could not even generate the proxy. Please do not try to convince me to use a share assembly for my DTOs as this defeats the purpose of having a language agnostic web service!

2

2 Answers

3
votes

Please do not try to convince me to use a share assembly for my DTOs as this defeats the purpose of having a language agnostic web service!

Doesn't sound like a Getting things done attitude. Not sure what you think the purpose of a service is but it's not to implement the complex WS-* specification (which is dead), it's not even to appease some proprietary code-gen proxy tool, especially ones that generates RPC method signatures coupling code-gen types to generate proxy clients that's limited to using the inefficient and bloated SOAP format which provides what is arguably the most fragile combination of technologies used in web service implementations today.

The purpose of a service is actually... just to provide a service - to encapsulate some capability and make it available remotely, in the most accessible, tolerant and interoperable way possible, ideally efficiently with the least amount of effort, friction and complexity.

Not sure why you think SOAP generated proxies is the ticket to having a language agnostic web service? Given that code-gen proxy implementations are often weak, incomplete and deprecated on platforms that aren't popular within Enterprises.

The whole purpose of a WSDL was to provide some machine readable spec which code-gen proxies can use to generate a typed service client - that's the purpose of a WSDL (not a service) - a tool to serve a means to an end (to provide connectivity to a service). But under all that complexity and closed-source black-box tooling it's still unable to re-create the clean DTO types that are developed and maintained on the server. But you can avoid all that artificial machinery and complexity by just copying the .dll (or source code) to your .NET client projects, giving you symmetrical parity with the Server DTOs that lets you use any of ServiceStack's generic .NET Service Clients providing the ability to re-use the same DTO's in any supported format (even built-in WCF/SOAP Clients) since the generic typed clients are substitutable.

WS-*/SOAP is deprecated because it was un-necessarily complex, it was built on the false premise that to provide an "interoperable service" you need to be abstract, explicit and opt-in to complexity. The opposite is true, you get much better interoperability, with less effort and friction using a simpler format and simple URIs, which is why new Web APIs today wont support SOAP.

2
votes

I have finally solved the issue so I am going to post the answer here. ServiceStack is not as broken as it seems although all the examples on the github repo need an update to work with the latest version. So to the point: if you want your classes to correctly produce proxy classes you have to decorate them all not only with the [DataContract] attribute on the class level but also with the [DataMember] on the property level i.e.

[DataContract]
class User
{
    [DataMember]
    public String Name { get; set; }
}

Of course you also need to either specify the namespace on the [DataContract] attribute (for Mono compatibility) or you will have to add a few lines on the AssemblyInfo.cs as described here.

Be warned though! All your DTOs including request types and response types should be on the same namespace! Also if you define only first level classes as request types (like the User example I used) then you will not get a proxy class! Instead all the public members will become method parameters. If you had though, by composition, another public member within User class i.e.

[DataContract]
class User
{
    [DataMember]
    public String Name { get; set; }
    [DataMember]
    public MyClass MyMember { get; set; }
}

then you would get your proxies for the MyClass though not for User. As for response types better read the ServiceStack wiki on SOAP limitations.

Last note: I usually have strong opinions only about flexibility, simplicity, finding alternatives and making things work. I find pointless the discussions that try to support a language over another, an architecture over another, a buzzword/niche technology over a standard approach, using tools that make life easier over hardcoding everything. So I see as such the discussion on the comments above and I wish to continue no more.

I am just glad that a great tool like ServiceStack continues to provide what most users use it for: A variety of alternatives.