v4.5.8 Released!

We’ve got a another feature-packed release with a number of exciting new features new support for the Open API specification enabling new integration possibilities with Azure API Management and Azure AutoRest, our real-time Server Events solution extending to new Mobile, Desktop and Server platforms, more flexible Authentication options to dramatically simplify integration with Mobile, Desktop and Web clients, effortless JWT Refresh Tokens, enhanced support for TypeScript and Java client libraries, new compression options, upgrades to the latest Fluent Validation with support for Async validators, Async Request Filters, a number of new quality OSS ServiceStack projects developed by the community and lots more use-case driven features and refinements across the entire ServiceStack suite!

Please see the v4.5.8 Release Notes for the full details, for a quick summary we’ll highlight the major features below:

Open API

We’ve added support for the Open API Specification which opens up several new integration possibilities including importing your Services into Azure API Management and generating native clients with Azure’s AutoRest. The Open API plugin also embeds Swagger UI letting you quickly explore and interact with your services.

Server Events

We’ve made great strides in this release towards our goal of expanding the Server Event ecosystem in popular Mobile, Desktop and Server platforms with new first-class implementations for Android, Java and TypeScript which now includes:

Android Java Chat

To showcase real-world usage of AndroidServerEventsClient in an Android App we’ve ported C# Xamarin Android Chat into Java 8 using Google’s recommended Android Studio Development Environment.

In addition to retaining the same functionality as the original C# Xamarin.Android Chat App, it also leverages the native Facebook, Twitter and Google SDK’s to enable seamless and persistent authentication when signing in with Facebook, Twitter or Google User accounts.

Web, Node.js and React Native ServerEvents Apps

The TypeScript servicestack-client npm package is a cross-platform library enabling a rich, productive end-to-end Typed development experience on Web, node.js Server projects, node.js test suites, React Native iOS and Android Mobile Apps - written in either TypeScript or plain JavaScript.

To help getting started using servicestack-client in each of JavaScript’s most popular platforms we’ve developed a simple Server Events Web, Node.js and React Native Mobile iOS App that can connect to any Server Events Server and listen to messages published on the subscribed channel. The App also maintains a live synchronized list of Users in the channel that’s automatically updated whenever Users join or leave the channel:

Each App uses the optimal starting configuration that enables a productive workflow on each platform and uses the minimum runtime dependencies - essentially just servicestack-client and its es6-shim and W3C EventSource polyfills on Node.js and React Native where it’s missing a native implementation.

TypeScript servicestack-client improvements

New APIs have been added to TypeScript’s servicestack-client to catch up with the additional flexibility and features available in C#/.NET Service Clients:

Sending additional arguments with Typed API Requests

Many AutoQuery Services utilize implicit conventions to query fields that aren’t explicitly defined on AutoQuery Request DTOs, these can now be queried by specifying additional arguments with the typed Request DTO, e.g:

const request = new FindTechStacks();

client.get(request, { VendorName: "ServiceStack" })
    .then(r => { }) // typed to QueryResponse<TechnologyStack> 

Calling APIs with Custom URLs

In addition to Typed API Requests you can now also call Services using relative or absolute urls, e.g:

client.get<GetTechnologyResponse>("/technology/ServiceStack")

client.get<GetTechnologyResponse>("http://techstacks.io/technology/ServiceStack")

// GET http://techstacks.io/technology?Slug=ServiceStack
client.get<GetTechnologyResponse>("/technology", { Slug: "ServiceStack" }) 

Relaxed TypeScript Definitions

The metadata requirements in TypeScript Ambient Interface definitions generated by Add ServiceStack Reference’s /types/typescript.d have been relaxed so they can be used to Type Object Literals:

let request:QueryContracts = { accountId: 1234 };

But as metadata in Request DTO interface definitions are no longer inferrable, their return Type and route will need to be supplied on each call-site, e.g:

let request:FindTechnologies = { vendorName: "ServiceStack" };

client.get<QueryResponse<Technology>>("/technology/search", request)
    .then(r => { }); //typed response

Authentication via OAuth AccessTokens

To improve OAuth Sign In integration from native Mobile or Desktop Apps we’ve added support for direct Authentication via AccessTokens which can dramatically simplify the Development and User Experience by being able to leverage the Native Facebook, Twitter and Google Client SDK’s to Sign In users locally then reuse their local AccessToken to Authenticate with back-end ServiceStack Servers.

This feature is what’s used to enable Integrated Facebook, Twitter and Google Logins in Android Java Chat and be able to Automatically Sign In users with saved AccessTokens.

This capability is now available on the popular OAuth Providers below:

  • FacebookAuthProvider - Sign in with Facebook
  • TwitterAuthProvider - Sign in with Twitter
  • GithubAuthProvider - Sign in with Github
  • GoogleOAuth2Provider - Sign in with Google

Client Authentication with AccessToken

Clients can utilize this feature with the new AccessToken and AccessTokenSecret properties on the existing Authenticate request DTO, sent with the provider that the AccessToken is for, e.g:

var response = client.Post(new Authenticate {
    provider = "facebook",
    AccessToken = facebookAccessToken,
    RememberMe = true,
});

JWT Refresh Tokens

Support for Refresh Tokens is now available in the JWT Auth Provider where new JWT Tokens can now be generated from a longer-lived RefreshToken which can be used to fetch new JWT Tokens without needing to re-authenticate with a separate Auth Provider.

Accessing Refresh Tokens

Just like JWT Tokens, Refresh Tokens are populated on the AuthenticateResponse DTO after successfully authenticating via any registered Auth Provider, e.g:

var response = client.Post(new Authenticate {
    provider = "credentials",
    UserName = userName,
    Password = password,
});

var jwtToken = response.BearerToken;
var refreshToken = response.RefreshToken;

Lifetimes of tokens

The default expiry time of JWT and Refresh Tokens below can be overridden when registering the JwtAuthProvider:

new JwtAuthProvider {
    ExpireTokensIn        = TimeSpan.FromDays(14),  // JWT Token Expiry
    ExpireRefreshTokensIn = TimeSpan.FromDays(365), // Refresh Token Expiry
}

Using JWT and Refresh Tokens

In order to provide the simplest development experience possible you only need to specify the Refresh Token on the Service Client and it will take care of transparently fetching a new JWT Token behind-the-scenes. You don’t even need to configure the client with a JWT Token as it will just fetch a new one on first use, e.g:

var client = new JsonServiceClient(baseUrl) {
    RefreshToken = refreshToken,
};

var response = client.Send(new Secured());

Fluent Validation Upgraded

Another major feature added in this release was contributed by the community with Scott Mackay upgrading our internal Fluent Validation implementation to the latest version of FluentValidation. Special care was taken to maintain backwards compatibility where ServiceStack enhancements were retrofitted on top of the new version and existing Error Codes were preserved to ensure minimal disruption with existing code bases.

Async Validators

One of the benefits from using the latest version of Fluent Validation is we now have support for Async Validators! Async validators can be registered using the MustAsync validator where you could simulate the following built-in Not Empty validation:

public class MyRequestValidator : AbstractValidator<MyRequest>
{
    public MyRequestValidator()
    {
        RuleFor(x => x.Name).NotEmpty();
    }
}

And replace it with an Async version that uses the Service Gateway to call a custom Async GetStringLength Service that returns the same ErrorCode and Error Message as the Not Empty validator:

public class MyRequestValidator : AbstractValidator<MyRequest>
{
    public MyRequestValidator()
    {
        RuleFor(x => x.Name).MustAsync(async (s, token) => 
            (await Gateway.SendAsync(new GetStringLength { Value = s })).Result > 0)
        .WithMessage("'Name' should not be empty.")
        .WithErrorCode("NotEmpty");
    }
}

Async Global Request Filters

To properly implement Async Validators we also needed Async Request Filters which were also added in this release where you can now register non-blocking Request Filters with:

GlobalRequestFiltersAsync.Add(async (req,res,dto) => {
    var response = await client.Send(new CheckRateLimit { 
        Service = dto.GetType().Name,
        IpAddress = req.UserHostAddress,
     });
     if (response.RateLimitExceeded) 
     {
         res.StatusCode = 403;
         res.StatusDescription = "RateLimitExceeded";
         res.EndRequest();
     }
})

Enhanced Compression Options

We’ve followed up Request Compression added in the last release with more compression features in this release including:

[CompressResponse] Attribute

You can now selectively choose which Services should be compressed with the new [CompressResponse] attribute to compress responses for clients which support compression, which can be applied to most Response Types, e.g:

[CompressResponse]
public class CompressedServices : Service
{
    public object Any(CompressDto request) => new CompressExamplesResponse(); 
    public object Any(CompressString request) => "foo"; 
    public object Any(CompressBytes request) => "foo".ToUtf8Bytes(); 
    public object Any(CompressStream request) => new MemoryStream("foo".ToUtf8Bytes()); 
    public object Any(CompressFile request) => new HttpResult(VirtualFileSources.GetFile("/foo"));

    public object Any(CompressAnyHttpResult request)
    {
        return new HttpResult(new CompressExamplesResponse());    // DTO
        return new HttpResult("foo", "text/plain");               // string
        return new HttpResult("foo".ToUtf8Bytes(), "text/plain"); // bytes
        //etc
    }
}

Note using [CompressResponse] is unnecessary when returning cached responses as ServiceStack automatically caches and returns the most optimal Response - typically compressed bytes for clients that supports compression

Static File Compression

ServiceStack can also be configured to compress static files with specific file extensions that are larger than specific size with the new opt-in Config options below:

SetConfig(new HostConfig {
    CompressFilesWithExtensions = { "js", "css" },
    // (optional), only compress .js or .css files > 10k
    CompressFilesLargerThanBytes = 10 * 1024 
});

When more fine-grained logic is needed you can override ShouldCompressFile() in your AppHost to choose which static files you want to compress on a per-file basis, e.g:

public override bool ShouldCompressFile(IVirtualFile file)
{
    return base.ShouldCompressFile(file) || file.Name == "large.csv";
}

Community

We’ve been lucky to receive a number of quality contributions from the Community in this release starting with the new Serilog Logging provider contributed by Josh Engler:

ServiceStack.Logging.Serilog

To Configure Serilog Logging, first download ServiceStack.Logging.Serilog from NuGet:

PM> Install-Package ServiceStack.Logging.Serilog

Then configure ServiceStack to use SerilogFactory:

LogManager.LogFactory =  new SerilogFactory();

Community Projects

There’s also been a number of quality OSS Community projects that’s surfaced recently that you may find useful to enable in your ServiceStack projects:

ServiceStack.Webhooks

If you need to implement a Webhooks solution for your Services you’ll definitely want to check out ServiceStack.Webhooks by @jezzsantos. ServiceStack.Webhooks is a high-quality, actively developed, well documented solution for raising and managing application-level “events” raised by your services:

ServiceStack.Authentication.Azure

ServiceStack.Authentication.Azure is a fork of ServiceStack.Authentication.Aad developed by Ian Kulmatycki which provides an AzureAuthenticationProvider for easily authenticating users with Office365 and hybrid Azure Active Directories.

ServiceStack.Authentication.Marten

ServiceStack.Authentication.Marten is a UserAuthRepository repository developed by Michał Gajek for persisting users in Marten - a Document Database for PostgreSQL.

MultiAppSettingsBuilder

Another feature contributed by Josh Engler is the MultiAppSettingsBuilder which adds a fluent discoverable API for configuring ServiceStack’s various App Setting Providers, e.g:

AppSettings = new MultiAppSettingsBuilder()
    .AddAppSettings()
    .AddDictionarySettings(new Dictionary<string,string> { "override" : "setting" })
    .AddEnvironmentalVariables()
    .AddTextFile("~/path/to/settings.txt".MapProjectPath())
    .Build();

CacheClient with Prefix

The CacheClientWithPrefix class contributed by @joelharkes lets you decorate any ICacheClient to prefix all cache keys using the .WithPrefix() extension method. This could be used to easily enable multi-tenant usage of a single redis instance, e.g:

container.Register(c => 
    c.Resolve<IRedisClientsManager>().GetCacheClient().WithPrefix("site1"));

OrmLite Soft Deletes

Select Filters were added to OrmLite to let you specify a custom SelectFilter that lets you modify queries
that use SqlExpression<T> before they’re executed. This could be used to make working with “Soft Deletes”
Tables easier where it can be made to apply a custom x.IsDeleted != true condition on every SqlExpression.

By either using a SelectFilter on concrete POCO Table Types, e.g:

SqlExpression<Table1>.SelectFilter = q => q.Where(x => x.IsDeleted != true);
SqlExpression<Table2>.SelectFilter = q => q.Where(x => x.IsDeleted != true);

Or alternatively you can configure a global SqlExpressionSelectFilter with:

OrmLiteConfig.SqlExpressionSelectFilter = q =>
{
    if (q.ModelDef.ModelType.HasInterface(typeof(ISoftDelete)))
    {
        q.Where<ISoftDelete>(x => x.IsDeleted != true);
    }
};

Both solutions above will transparently add the x.IsDeleted != true to all SqlExpression<T> based queries so it only returns results which aren’t IsDeleted from any of queries below:

var results = db.Select(db.From<Table>());
var result = db.Single(db.From<Table>().Where(x => x.Name == "foo"));
var result = db.Single(x => x.Name == "foo");

ServiceStack.Text

You can easily escape HTML Entities characters (<, >, &, =, ') when serializing JSON strings with:

JsConfig.EscapeHtmlChars = true;

This can also be requested by clients using Customized JSON Responses, e.g:

/my-api?jsconfig=EscapeHtmlChars

Rabbit MQ

A strong-named version of ServiceStack.RabbitMq is now available at:

PM> Install-Package ServiceStack.RabbitMq.Signed

The new CreateQueueFilter and CreateTopicFilter filters added to the Rabbit MQ Server will let you customize what options Rabbit MQ Queue’s and topics are created with.

Startup Errors

To better highlight the presence of Startup Errors we’re now adding a red warning banner in /metadata
pages when in DebugMode, e.g:

The number of Startup Errors is also added to the X-Startup-Errors: n Global HTTP Header so you’ll be
able to notice it when debugging HTTP Traffic.

Forcing a Content Type

Whilst ServiceStack Services are typically available on any endpoint and format, there are times when you only want adhoc Services available in a particular format, for instance you may only want the View Models for your dynamic Web Views available in HTML. This can now be easily enabled with the new [HtmlOnly] Request Filter Attribute, e.g:

[HtmlOnly]
public class HtmlServices : Service
{
    public object Any(MyRequest request) => new MyViewModel { .. };
}

This feature is also available for other built-in Content Types: [JsonOnly], [XmlOnly], [JsvOnly] and [CsvOnly].

AuthProvider available on IAuthSession

You can now determine what Auth Provider was used to populate a User’s Session with the new IAuthSession.AuthProvider property. This could be used for instance to detect and ensure highly-sensitive services are only available to users that authenticated using a specific Auth Provider.

All .NET Core Examples upgraded to .NET Core 1.1

All .NET Core Live examples including the redis-geo project used in Deploy .NET Core with Docker to AWS ECS Guide were upgraded to .NET Core 1.1 and has been changed to use the microsoft/dotnet:1.1-sdk-projectjson Docker Image since microsoft/dotnet:latest was changed to only support projects with VS 2017 .csproj msbuild format.

This covers a high-level view of the major features added in this release, please see the
v4.5.8 Release Notes for the full details and other features added in this release.

This topic is now pinned globally. It will appear at the top of its category and all topic lists until it is unpinned by staff for everyone, or by individual users for themselves.

This topic is now unpinned. It will no longer appear at the top of its category.