Edit on GitHub

v4.0.31 Release Notes

The most requested feature since our last release was to expand our last releases support for Server Sent Events with both a scale-out Redis ServerEvents back-end for use in load-balanced App Servers scenarios as well as a typed C# ServerEvents Client - we’re happy to announce we’ve been able to deliver both features in this release!

Major features in this release

Redis ServerEvents

One limitation the default MemoryServerEvents implementation has is being limited for use within a single App Server where all client connections are maintained. This is no longer a limitation with the new Redis ServerEvents back-end which utilizes a distributed redis-server back-end to provide a scale-out option capable of serving fan-out/load-balanced App Servers. If you’re familiar with SignalR, this is akin to SignalR’s scaleout with Redis back-end.

RedisServerEvents is a drop-in replacement for the built-in MemoryServerEvents that’s effectively a transparent implementation detail, invisible to Server or Client API’s where both implementations even share the same integration Tests.

Redis ServerEvents Scale Out

Enabling RedisServer Events

As a drop-in replacement it can easily be configured with just a few lines of code, as seen in the updated Chat App which can run on either Memory or Redis ServerEvents providers:

var redisHost = AppSettings.GetString("RedisHost");
if (redisHost != null)
{
    container.Register<IRedisClientsManager>(new PooledRedisClientManager(redisHost));

    container.Register<IServerEvents>(c => 
        new RedisServerEvents(c.Resolve<IRedisClientsManager>()));
    
    container.Resolve<IServerEvents>().Start();
}

The above configuration will use Redis ServerEvents if there’s a RedisHost appSetting in Chat’s Web.config:

<add key="RedisHost" value="localhost:6379" />

Cross-platform Memory and Redis ServerEvent Enabled Chat.exe

To showcase Redis ServerEvents in action, we’ve prepared a stand-alone ServiceStack.Gap version of Chat compiled down into a single Chat.exe that can run on either Windows and OSX with Mono which can be downloaded from:

Chat.zip (1.2MB)

Redis ServerEvents Preview

As Chat only runs on 2 back-end Services, it fits well within ServiceStack’s Free Quota’s which can be further customized and enhanced without a commercial license.

Running Chat.exe without any arguments will run Chat using the default Memory ServerEvents. This can be changed to use Redis ServerEvents by un-commenting this line in appsettings.txt:

#redis localhost

This will require a redis-server running on localhost. If you don’t have redis yet, download redis-server for Windows.

Alternatively you can specify which port to run Chat on and change it to use Redis ServerEvents by specifying the redis instance it should connect to on the command-line with:

Chat.exe /port=1337 /redis=localhost

Also included in Chat.zip are test-fanout-redis-events.bat and equivalent test-fanout-redis-events.sh helper scripts for spawning multiple versions of Chat.exe on different ports (and backgrounds) for Windows or OSX, showing how multiple clients are able to send messages to each other via Redis whilst being subscribed to different HTTP Servers:

START Chat.exe /port=1337 /redis=localhost
START Chat.exe /port=2337 /redis=localhost /background=http://bit.ly/1oQqhtm
START Chat.exe /port=3337 /redis=localhost /background=http://bit.ly/1yIJOBH

This script was used to create the animated gif above to launch 3 self-hosting instances of Chat.exe running on different ports, all connected to each other via Redis. This enables some interesting peer-to-peer scenarios where users are able to run a network of (CPU/resource isolated) decentralized stand-alone HTTP Servers on their local machines, but can still communicate with each other via redis.

C# ServerEvents Client

Like ServiceStack’s other C# Service Clients, the new ServerEventsClient is a portable library contained in the ServiceStack.Client NuGet package:

PM> Install-Package ServiceStack.Client

And like the Service Clients it requires the BaseUri of your ServiceStack instance as well as an optional channel for the client to subscribe to:

var client = new ServerEventsClient("http://chat.servicestack.net", channel:"home");

Managed Connection

The C# ServerEvent Client is a managed .NET client with feature parity with the ServiceStack’s JavaScript client that auto-reconnects when a connection is lost, sends periodic heartbeats to maintain an active subscription as well as auto-unregistering once the client stops listening for messages, or gets disposed.

Handling Server Events

Unlike other C# clients, the ServerEvents Client is mainly reactive in that it’s primarily waiting for Server Events to be initiated from a remote server instead of the typical scenario in which requests are initiated by clients. To maximize utility, there are a number of different API’s to receive and process messages:

Assigning Callback Handlers

One way to receive messages (useful in long-running clients) is to assign handlers for each of the different events that are fired. This example shows how to capture all the different events a Client can receive:

ServerEventConnect connectMsg = null;
var msgs = new List<ServerEventMessage>();
var commands = new List<ServerEventMessage>();
var errors = new List<Exception>();

var client = new ServerEventsClient(baseUri) {
    OnConnect = e => connectMsg = e,
    OnCommand = commands.Add,
    OnMessage = msgs.Add,
    OnException = errors.Add,
}.Start();

Once the Client is configured, calling Start() will start listening for messages and calling Stop() or Dispose() will cancel the background HTTP connection and stop it listening for server events.

Customizing Metadata sent to clients

As ServerEvents have deep integration with the rest of ServiceStack we’re able to offer Typed Messages containing the users UserAuthId, DisplayName and ProfileUrl of the users avatar when it’s available. The typed messages also offer an extensible Dictionary<string,string> Meta collection for maintaining custom metadata that can be sent to clients by appending to them in the ServerEventsFeature hooks, which can be defined when registering ServerEventsFeature:

Plugins.Add(new ServerEventsFeature { 
    // private Connect args
    OnConnect = (subscription,httpReq) => AppendTo(subscription.Meta),

    // public Join/Leave args
    OnCreated = (subscription,httpReq) => AppendTo(subscription.Meta), 
})

Using C# Async/Await friendly API’s

Depending on your use-case, if you only want to use the ServerEvent Client for a short-time to listen for predictable responses (i.e. waiting for a Server callback on a pending request) you can alternatively use the Task-based API’s letting you to participate in C# async/await workflows:

var client = new ServerEventsClient(baseUri, channel="Home");

// Wait to receive onConnect event
ServerEventConnect connectMsg = await client.Connect();

// Wait to receive onJoin command event
ServerEventCommand joinMsg = await client.WaitForNextCommand();

// Hold a future task to get notified once a msg has been received
Task<ServerEventMessage> msgTask = client1.WaitForNextMessage();

// Send a Web Service Request using the built-in JsonServiceClient
client.ServiceClient.Post(new PostChatToChannel {
    Channel = client.Channel,     // The channel we're listening on
    From = client.SubscriptionId, // SubscriptionId Populated after Connect() 
    Message = "Hello, World!",
});

// Wait till we receive the chat Msg event we sent earlier
ServerEventMessage msg = await msgTask;

The above example showcases the 3 Task-based API’s available:

  1. Connect() wait till receiving confirmation of a successful event subscription
  2. WaitForNextCommand() wait for the next onJoin or onLeave subscription events
  3. WaitForNextMessage() wait for the next message published to the channel

The ServiceClient property lets you access a JsonServiceClient that’s pre-configured with the clients BaseUri so that is primed for Sending Web Service Requests with.

After the ServerEvent Client has connected, the ConnectionInfo property is populated with the typed ServerEventConnect response.

Message Event Handlers

The above examples show generic API’s for receiving any type of message, but just like in the JavaScript client, more fine-grained API’s are available for handling specific message types.

The Handlers dictionary is akin to the JavaScript Client’s Global Event Handlers which specify lambda’s to be executed when messages are sent with the cmd.* selector:

client.Handlers["chat"] = (client, msg) => {
    var chatMsg = msg.Json.FromJson<ChatMessage>(); //Deserialize JSON string to typed DTO
    "Received '{0}' from '{1}'".Print(chatMsg.Message, chatMsg.FromName);
};

Roughly translates to the equivalent JavaScript below:

$(source).handleServerEvents({
    handlers: {
        chat: function (msg, event) {
            console.log("Received " + msg.message + " from " + msg.fromName);
        }
    }
});

Where both methods handle the ChatMessage sent with the cmd.chat selector.

Named Receivers

Whilst handlers provide a light way to handle loose-typed messages, there’s a more structured and typed option that works similar to ServiceStack’s IService classes but are used to instead handle typed Server Event Messages.

To be able to handle messages with your own classes, get them to implement the IReceiver empty marker interface:

public interface IReceiver
{
    void NoSuchMethod(string selector, object message);
}

Whilst primarily a marker interface, IReceiver does include a NoSuchMethod API to be able to handle messages sent with a unknown selector target that doesn’t match any defined method or property.

Named Receivers are equivalent to Receivers in the JavaScript client which can be assigned to handle all messages sent to a receiver with the selector format:

{receiver}.{target}

A Named Receiver can be registered with the API below:

client.RegisterNamedReceiver<TestNamedReceiver>("test");

Which will forward all messages with a test.* selector to an instance of the TestNamedReceiver Type

public class TestNamedReceiver : ServerEventReceiver
{
    public void FooMethod(CustomType request) {} // void return type

    public CustomType BarMethod(CustomType request)
    {        
        return request; // works with any return type, which are ignored
    }

    public CustomType BazSetter { get; set; } // Auto populate properties

    public override void NoSuchMethod(string selector, object message)
    {
        var msg = (ServerEventMessage)message;
        var nonExistentMethodCustomType = msg.Json.FromJson<CustomType>();
    }
}

This is roughly equivalent to the following JavaScript code:

$(source).handleServerEvents({
    receivers: {
        test: {
            FooMethod: function (msg, event) { ... },
            BarMethod: function (msg, event) { ... },
            BazSetter: null,            
        }
    }
});

The ServerEventReceiver is a convenient base class that in addition to implementing IReceiver interface, gets injected with the Client as well as additional context about the raw message available in base.Request.

Unknown Message Handling

One difference in the JavaScript client is that messages with unknown targets are assigned as properties on the test receiver, e.g test.QuxTarget = {..}.

Sending messages to Named Receivers

Once registered, an instance of TestNamedReceiver will process messages sent with a test.* selector. The example below shows how to send a DTO to each of TestNamedReceiver defined methods and properties:

public class MyEventServices : Service
{
    public IServerEvents ServerEvents { get; set; }

    public void Any(CustomType request)
    {
        ServerEvents.NotifyChannel("home", "test.FooMethod", request);
        ServerEvents.NotifyChannel("home", "test.BarMethod", request);
        ServerEvents.NotifyChannel("home", "test.BazSetter", request);

        ServerEvents.NotifyChannel("home", "test.QuxTarget", request);
    }
}

Life-cycle of Receivers

Similar to Services in ServiceStack, each message is processed with an instance of the Receiver that’s resolved from ServerEventsClient.Resolver which by default uses the NewInstanceResolver to execute messages using a new instance of the Receiver Type:

public class NewInstanceResolver : IResolver
{
    public T TryResolve<T>()
    {
        return typeof(T).CreateInstance<T>();
    }
}

This can be changed to re-use the same instance by assigning a SingletonInstanceResolver instead:

public class SingletonInstanceResolver : IResolver
{
    ConcurrentDictionary<Type, object> Cache = new ConcurrentDictionary<Type, object>();

    public T TryResolve<T>()
    {
        return (T)Cache.GetOrAdd(typeof(T), type => type.CreateInstance<T>());
    }
}

client.Resolver = new SingletonInstanceResolver();

We can also have it resolve instances from your preferred IOC. Here’s an example showing how to register all Receiver Types, auto-wire them with any custom dependencies, and instruct the client to resolve instances from our IOC:

// Register all Receivers:
client.RegisterNamedReceiver<TestNamedReceiver>("test");
...

// Register all dependencies used in a new Funq.Container:
var container = new Container();
container.RegisterAs<Dependency, IDependency>();

// Go through an auto-wire all Registered Receiver Types with Funq:
container.RegisterAutoWiredTypes(client.ReceiverTypes);

// Change the client to resolve receivers from the new Funq Container:
client.Resolver = container;

We can assign Funq.Container directly as it already implements the IResolver interface, whilst you can re-use the existing IOC Container Adapters to enable support for other IOCs.

The Global Receiver

Whilst Named Receivers are used to handle messages sent to a specific namespaced selector, the client also supports registering a Global Receiver for handling messages sent with the special cmd.* selector.

Handling Messages with the Default Selector

All IServerEvents Notify API’s inlcudes overloads for sending messages without a selector that by convention will take the format cmd.{TypeName}.

These events can be handled with a Global Receiver based on Message type, e.g:

public class GlobalReceiver : ServerEventReceiver
{
    public SetterType AnyNamedProperty { get; set; }

    public void AnyNamedMethod(CustomType request)
    {
        ...
    }
}

client.RegisterReceiver<GlobalReceiver>();

Which will be called when messages are sent without a selector, e.g:

public class MyServices : Service
{
    public IServerEvents ServerEvents { get; set; }

    public void Any(Request request)
    {
        ServerEvents.NotifyChannel("home", new CustomType { ... });
        ServerEvents.NotifyChannel("home", new SetterType { ... });
    }
}

As Global Receivers handle other messages sent with the cmd.* selector and can be re-used as a named receiver, we can define a single class to handle all the different custom messages sent in chat.servicestack.net App, E.g:

cmd.chat Hi
cmd.announce This is your captain speaking...
cmd.toggle#channels
css.background-image url(https://servicestack.net/img/bg.jpg)
...

The above messages can all be handled with the Receiver below:

public class JavaScriptReceiver : ServerEventReceiver
{
    public void Chat(ChatMessage message) { ... }
    public void Announce(string message) { ... }
    public void Toggle(string message) { ... }
    public void BackgroundImage(string cssRule) { ... }
}

client.RegisterNamedReceiver<JavaScriptReceiver>();
client.RegisterNamedReceiver<JavaScriptReceiver>("css");

As seen above the target names are case-insensitive and - are collapsed to cater for JavaScript/CSS naming conventions.

ServiceStack.Redis

Redis Pub/Sub Server

To power RedisServerEvents we’ve extracted the managed Pub/Sub long-running message-loop originally built for Redis MQ and encapsulated it into a re-usable class that can be used independently for handling messages published to specific Redis Pub/Sub channels.

RedisPubSubServer processes messages in a managed background thread that automatically reconnects when the redis-server connection fails and works like an independent background Service that can be stopped and started on command.

The public API is captured in the IRedisPubSubServer interface:

public interface IRedisPubSubServer : IDisposable
{
    IRedisClientsManager ClientsManager { get; }
    // What Channels it's subscribed to
    string[] Channels { get; }

    // Run once on initial StartUp
    Action OnInit { get; set; }
    // Called each time a new Connection is Started
    Action OnStart { get; set; }
    // Invoked when Connection is broken or Stopped
    Action OnStop { get; set; }
    // Invoked after Dispose()
    Action OnDispose { get; set; }

    // Fired when each message is received
    Action<string, string> OnMessage { get; set; }
    // Fired after successfully subscribing to the specified channels
    Action<string> OnUnSubscribe { get; set; }
    // Called when an exception occurs 
    Action<Exception> OnError { get; set; }
    // Called before attempting to Failover to a new redis master
    Action<IRedisPubSubServer> OnFailover { get; set; }

    int? KeepAliveRetryAfterMs { get; set; }
    // The Current Time for RedisServer
    DateTime CurrentServerTime { get; }

    // Current Status: Starting, Started, Stopping, Stopped, Disposed
    string GetStatus();
    // Different life-cycle stats
    string GetStatsDescription();
    
    // Subscribe to specified Channels and listening for new messages
    IRedisPubSubServer Start();
    // Close active Connection and stop running background thread
    void Stop();
    // Stop than Start
    void Restart();
}

To use RedisPubSubServer, initialize it with the channels you want to subscribe to and assign handlers for each of the events you want to handle. At a minimum you’ll want to handle OnMessage:

var clientsManager = new PooledRedisClientManager();
var redisPubSub = new RedisPubSubServer(clientsManager, "channel-1", "channel-2") {
        OnMessage = (channel, msg) => "Received '{0}' from '{1}'".Print(msg, channel)
    }.Start();

Calling Start() after it’s initialized will get it to start listening and processing any messages published to the subscribed channels.

App Settings

For many years our solution against using .NET’s complex XML configuration for App configuration is to store structured configuration in the Web.config appSettings which thanks to the JSV format makes it easy to read and write structured data from a single string value, e.g:

<appSettings>
    <add key="String" value="Foo"/>
    <add key="Int" value="42"/>
    <add key="List" value="A,B,C,D,E"/>
    <add key="Dict" value="A:1,B:2,C:3"/>
    <add key="Poco" value="{Foo:Bar}"/>
</appSettings>

This can be easily parsed into C# types with the IAppSettings API:

IAppSettings settings = new AppSettings();

string value = settings.Get("String");
int value = settings.Get("Int", defaultValue:1);
List<string> values = settings.GetList("List");
Dictionary<string,string> valuesMap = settings.GetDictionary("Dict");
MyConfig config = settings.Get("Poco", new MyConfig { Foo = "Baz" });

Like other ServiceStack providers, IAppSettings is a clean interface with multiple providers letting you easily change or override where you want to source your App configuration from:

We take advantage of this in our public OSS projects when we want to override public appSettings with production settings or in our stand-alone Applications by allowing us to ship our applications with more end-user friendly plain-text config file whose defaults are embedded in the stand-alone .exe, exporting it if it doesn’t exist - letting us achieve a single, portable .exe that can be xcopy’ed and run as-is.

First class AppSettings

After proving its value over the years we’ve decided to make it a first-class property on IAppHost.AppSettings which defaults to looking at .NET’s App/Web.config’s.

The new Chat.zip App explores different ways AppSettings can be used:

If there’s an existing appsettings.txt file where the .exe is run it will use that, otherwise it falls back to Web.config appSettings:

public AppHost() : base("Chat", typeof (ServerEventsServices).Assembly)
{
    var customSettings = new FileInfo("appsettings.txt");
    AppSettings = customSettings.Exists
        ? (IAppSettings)new TextFileSettings(customSettings.FullName)
        : new AppSettings();
}

As a normal property in your AppHost, AppSettings can be accessed directly in AppHost.Configure():

public void Configure(Container container)
{
    ...
    var redisHost = AppSettings.GetString("RedisHost");
    if (redisHost != null)
    {
        container.Register<IServerEvents>(c => 
            new RedisServerEvents(new PooledRedisClientManager(redisHost)));
        
        container.Resolve<IServerEvents>().Start();
    }
}

Inside your services or IOC dependencies, like any other auto-wired dependency:

public class ServerEventsServices : Service
{
    public IAppSettings AppSettings { get; set; }

    public void Any(PostRawToChannel request)
    {
        if (!IsAuthenticated && AppSettings.Get("LimitRemoteControlToAuthenticatedUsers", false))
            throw new HttpError(HttpStatusCode.Forbidden, "You must be authenticated to use remote control.");
        ...
    }   
}

Directly within Razor views:

<style>
    body {
        background-image: url(@AppSettings.Get("background","/img/bg.jpg")) 
    }
</style>

As well as outside ServiceStack, via the HostContext static class:

var redisHost = HostContext.AppSettings.GetString("redis");

AppSettings are now writable

A new Set() API was added to IAppSettings letting you save any serializable property that works for all providers:

public interface IAppSettings
{
    void Set<T>(string key, T value);
    ...
}

AppSettings.Set("Poco", new MyConfig { Foo = "Baz" });

In providers that support writable configuration natively like OrmLiteAppSettings and DictionarySettings, the settings get written through to the underlying provider. For read-only providers like Web.config’s AppSettings or TextFileSettings a shadowed cache is kept that works similar to prototypal shadowing in JavaScript where if a property doesn’t exist, setting a property will be stored on the top-level object instance which also takes precedence on subsequent property access.

Metadata Pages

The metadata pages have been expanded to include some of Swagger API Attribute annotations which now shows the parameters for the Request and Response DTO’s as well as any other DTO’s used in each metadata operation page:

Metadata Type Info

When annotated the Description also shows any allowable Enum values or range limits when provided.

HtmlFormat

The humanize feature in Auto HtmlFormat for splitting JoinedCase words with spaces can be disabled for all pages with:

HtmlFormat.Humanize = false;

Or on adhoc pages by adding #dehumanize hash param.

Authentication

Web Sudo

A common UX in some websites is to add an extra layer of protection for super protected functionality by getting users to re-confirm their password verifying it’s still them using the website, common in places like confirming a financial transaction.

WebSudo (by @tvjames) is a new feature similar in spirit requiring users to re-authenticate when accessing Services annotated with the [WebSudoRequired] attribute. To make use of WebSudo, first register the plugin:

Plugins.Add(new WebSudoFeature());

You can then apply WebSudo behavior to existing services by annotating them with [WebSudoRequired]:

[WebSudoRequired]
public class RequiresWebSudoService : Service
{
    public object Any(RequiresWebSudo request)
    {
        return request;
    }
}

Once enabled this will throw a 402 Web Sudo Required HTTP Error the first time the service is called:

var requiresWebSudo = new RequiresWebSudo { Name = "test" };
try
{
    client.Send<RequiresWebSudoResponse>(requiresWebSudo); //throws
}
catch (WebServiceException)
{
    client.Send(authRequest); //re-authenticate
    var response = client.Send(requiresWebSudo); //success!
}

Re-authenticating afterwards will allow access to the WebSudo service.

Auth Events

In order to enable functionality like WebSudo we’ve added additional hooks into the Authentication process with IAuthEvents:

public interface IAuthEvents
{
    void OnRegistered(IRequest httpReq, IAuthSession session, IServiceBase registrationService);

    void OnAuthenticated(IRequest httpReq, IAuthSession session, IServiceBase authService, 
        IAuthTokens tokens, Dictionary<string, string> authInfo);

    void OnLogout(IRequest httpReq, IAuthSession session, IServiceBase authService);

    void OnCreated(IRequest httpReq, IAuthSession session);
}

These are the same authentication hooks that were previously only available when creating a Custom UserSession by inheriting AuthUserSession. The new AuthEvents API provide a loose-typed way where plugins can tap into the same hooks by registering it with AuthFeature.AuthEvents, e.g:

public class WebSudoFeature : IPlugin, IAuthEvents
{
    public void Register(IAppHost appHost)
    {
        ...
        var authFeature = appHost.GetPlugin<AuthFeature>();
        authFeature.AuthEvents.Add(this);
    }

    // Add implementations on `IAuthEvents` handlers
    public void OnCreated(IRequest httpReq, IAuthSession session)
    {
        ...
    }
    ...
}

An alternative way for accessing IAuthEvents is to register it like a normal dependency, e.g:

container.RegisterAs<LogAuthEvents,IAuthEvents>();

To simplify custom implementations you can inherit from the empty concrete AuthEvents and choose to only implement the callbacks you’re interested in, e.g:

public class LogAuthEvents : AuthEvents
{
    public static ILog Log = LogManager.GetLogger(typeof(LogAuthEvents));

    public override void OnLogout(IRequest httpReq, IAuthSession session, IServiceBase authService) 
    {
        Log.DebugFormat("User #{0} {1} has logged out", session.UserAuthId, session.UserName);
    }
}

OrmLite

Text

Community

ServiceStack MiniProfiler Toolkit

From the wider ServiceStack Community, Michał Gajek has developed an alternative analyzer of ServiceStack’s MiniProfiler results in a comprehensive UI that allows deep introspection of your running Services. From the Project’s description:

Description

This project intends to provide tools for collecting & analyzing profiling results of ServiceStack-based apps. Not only this makes profiling possible in the scenario when no built-in web-frontend is available (like Single Page Applications), but also has several advantages over it:

Screenshots

Install

PM> Install-Package Migajek.MiniProfiling.ServiceStack.RemoteStorage

Register the Plugin:

Plugins.Add(new Migajek.Profiling.ServiceStackProfiler.MiniProfilingToolkit("http://url/", "ProjectName"));