ServiceStack v4.0.33

OrmLite now supports Async!

Another major feature request is ticked off in this release with the new Async support available in OrmLite!

A quick overview of the new Async API's added can be seen in the class diagram below:

OrmLite Async APIs

Basically most of OrmLite public API's now have async equivalents of the same name and an additional conventional *Async suffix. The Async API's also take an optional CancellationToken making converting sync code trivial, where you just need to add the Async suffix and await keyword, as can be seen in the Customer Orders UseCase upgrade to Async diff , e.g:

Sync:

db.Insert(new Employee { Id = 1, Name = "Employee 1" });
db.Save(product1, product2);
var customer = db.Single<Customer>(new { customer.Email }); 

Async:

await db.InsertAsync(new Employee { Id = 1, Name = "Employee 1" });
await db.SaveAsync(product1, product2);
var customer = await db.SingleAsync<Customer>(new { customer.Email });

Effectively the only Data Access API's that doesn't have async equivalents are *Lazy APIs yielding a lazy sequence (incompatible with async) as well as Schema DDL API's which are typically not used at runtime.

For a quick preview of many of the new Async API's in action, checkout ApiSqlServerTestsAsync.cs.

Async RDBMS Providers

Currently only a limited number of RDBMS providers offer async API's which are only available in their .NET 4.5 builds, which at this time are only:

We've also added a .NET 4.5 build for Sqlite as it's a common use-case to swapout to use Sqlite's in-memory provider for faster tests. But as Sqlite doesn't provide async API's under-the-hood we fallback to pseudo async support where we just wrap its synchronous responses in Task results.

Regardless of whether the RDBMS provider offers Async API's, you still can use the same OrmLite async API's with all providers, where the same Async OrmLite API's can also be used in DB Providers that doesn't natively support Async (i.e. Sqlite):

Only when these Async API's are run on an RDBMS provider with native async support (i.e. .NET 4.5 SqlServer or MySql) will you benefit from true non-blocking Async I/O, otherwise it fallsback to pseudo async support, i.e. synchronous I/O datasets wrapped in Task Results.

Multiple Self References

OrmLite's POCO Reference conventions has been expanded to include support for multiple Self References.

The example below shows a customer with multiple CustomerAddress references which are able to be matched with the {PropertyReference}Id naming convention, e.g:

public class Customer
{
    [AutoIncrement]
    public int Id { get; set; }
    public string Name { get; set; }

    [References(typeof(CustomerAddress))]
    public int? HomeAddressId { get; set; }

    [References(typeof(CustomerAddress))]
    public int? WorkAddressId { get; set; }

    [Reference]
    public CustomerAddress HomeAddress { get; set; }

    [Reference]
    public CustomerAddress WorkAddress { get; set; }
}

Once defined, it can be saved and loaded via OrmLite's normal Reference and Select API's, e.g:

var customer = new Customer
{
    Name = "Z Customer",
    HomeAddress = new CustomerAddress {
        Address = "1 Home Street",
        Country = "US"
    },
    WorkAddress = new CustomerAddress {
        Address = "2 Work Road",
        Country = "UK"
    },
};

db.Save(customer, references:true);

var c = db.LoadSelect<Customer>(q => q.Name == "Z Customer");
c.WorkAddress.Address.Print(); // 2 Work Road

var ukAddress = db.Single<CustomerAddress>(q => q.Country == "UK");
ukAddress.Address.Print();     // 2 Work Road

ServiceStack.Redis SSL Support

The most requested feature for ServiceStack.Redis has also been realized in this release with ServiceStack.Redis now supporting SSL connections making it suitable for accessing remote Redis server instances over a secure SSL connection.

Azure Redis Cache

Redis Use Cases

Redis is normally used as a back-end datastore whose access is typically limited to Internal networks or authorized networks protected via firewalls. The new SSL Support in the Redis Client also enables secure access to a redis-server instance over the Internet and public networks as well, a scenario that's been recently popularized by Cloud hosting environments like Azure Redis Cache.

Connecting to Azure Redis

As connecting to Azure Redis Cache via SSL was the primary use-case for this feature, we've added a new Getting connected to Azure Redis via SSL to help you get started.

Redis Connection Strings

Redis Connection strings have been expanded to support the more versatile URI format which is now able to capture most of Redis Client settings in a single connection string (akin to DB Connection strings).

Redis Connection Strings supports multiple URI-like formats, from a simple hostname or IP Address and port pair to a fully-qualified URL with multiple options specified on the QueryString.

Some examples of supported formats:

localhost
127.0.0.1:6379
redis://localhost:6379
password@localhost:6379
clientid:password@localhost:6379
redis://clientid:password@localhost:6380?ssl=true&db=1

More examples can be seen in ConfigTests.cs

Any additional configuration can be specified as QueryString parameters. The full list of options that can be specified include:

Ssl bool If this is an SSL connection
Db int The Redis DB this connection should be set to
Client string A text alias to specify for this connection for analytic purposes
Password string UrlEncoded version of the Password for this connection
ConnectTimeout int Timeout in ms for making a TCP Socket connection
SendTimeout int Timeout in ms for making a synchronous TCP Socket Send
ReceiveTimeout int Timeout in ms for waiting for a synchronous TCP Socket Receive
IdleTimeOutSecs int Timeout in Seconds for an Idle connection to be considered active
NamespacePrefix string Use a custom prefix for ServiceStack.Redis internal index colletions

New RedisManagerPool Client Manager

With the introduction of Redis URI Connection Strings we've been able to simplify and streamline the existing PooledRedisClientManager implementation that's been extracted out into clients manager called RedisManagerPool. In addition to removing all above options on the Client Manager itself, we've also removed readonly connection strings so the configuration is much simpler and more aligned with the common use-case.

In most cases, PooledRedisClientManager is substitutable with RedisManagerPool e.g:

container.Register<IRedisClientsManager>(c => 
    new RedisManagerPool(redisConnectionString));

New Generic API's for calling Custom Redis commands

Most of the time when waiting to use a new Redis Command you'll need to wait for an updated version of ServiceStack.Redis to add support for the new commands likewise there are times when the Redis Client doesn't offer every permutation that redis-server supports.

With the new Custom and RawCommand API's on IRedisClient and IRedisNativeClient you can now use the RedisClient to send your own custom commands that can call adhoc Redis commands:

public interface IRedisClient
{
    ...
    RedisText Custom(params object[] cmdWithArgs);
}

public interface IRedisNativeClient
{
    ...
    RedisData RawCommand(params object[] cmdWithArgs);
    RedisData RawCommand(params byte[][] cmdWithBinaryArgs);
}

These API's return Custom Results in the generic data structures below:

public class RedisText
{
    public string Text { get; set; }
    public List<RedisText> Children { get; set; }
}

public class RedisData
{
    public byte[] Data { get; set; }
    public List<RedisData> Children { get; set; } 
}

These Custom API's take a flexible object[] arguments which accepts any serializable value e.g. byte[], string, int as well as any user-defined Complex Types which are transparently serialized as JSON and send across the wire as UTF-8 bytes.

var ret = Redis.Custom("SET", "foo", 1);          // ret.Text = "OK"

byte[] cmdSet = Commands.Set;
ret = Redis.Custom(cmdSet, "bar", "b");           // ret.Text = "OK"

ret = Redis.Custom("GET", "foo");                 // ret.Text = "1"

There are also convenient extension methods on RedisData and RedisText that make it easy to access structured data, e.g:

var ret = Redis.Custom(Commands.Keys, "*");
var keys = ret.GetResults();                      // keys = ["foo", "bar"]

ret = Redis.Custom(Commands.MGet, "foo", "bar");
var values = ret.GetResults();                    // values = ["1", "b"]

Enum.GetNames(typeof(DayOfWeek)).ToList()
    .ForEach(x => Redis.Custom(Commands.RPush, "DaysOfWeek", x));
ret = Redis.Custom(Commands.LRange, "DaysOfWeek", 1, -2);
var weekDays = ret.GetResults();      

weekDays.PrintDump(); // ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

and some more examples using Complex Types with the Custom API's:

var ret = Redis.Custom(Commands.Set, "foo", new Poco { Name = "Bar" }); // ret.Text = "OK"

ret = Redis.Custom(Commands.Get, "foo");          // ret.Text =  {"Name":"Bar"}
Poco dto = ret.GetResult<Poco>();

dto.Name.Print(); // Bar

New Config, Role and Client commands

A number of New API's added in this can be seen below:

public interface IRedisClient
{
    ...
    RedisText GetServerRoleInfo();
    string GetConfig(string item);
    void SetConfig(string item, string value);
    void SaveConfig();
    void ResetInfoStats();

    string GetClient();
    void SetClient(string name);
    void KillClient(string address);
    long KillClients(string fromAddress = null, 
        string withId = null, RedisClientType? ofType = null, bool? skipMe = null);
    List<Dictionary<string, string>> GetClientsInfo();
    void PauseAllClients(TimeSpan duration);
}

public interface IRedisNativeClient
{
    ...
    void ConfigRewrite();
    RedisText Role();
    string ClientGetName();
    void ClientSetName(string client);
    void ClientKill(string host);
    long ClientKill(string addr = null, string id = null, string type = null, string skipMe = null);
    byte[] ClientList();
    void ClientPause(int timeOutMs);    
}

New VB.NET Add ServiceStack Reference!

This release also adds Add ServiceStack Reference support for the last remaining major .NET language with the new first-class support for VB.NET Add ServiceStack Reference!

This now allows any C#, F# or VB.NET client project to be able generate and end-to-end typed API for your services just by providing the url of your remote ServiceStack instance, directly from within VS.NET!

Add ServiceStack Reference

After clicking OK, the servers DTO's and ServiceStack.Client NuGet package are added to the project, providing an instant typed API:

Calling a ServiceStack Service from VB.NET

Thanks to the close semantics between the C# and VB.NET languages, we're able to add support for all C# customization options in VB.NET as well.

Much of the new VB.NET NativeTypes provider is thanks to the efforts of @KevinHoward.

Upgrade ServiceStackVS

To take advantage of VB.NET Add ServiceStack Reference feature, Upgrade or Install ServiceStackVS VS.NET Extension. If you already have ServiceStackVS installed, uninstall it first from Tools -> Extensions and Updates... -> ServiceStackVS -> Uninstall.

Simplified UX for all languages

Our first iteration of Add ServiceStack Reference for C# used a T4 Template to make it easy for clients to view and modify all Customization options available and to be able to auto-generate the Server DTO's by modifying and saving (or re-running) the T4 template.

As F# projects didn't support T4 Templates, when we added support for F# Add ServiceStack Reference we had to skip the T4 template and add the server-generated DTO's source file directly to the project.

By skipping the T4 Template we pleasantly discovered we ended up with a nicer, simplified and more user-friendly UX, with less moving parts for the default use case of generating client DTO's based on the Default Server Configuration.

Improving Single Generated Source File Story

We've since decided to embrace and provide a better development experience around a single source file approach and use it consistently in all C#, F# and VB.NET projects - now resulting simpler Add ServiceStack Reference UX for all client projects.

Update ServiceStack Reference Context Menu Item

With the latest ServiceStackVS you can now update the Server DTO's in all projects by clicking on Update ServiceStack Reference on the context-menu, e.g:

Update ServiceStack Reference

Updating and Customizing Generated Types

To customize the generated DTO's on the client you can just uncomment the option you want to change directly in the header comments and hit save. ServiceStackVS automatically watches for any changes to the generated dto source files (i.e. ending with .dtos.cs) and will automatically send the uncommented options to the remote server referenced by the BaseUrl and replace the existing file with the updated DTOs instantly!

Taking the example below, once we uncomment the MakePartial option and save the file, ServiceStackVS automatically sends a new request to the remote ServiceStack instance, passing in the ?MakePartial=False option when requesting updated DTO's:

/* Options:
Date: 2014-10-21 00:44:24
Version: 1
BaseUrl: https://stackapis.netcore.io

MakePartial: False
//MakeVirtual: True
//MakeDataContractsExtensible: False
//AddReturnMarker: True
//AddDescriptionAsComments: True
//AddDataContractAttributes: False
//AddIndexesToDataMembers: False
//AddResponseStatus: False
//AddImplicitVersion: 
//InitializeCollections: True
//AddDefaultXmlNamespace: http://schemas.servicestack.net/types
*/

After saving you'll be able to notice the DTO's are updated instantly with the Date: * changing to reflect the current time and the new generated DTO's no longer containing partial classes.

ServiceStack.Text

New JsConfig<T>.OnDeserializing and dynamic ShouldSerialize(string field) customization options were added to ServiceStack's JSON and JSV Text serializers by @pavelsavara. An example of these new customization options in action is visible below:

[DataContract]
public class CustomSerializedPoco
{
    [IgnoreDataMember]
    public HashSet<string> hasAttribute;

    [DataMember(EmitDefaultValue = false, IsRequired = false)]
    public int A { get; set; }

    [DataMember(EmitDefaultValue = false, IsRequired = false)]
    public int? B { get; set; }

    public bool? ShouldSerialize(string fieldName)
    {
        return hasAttribute == null 
            ? null
            :  hasAttribute.Contains(fieldName);
    }

    public object OnDeserializing(string fieldName, object value)
    {
        if (hasAttribute == null)
            hasAttribute = new HashSet<string>();
        hasAttribute.Add(fieldName);
        return value;
    }
}

This change makes it possible to create dynamic POCO's that behave in a similar way that dynamic languages can, e.g. After deserialization you can detect which fields were deserialized by inspecting the hasAttribute collection.

The ShouldSerialize API, closely follows the existing ShouldSerialize{X} convention but instead allows for a single API to handle all serializable properties.

The API returns a bool? which has the following meaning:

  • true - Should be emitted
  • false - Should not be emitted
  • null - Use default behavior

This allows us to implement a custom type that can support full round-trip when the field on the original JSON payload allowing use to implement a custom type with similar functionality to IExtensibleDataObject which allows survival and forwarding of unknown properties, but for JSON.

RabbitMQ

RabbitMQ Server and Client now have optional PublishMessageFilter and GetMessageFilter callbacks which can be used to intercept outgoing and incoming messages, the IBasicProperties.Type is also pre-populated with the Type name of the message body that was published, e.g:

var mqServer = new RabbitMqServer("localhost") 
{
    PublishMessageFilter = (queueName, properties, msg) => {
        properties.AppId = "app:{0}".Fmt(queueName);
    },
    GetMessageFilter = (queueName, basicMsg) => {
        var props = basicMsg.BasicProperties;
        receivedMsgType = props.Type; //automatically added by RabbitMqProducer
        receivedMsgApp = props.AppId;
    }
};

using (var mqClient = mqServer.CreateMessageQueueClient())
{
    mqClient.Publish(new Hello { Name = "Bugs Bunny" });
}

receivedMsgApp.Print();   // app:mq:Hello.In
receivedMsgType.Print();  // Hello

Other Minor Changes

  • ServerEvents Server now echoes heartbeat messages back through to the listening connection, ServerEventsClient only fires the OnHeartbeat callback when it's receives the echoed cmd.Heartbeat command message
  • Request binding for Path and QueryString variables are added to DTO's with Request DTO's providing their own custom body deserialization by implementing IRequiresRequestStream
  • New IAppHost.OnDisposeCallbacks available allowing Plugins to register callbacks when AppHost is disposed
  • Config.UseHttpsLinks now modifies generated BaseUrl of all links to use https
  • The ResponseStatus on Custom DTO's are now preserved when thrown inside a custom HttpError response
  • Equality members added to [Route], [Authenticate], [RequiredRole] and [RequiredPermission] attributes
  • ToOptimizedResultUsingCache no longer double-encodes raw string responses
  • MvcHtmlString was moved to ServiceStack.Html namespace
  • New StaticFileHandler.ResponseFilter added to be able to modify custom headers returned on static files
  • Many of OrmLite's static Extension method classes were renamed into a more logical grouping. These changes are source compatible for typical usage of OrmLite API's, i.e. referenced as extension methods

Breaking changes

Added new .NET 4.5 Builds

In preparation for introducing Async API's we've added new .NET 4.5 builds for the following packages:

  • ServiceStack.OrmLite
  • ServiceStack.OrmLite.Sqlite.Mono
  • ServiceStack.OrmLite.SqlServer
  • ServiceStack.OrmLite.MySql
  • ServiceStack.Server

When adding ServiceStack NuGet Packages to a .NET 4.5 project you will now get these newer .NET 4.5 builds instead. The additional builds means you could potentially run into issues if mixing .NET v4.0 and v4.5 builds as all dependencies need to reference the same build version.

Should you need to, the easiest way to fix any versioning issues is to make sure all projects use the same .NET Framework version (e.g. .NET 4.5) and then just uninstall and re-install the ServiceStack NuGet packages.

Removed ThreadStatic OrmLite Configuration

We've also removed our existing ThreadStatic config variables (used to temporarily override global configuration). Most per-connection state is now stored on the connection e.g. CommandTimeout was previously overridden with:

var hold = OrmLiteConfig.TSCommandTimeout;
try {
	OrmLiteConfig.TSCommandTimeout = 60;
	db.Select(...);
} finally {
	OrmLiteConfig.TSCommandTimeout = hold;
}

Is now set directly on the connection (and only applies to that connection), e.g:

using (var db = DbFactory.Open())
{
	db.SetCommandTimeout(60);
	db.Select(...);
}

Likewise if you ever need to access the current OrmLiteConfig.DialectProvider, it should now be retrieved from the IDbConnection, i.e:

db.GetDialectProvider();

and if you ever need to access the underlying ADO.NET IDbConnection or IDbCommand you can access them via the following APIs:

IDbConnection adoDb = db.ToDbConnection();
IDbCommand adoDbCmd = dmCmd.ToDbCommand();

IReturnVoid now returns void

All IReturnVoid API's on Service Clients have been changed to return void instead of HttpWebResponse which needed to be explicitly disposed by the callee.

To access the HttpWebResponse, Request DTO's can be changed to IReturn<HttpWebResponse>

public class EmptyResponse : IReturn<HttpWebResponse> { ... }

Alternatively the Response can be specified on the call-site with:

HttpWebResponse response = client.Get<HttpWebResponse>(new EmptyResponse());