1
votes

After reading some ServiceStack wiki, I have a problem about DTO and I was hoping you could help.

The wiki said:

  1. In Service development your services DTOs provides your technology agnostic Service Layer which you want to keep clean and as 'dependency-free' as possible for maximum accessibility and potential re-use. Our recommendation is to keep your service DTOs in a separate largely dep-free assembly. (https://github.com/ServiceStack/ServiceStack/wiki/New-API)

  2. Finally you can also use the previous more explicit client API (ideal for when you don't have the IReturn<> marker): (https://github.com/ServiceStack/ServiceStack/wiki/New-API)

According to the reasons above, I consider the best practice about ServiceStack is: We should use POCO Request-Response DTOs instead of inheriting from IReturn<>.?

For instance:

We should use 1#:

public class AuthenticationRequest
{
    public string Name { get; set; }   
    public string Password { get; set; }
}

public class AuthenticationResponse
{
   public AuthenticationResponseType Result { get; set; }
   public UserInfoDto UserInfo { get; set; }
}

We shouldn't use 2#:

using ServiceStack;
public class AuthenticationRequest : IReturn<AuthenticationResponse>
{
    public string Name { get; set; }
    public string Password { get; set; }
}

public class AuthenticationResponse
{
   public AuthenticationResponseType Result { get; set; }
   public UserInfoDto UserInfo { get; set; }
}

Because 1# is zero dependency, 2# have a dependency on ServiceStack library/framework.

If I package all Request-Response DTOs to a NET DLL, 1# is more abstract than 2#!

This means: If one day in the future I deceide not to use ServiceStack, this DLL doesn't need any change. (ServiceStack library/framework should be Infrastructure not Abstraction)

Please correct me if I am wrong.

Very thanks.

1

1 Answers

1
votes

The only dependency DTO's should have is the impl-free ServiceStack.Interfaces.dll which as it's a Portable Class Library (PCL) supports almost every mobile or Desktop platform that .NET runs on. ServiceStack's Interfaces .dll is required in order to be able to cleanly describe your complete Services contract in a single, benign .dll.

For example. the [Route] metadata attribute captures the Custom Routes where the remote Services are hosted which is required info about your Service that clients need to know in order to be able to call services via their published Custom Routes. Likewise the IReturn<T> interface marker provides a strong-typed contract on what your Service returns which is what enables ServiceStack succinct end-to-end Typed API. Essentially ServiceStack.Interfaces is a required extension to be able to capture your entire Service Contract in your Services DTO's.

ServiceStack.Interfaces can be used outside of ServiceStack

Even if you don't use ServiceStack, you can still use the benign ServiceStack.Interfaces.dll which the clients can introspect to find out more information about your DTO's and the remote Service Contract. Whilst I'm not seeing any reason to, if you want to decouple the ServiceStack.Interfaces on your project you can just copy the attributes you're using in your DTO .dll freeing it from any external dependencies. But this would impact your ability to have a generic Service Client since these embedded interfaces and attributes are unknown to your client library, limiting its ability to enable rich generic functionality using it.

Service Contract Interfaces and Attributes in other Languages

To support non .NET languages like TypeScript, ServiceStack emits these interfaces in the generated DTO's so they don't require any dependencies.

Likewise in Add ServiceStack Reference support of Swift 2.0 or Java and Android these additional contracts are emitted idiomatically referencing a Swift IReturn protocol or IReturn<T> interface in the Java android client package which is also what enables the succinct Typed API's ServiceStack enables on both iOS and Android.

Service Design

Something you should keep in mind when designing your API's is that your Service Layer is your most important contract. i.e. Your API exists to allow consumers access to your remote Servers capabilities, so your internal logic should be a hidden impl-detail, not something that should impact the external surface area of your API.

The Request DTO defines your Service Contract where I find using a Request suffix is an ugly construct that negatively affects the readability of your external API, e.g. Here's a typical example of what a noun with a *Request suffix would look like:

var response = client.Get(new CustomerRequest { ... });

Compared with using a Verb where the Request DTO is indicative and provides better readability of what the Service does:

var response = client.Get(new FindCustomers { ... });

Your Request DTO should ideally be a verb that's grouped by call semantics and Response Type. Having a *Dto suffix is an indication that your internal implementation is leaking and affecting the ideal Service Contract your external API Consumers will bind to (and should never change). Keep in mind the objective of your Service is to provide re-usable functionality to your consumers so your impl should realize your published contract, not the other way around where its implementation dictates what the contract should be.

With that in mind I would rewrite your ServiceStack Examples to look like:

public class Authenticate : IReturn<AuthenticateResponse>
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

public class AuthenticateResponse
{
   public AuthenticationResult Result { get; set; }
   public UserInfo UserInfo { get; set; }
}

Which ends up being similar to ServiceStack's built-in Authenticate and AuthenticateResponse Request and Response DTOs.

I also recommend reading this earlier answer to understand the importance of DTO's and how it relates to the goals of a Service.