How to separate layers when using ServiceStack

4,157 views
Skip to first unread message

tsing gao

unread,
Nov 23, 2012, 10:09:14 AM11/23/12
to servic...@googlegroups.com
Usually, we separate our solution into different layers and use DI container to keep them working together:

Web ( UI, Controller, ViewModel )

Service ( IService, Service, IRepository )

Data (  Implementation of IRepository )

Core ( Domain + Utils )

But when  I decide to use ServiceStack,  I found it is a little different, 

1. Since we don't need Controller, we don't need to inject IService to Web project either. 
2. We use ORMLite to operate the repository, and it's a property of Service, does it mean we don't need a separated DAL anymore ? If so, how could we switch the database in the future ?

all the examples of service stack all be placed in a single web project. Is there any demo show how to separate layers ? 

Thanks.

Demis Bellot

unread,
Nov 23, 2012, 7:22:33 PM11/23/12
to servic...@googlegroups.com
This question is going to require a lot more content than the cursory answer I can provide on this thread.
This is an area I intend to cover in-depth soon as I intend to start publishing more code + SOA architectural patterns and guidance's complete with sample code-bases hopefully early next year.

Basically here are a few quick pointers I have on the subject:

ServiceStack classes are designed to be 'pure C#' (i.e. Request + Response POCOs), highly-testable (i.e. can mock all deps) and free of endpoint concerns so the common pattern of capturing user intent in Controllers just to delegate them into 'DDD C# service classes' is not really needed and you can consider your servicestack services to be just another 'C# Service' class that you can divide and refactor as needed.

OrmLite DTOs can effectively be re-used as DTOs since they're just POCOs as well. This is uncommon to be able to do with most Heavy ORM data models since they have persistence concerns and cyclical deps embedded in their data models. Structurally these aren't issues with Micro ORMs since they're able to make use of re-usable  disconnected POCOs. Having said that your OrmLite POCOs are data models, and when you start seeing DTO concerns creep starting to affect them, then its time to maintain separate DTOs for that purpose and use ServiceStack's built-in Translators (or AutoMapper) to map between them. See this thread for more context about this:
As a rule, I highly recommend putting DTOs in there own largely dep-free assembly, this ensures all your data contracts for your services are impl-free and isolated within well-defined service layer. As such this allows your Service Contract (i.e. DTO .dll) to be re-usable with any .NET client that wishes to consume your typed services.
For the other components of your services:

  - Your Host project should be kept as light as possible - it's just the glue to wire up all the config and dependencies required by your services
  - I keep my DTOs in an assembly named *.ServiceModel (that I keep as impl and dep-free as possible)
  - I keep my service implementations in an assembly named *.ServiceInterface. If you have multiple cohesive modules you can split the implementation across multiple impl .dlls and get ServiceStack to use them all by specifying the assembly list in the AppHostBase constructor.

As a general development guideline I like to follow the Interface Segregation Principle (it's my favorite SOLID principle since I was using it naturally before I knew it existed :)
Basically your services should be binded to methods on interfaces that capture its intent. In the implementation of that interface I'll give myself complete freedom to impl it as DRY with the least amount of code/effort as allowed.

In terms of Code Architecture, this should be driven by the code-base where your architecture should grow with your code-base and are ultimately driven by DRY and re-usability. 
I generally start off small by avoiding adding abstractions and delegation until they're required:

For simple single-purpose apps (like many of ServiceStack's live demos), its ok to just have everything in a single class since it lets you see all the code in a single file, e.g from Backbone's Todo ServiceStack back-end:

When I start having multiple services that require the same data access code, then to ensure DRY we can start re-factoring that out into cohesive repositories like we do in Redis StackOverflow:

Then when I start to require logic that requires both shared data access in addition to external dependencies I'll wrap those in another C# Service class and change my services to only access those, e.g:

public class MyServices : Service {
    public ITodoService TodoService { get; set; }
    ...
}

public TodoService : ITodoService {
    public ITodoRepository TodoRepository { get; set; } 
    public IExternalDependency Foo { get; set; }
   ...
}

public TodoRepository : ITodoRepository {
    public IDbConnectionFactory DbFactory { get; set; }
}

I'll only do this when necessary, e.g. when your services access other 3rd Party dependencies (e.g. Gateways) in addition to your repository's data access.

In general I try to avoid tying myself to any one particular architecture i.e. It's common for me to have the multiple levels of the architecture described above within the same code-base, e.g. Data Access code in Services for reporting to nested services + repositories to handle complex tasks.
I also dislike imposing the forced use of any dev patterns or interim schemas on myself, as when they're needed I'll introduce them naturally, e.g. I'll avoid stuff like Single Table Repositories which imposes a code architecture that's a recipe for over architecture and code-bloat.

In essence no holy grail architecture exists for all use-cases, the best approach I've found is to start small and only add abstractions and delegation when they're absolutely required.

Something that I find helps keep DRY whilst battling un-necessary abstractions and promotes clean readable code are extension methods, which I'll use whenever I need shared logic that doesn't require external dependencies.

Hope this helps.

Regards,


tsing gao

unread,
Nov 28, 2012, 7:37:50 AM11/28/12
to servic...@googlegroups.com
Thank you very much. I will create a demo project to try this out. 
Reply all
Reply to author
Forward
0 new messages