Service Gateway

Demis Bellot edited this page Oct 25, 2016 · 9 revisions

This page has moved to

The Service Gateway is implemented on top of ServiceStack's existing message-based architecture to open up exciting new possibilities for development of loosely-coupled Modularized Service Architectures.

The new IServiceGateway interfaces represent the minimal surface area required to support ServiceStack's different calling conventions in a formalized API that supports both Sync and Async Service Integrations:

public interface IServiceGateway
    // Normal Request/Reply Services
    TResponse Send<TResponse>(object requestDto);

    // Auto Batched Request/Reply Requests
    List<TResponse> SendAll<TResponse>(IEnumerable<object> requestDtos);

    // OneWay Service
    void Publish(object requestDto);

    // Auto Batched OneWay Requests
    void PublishAll(IEnumerable<object> requestDtos);

// Equivalent Async API's
public interface IServiceGatewayAsync
    Task<TResponse> SendAsync<TResponse>(object requestDto, 
        CancellationToken token = default(CancellationToken));

    Task<List<TResponse>> SendAllAsync<TResponse>(IEnumerable<object> requestDtos, 
        CancellationToken token = default(CancellationToken));

    Task PublishAsync(object requestDto, 
        CancellationToken token = default(CancellationToken));

    Task PublishAllAsync(IEnumerable<object> requestDtos, 
        CancellationToken token = default(CancellationToken));

The minimum set of API's above requires the least burden for IServiceGateway implementers whilst the ServiceGatewayExtensions overlays convenience API's common to all implementations providing the nicest API's possible for Request DTO's implementing the recommended IReturn<T> and IReturnVoid interface markers. The extension methods also provide fallback pseudo-async support for IServiceGateway implementations that also don't implement the optional IServiceGatewayAsync, but will use native async implementations for those that do.

Naked Request DTO's without annotations are sent as a POST but alternative Verbs are also supported by annotating Request DTO's with HTTP Verb Interface Markers where Request DTO's containing IGet, IPut, etc. are sent using the typed Verb API, e.g:

public class GetCustomer : IGet, IReturn<Customer>
    public int Id { get; set ;}

var customer = client.Send(new GetCustomer { Id = 1 }); //GET /customers/1
//Equivalent to:
var customer = client.Get(new GetCustomer { Id = 1 });  

Service Integration API's

To execute existing ServiceStack Services internally you can call ExecuteRequest(requestDto) which passes the Request DTO along with the current IRequest into the ServiceController.Execute() to execute. The alternative is to call ResolveService<T> to resolve an autowired instance of the Service that's injected with the current IRequest context letting you call methods on the Service instance directly. Below is an example of using both API's:

public object Any(GetCustomerOrders request)
    using (var orderService = base.ResolveService<OrderService>())
        return new GetCustomerOrders {
            Customer = (Customer)base.ExecuteRequest(new GetCustomer {Id=request.Id}),
            Orders = orderService.Any(new QueryOrders { CustomerId = request.Id })

The recommended approach now is to instead use the IServiceGateway accessible from base.Gateway available in all Service, Razor Views, MVC ServiceStackController classes, etc. It works similar to the ExecuteRequest() API (which it now replaces) where you can invoke a Service with just a populated Request DTO, but instead yields an ideal typed API for Request DTO's implementing the recommended IReturn<T> or IReturnVoid markers:

public object Any(GetCustomerOrders request)
    return new GetCustomerOrders {
        Customer = Gateway.Send(new GetCustomer { Id = request.Id }),
        Orders = Gateway.Send(new QueryOrders { CustomerId = request.Id })

Or you can use the Async API if you prefer the non-blocking version:

public async Task<GetCustomerOrdersResponse> Any(GetCustomerOrders request)
    return new GetCustomerOrdersResponse {
        Customer = await Gateway.SendAsync(new GetCustomer { Id = request.Id }),
        Orders = await Gateway.SendAsync(new QueryOrders { CustomerId = request.Id })

The capability that sets the ServiceGateway apart (other than offering a nicer API to work with) is that this System could later have its Customer and Order Subsystems split out into different hosts and this exact Service implementation would continue to function as before, albeit a little slower due to the overhead of any introduced out-of-process communications.

The default implementation of IServiceGateway uses the InProcessServiceGateway which delegates the Request DTO to the appropriate ServiceController.Execute() or ServiceController.ExecuteAsync() methods to execute the Service. One noticeable difference is that any Exceptions thrown by downstream Services are automatically converted into the same WebServiceException that clients would throw when calling the Service externally, this is so Exceptions are indistinguishable whether it's calling an internal Service or an external one, which begins touching on the benefits of the Gateway...

The ServiceGateway is the same interface whether you're calling an Internal Service on the Server or a remote Service from a client. It exposes an ideal message-based API that's optimal for remote Service Integrations that also supports Auto Batched Requests for combining multiple Service Calls into a single Request, minimizing latency when possible.

Substitutable Service Gateways

These characteristics makes it easy to substitute and customize the behavior of the Gateway as visible in the examples below. The easiest scenario to support is to redirect all Service Gateway calls to a remote ServiceStack instance which can be done by registering any .NET Service Client against the IServiceGateway interface, e.g:

public override void Configure(Container container)
    container.Register<IServiceGateway>(c => new JsonServiceClient(baseUrl));

A more likely scenario you'd want to support is a mix where internal requests are executed in-process and external requests call their respective Service. If your system is split in two this becomes a simple check to return the local InProcess Gateway for Requests which are defined in this ServiceStack instance otherwise return a Service Client configured to the alternative host when not, e.g:

public class CustomServiceGatewayFactory : ServiceGatewayFactoryBase
    public override IServiceGateway GetGateway(Type requestType)
        var isLocal = HostContext.Metadata.RequestTypes.Contains(requestType);
        var gateway = isLocal
            ? (IServiceGateway)base.localGateway
            : new JsonServiceClient(alternativeBaseUrl);
        return gateway;

For this we needed to implement the IServiceGatewayFactory so we can first capture the current IRequest that's needed in order to call the In Process Service Gateway with. The convenience ServiceGatewayFactoryBase abstracts the rest of the API away so you're only tasked with returning the appropriate Service Gateway for the specified Request DTO.

Capturing the current IRequest makes the Gateway factory instance non-suitable to use as a singleton, so we'll need to register it with a ReuseScope.None scope so a new instance is resolved each time:

public override void Configure(Container container)
    container.Register<IServiceGatewayFactory>(x => new CustomServiceGatewayFactory())

Service Discovery

This demonstrates the underpinnings by which we can plug into and intercept all intra-Service calls and apply our own high-level custom logic which sets the foundation for other value-added functionality like Service Discovery which can transparently route service calls to the most appropriate available remote endpoint at run-time, automatically without additional configuration or code-maintenance overhead.

Designing for Microservices

Whether or not Systems benefit overall from a fine-grained microservices architecture, enough to justify the additional latency, management and infrastructure overhead it requires, we still see value in the development process of designing for Microservices where decoupling naturally isolated components into loosely-coupled subsystems has software-architecture benefits with overall complexity of an entire system being reduced into smaller, more manageable logical scopes which encapsulates their capabilities behind re-usable, coarse-grained messages to small, well-defined facades.

The ServiceGateway and its Services Discovery ecosystem together with ServiceStack's recommended use of impl-free reusable POCO DTO's and its ability to modularize Service implementations across multiple projects naturally promote a microservices-ready architecture where Service interactions are loosely-coupled behind well-defined, reusable, coarse-grained messages. Designing systems in this way later allows the isolated Service Implementation .dll to be extracted from the main System and wrapped into its own AppHost. Together with an agreed Service Discovery solution, allows you to spawn multiple instances of the new Service - letting you scale, deploy and maintain it independently from the rest of the system.

  1. Getting Started

    1. Creating your first project
    2. Create Service from scratch
    3. Your first webservice explained
    4. Example Projects Overview
    5. Learning Resources
  2. Designing APIs

    1. ServiceStack API Design
    2. Designing a REST-ful service with ServiceStack
    3. Simple Customer REST Example
    4. How to design a Message-Based API
    5. Software complexity and role of DTOs
  3. Reference

    1. Order of Operations
    2. The IoC container
    3. Configuration and AppSettings
    4. Metadata page
    5. Rest, SOAP & default endpoints
    6. SOAP support
    7. Routing
    8. Service return types
    9. Customize HTTP Responses
    10. Customize JSON Responses
    11. Plugins
    12. Validation
    13. Error Handling
    14. Security
    15. Debugging
    16. JavaScript Client Library (ss-utils.js)
  4. Clients

    1. Overview
    2. C#/.NET client
      1. .NET Core Clients
    3. Add ServiceStack Reference
      1. C# Add Reference
      2. F# Add Reference
      3. VB.NET Add Reference
      4. Swift Add Reference
      5. Java Add Reference
    4. Silverlight client
    5. JavaScript client
      1. Add TypeScript Reference
    6. Dart Client
    7. MQ Clients
  5. Formats

    1. Overview
    2. JSON/JSV and XML
    3. HTML5 Report Format
    4. CSV Format
    5. MessagePack Format
    6. ProtoBuf Format
  6. View Engines 4. Razor & Markdown Razor

    1. Markdown Razor
  7. Hosts

    1. IIS
    2. Self-hosting
    3. Messaging
    4. Mono
  8. Security

    1. Authentication
    2. Sessions
    3. Restricting Services
    4. Encrypted Messaging
  9. Advanced

    1. Configuration options
    2. Access HTTP specific features in services
    3. Logging
    4. Serialization/deserialization
    5. Request/response filters
    6. Filter attributes
    7. Concurrency Model
    8. Built-in profiling
    9. Form Hijacking Prevention
    10. Auto-Mapping
    11. HTTP Utils
    12. Dump Utils
    13. Virtual File System
    14. Config API
    15. Physical Project Structure
    16. Modularizing Services
    17. MVC Integration
    18. ServiceStack Integration
    19. Embedded Native Desktop Apps
    20. Auto Batched Requests
    21. Versioning
    22. Multitenancy
  10. Caching

  11. Caching Providers

  12. HTTP Caching

  13. CacheResponse Attribute

  14. Cache Aware Clients

  15. Auto Query

  16. Overview

  17. Why Not OData

  18. AutoQuery RDBMS

  19. AutoQuery Data

  20. AutoQuery Memory

  21. AutoQuery Service

  22. AutoQuery DynamoDB

  23. Server Events

    1. Overview
    2. JavaScript Client
    3. C# Server Events Client
    4. Redis Server Events
  24. Service Gateway

    1. Overview
    2. Service Discovery
  25. Encrypted Messaging

    1. Overview
    2. Encrypted Client
  26. Plugins

    1. Auto Query
    2. Server Sent Events
    3. Swagger API
    4. Postman
    5. Request logger
    6. Sitemaps
    7. Cancellable Requests
    8. CorsFeature
  27. Tests

    1. Testing
    2. HowTo write unit/integration tests
  28. ServiceStackVS

    1. Install ServiceStackVS
    2. Add ServiceStack Reference
    3. TypeScript React Template
    4. React, Redux Chat App
    5. AngularJS App Template
    6. React Desktop Apps
  29. Other Languages

    1. FSharp
      1. Add ServiceStack Reference
    2. VB.NET
      1. Add ServiceStack Reference
    3. Swift
    4. Swift Add Reference
    5. Java
      1. Add ServiceStack Reference
      2. Android Studio & IntelliJ
      3. Eclipse
  30. Amazon Web Services

  31. ServiceStack.Aws

  32. PocoDynamo

  33. AWS Live Demos

  34. Getting Started with AWS

  35. Deployment

    1. Deploy Multiple Sites to single AWS Instance
      1. Simple Deployments to AWS with WebDeploy
    2. Advanced Deployments with OctopusDeploy
  36. Install 3rd Party Products

    1. Redis on Windows
    2. RabbitMQ on Windows
  37. Use Cases

    1. Single Page Apps
    2. HTML, CSS and JS Minifiers
    3. Azure
    4. Connecting to Azure Redis via SSL
    5. Logging
    6. Bundling and Minification
    7. NHibernate
  38. Performance

    1. Real world performance
  39. Other Products

    1. ServiceStack.Redis
    2. ServiceStack.OrmLite
    3. ServiceStack.Text
  40. Future

    1. Roadmap
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.