Service Gateway

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

  1. Getting Started

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

    1. ServiceStack API Design
    2. Designing a REST-ful service with ServiceStack
      1. Simple Customer REST Example
    3. How to design a Message-Based API
    4. 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

    1. Razor & Markdown Razor
    2. 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

    1. Caching Providers
    2. HTTP Caching
      1. CacheResponse Attribute
      2. Cache Aware Clients
  11. Auto Query

    1. Overview
    2. Why Not OData
    3. AutoQuery RDBMS
    4. AutoQuery Data
      1. AutoQuery Memory
      2. AutoQuery Service
      3. AutoQuery DynamoDB
  12. Server Events

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

    1. Overview
    2. Service Discovery
  14. Encrypted Messaging

    1. Overview
    2. Encrypted Client
  15. Plugins

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

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

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

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

    1. ServiceStack.Aws
    2. PocoDynamo
    3. AWS Live Demos
    4. Getting Started with AWS
  20. Deployment

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

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

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

    1. Real world performance
  24. Other Products

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

    1. Roadmap
Clone this wiki locally

This page has moved to docs.servicestack.net/service-gateway


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:

[Route("/customers/{Id}")]
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())
        .ReusedWithin(ReuseScope.None);
}

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.