Skip to content

Latest commit

 

History

History
1204 lines (876 loc) · 49.7 KB

v4.0.62.md

File metadata and controls

1204 lines (876 loc) · 49.7 KB

v4.0.62 Release Notes

Gistlyn - a C# Gist IDE powered by Roslyn!

We're super excited to announce the release of gistlyn.com - A C# Gist IDE for creating, running and sharing stand-alone, executable C# snippets!

Born out of our initiative to improve ServiceStack's documentation, we set out to create the best way for developers to learn and explore different features in ServiceStack, the result is the ultimate collaborative tool for trying out and exploring C# and .NET libraries on NuGet from a zero install - modern browser. Gistlyn is ideal for use as a companion tool for trying out libraries during development or on the go from the comfort of their iPad by going to gistlyn.com.

Maintain C# snippets in your Github Gists

Gistlyn is an open platform where all C# snippets and documentation are hosted entirely in Github gists that lets anyone create new C# Gists or fork, update or rename and add new files to existing ones - providing a complete UI authoring experience for your C# snippets that gets saved directly to your Gists on Github. You can easily Create or Fork a copy of any Gist by hitting Ctrl+S which will save any of your changes to your modified copy.

The Hello World Gist shows a minimal C# example of what it takes to run in Gistlyn, i.e. just valid C# source code in a main.cs file:

main.cs

//Variables in top scope can be inspected in preview inspector

var name = "World";
var greeting = $"Hello, {name}!";

Hitting Ctrl+Enter (or clicking play) will execute your code on Gistlyn's server, running in an isolated context where each of the variables defined in the top-level scope can be inspected further. The preview inspector also includes an Expression evaluator that can be used to evaluate C# expressions against the live server session:

The best thing about Gistlyn collections is that they're just plain Github Gists with a single index.md Markdown document. So if you've previously created documentation in Github or asked questions in StackOverflow you already know how to Create Gistlyn Collections.

Being able to mix step-by-step documentation and executable code enables a "live" learning experience where after introducing and explaining a feature you can provide a focused code example that Users can open in the code editor on the left which they can run to see it working, inspect its results and further modify the C# sample to continue exploring it even further themselves.

The OrmLite collection is a good example of this which has become the ideal place to learn about OrmLite, starting with how to install it and complete examples showing all the source code needed to run it in Gistlyn and your C# programs.

The OrmLite Collection page serves as a launch pad to quickly jump into different areas of OrmLite, each major feature being another collection with more in-depth docs and code-samples:

OrmLite Tour: gistlyn.com/ormlite

Instant Feedback

Gistlyn shines at being able to quickly navigate, run code and preview results at a glance where you can preview complex types with nested complex collections in a human-friendly format for instant feedback.

To give you an example, here's what the preview inspector shows after running the OrmLite Reference Test Data sample C# code below:

//SELECT all artists including their Track references
var allArtists = db.LoadSelect<Artist>();
allArtists.PrintDump(); // Dump to Console

After it's executed all the variables get shown in the preview inspector. Then clicking on allArtists executes it in the Expression Evaluator and displays the results below:

The T.PrintDump() and T.Dump() extension methods are ideal for dumping and quickly seeing the results of any variable to the Console.

One feature that will add a lot of complementary value to your ServiceStack Services is Gistlyn's integrated support for Add ServiceStack Reference feature which will generate a Typed API for your remote ServiceStack Services and let you call them using ServiceStack's typed C# Service Clients and view their results - within seconds!

The easiest way to use this feature is to add the BaseUrl for your remote ServiceStack instance to the ?AddServiceStackReference query string, e.g:

This will open the Add ServiceStack Reference dialog that automatically validates if the specified url is to a valid ServiceStack instance:

Hitting Enter then:

  • creates a new Gist
  • adds your generated C# DTOs with the filename specified
  • initializes a JsonServiceClient with your BaseUrl
  • and provides an example of a Get() Request using the first GET Request DTO it can find

Which for techstacks.io results in:

using System.Linq;
using ServiceStack;
using ServiceStack.Text;

var client = new JsonServiceClient("http://techstacks.io");

//Call techstacks.io APIs by sending typed Request DTO's
var response = client.Get(new GetAllTechnologies {  });

//response.PrintDump();  // Uncomment to Print Response to Console

So without having written any code, Users can hit Ctrl+Enter to execute the generated Gist which for techstacks.io returns details of All Technologies it maintains in its database that it shows in the Preview Inspector. Uncommenting response.PrintDump(); will also dump the contents of the Web Services response to the Console.

URL Customizations

One thing you'll likely want to do is change which Request DTO gets used by specifying it in the ?Request query string, e.g:

You can also pre-populate the C# expression and have it autorun with:

We then end up with a live link that anyone with a modern browser on their Desktop or iPad can click on to call techstacks.io's public API to find out what its Most popular technology is, in seconds.

Adding ServiceStack References to existing Gists

Similar to how Add ServiceStack Reference works in most major IDE's, you can also add the reference to existing Gists using the Editor Context Menu:

Then after clicking Add Reference Gistlyn adds your remote Services Typed DTOs to your existing gist using the filename specified.

v4.0.62 required

If you're adding a Service reference to a version of ServiceStack before v4.0.62 you will need to manually remove any C# namespaces as they're not supported in Roslyn Scripting.

Snapshots

Gistlyn gets a lot of natural benefits from being a React web-based IDE, from deep linking to being able to quickly navigate back/forward through your browser history. It also saves every change to your localStorage that restores instantly, so you can close your browser at anytime and revisiting gistlyn.com will bring you right back to the same state where you left it. Drafts of every Gist you visit are also saved, so you can happily be working on multiple gists without losing any changes.

Another feature Gistlyn naturally benefits from is Snapshots...

Snapshots lets you save the entire client state of your current workspace (excluding your login info) into a generated url which you can use to revert back in time from when the snapshot was taken or send to someone else who can instantly see and run what you're working on, who'll be able to continue working from the same place you're at.

Like everything else in Gistlyn, a snapshot is just a snapshot.json document of your serialized State saved to your User Account in a private Github Gist.

Capturing a Snapshot

As snapshots are saved to your gists, you'll need to first sign-in to be able take a snapshot. After you're authenticated with Github you can click on the camera icon that appears in the footer to take a snapshot:

This will open the Snapshot Dialog where you can enter the name of the Snapshot which by default is automatically populated with the timestamp of when the Snapshot was taken:

Clicking Save Snapshot serializes your captured snapshot and saves it as a snapshot.json document in a new private gist. Gistlyn then just appends the id of the newly created Gist to the ?snapshot queryString to form the url for your new snapshot:

Loading a Snapshot

There are 2 ways to load a snapshot, either by clicking on the generated url to launch it in a browser:

Which will load a new Gistlyn session initialized with the snapshot, complete with the contents of all working files, the state of the preview window, any console logs, etc:

The alternative is to paste the id of the Gist into Gistlyn's URL bar:

Incidentally you can paste the id of any C# Gist, Collection or Snapshot in the URL Bar

Gistlyn's Stateless Architecture

One surprising thing about Gistlyn is that it's entirely stateless where it runs without any kind of backend db persistence. All state is either persisted to Github gists or in your browser's localStorage. Not even your Authenticated Github session is retained on the server as it's immediately converted into an encrypted JWT Cookie that is sent with every Ajax request, so redeployments (or even clean server rebuilds) won't lose any of your work or force you to Sign In again until the JWT Token expires.

Downloads

Thanks to ServiceStack's React Desktop Apps VS.NET Template Gistlyn is available in a variety of different flavours:

Deployed as an ASP.NET Web Application on both Windows / .NET and Linux / Mono servers at:

  • gistlyn.com - Ubuntu / Vagrant / Windows 2012 Server VM / IIS / .NET 4.6
  • mono.gistlyn.com - Ubuntu / Docker / mono / nginx / HyperFastCGI

Having both Windows and Linux versions of Gistlyn is useful when you want to test whether a feature has the same behavior in both .NET and Mono. Where after saving you can add/remove the mono subdomain to run your scripts on different Operating Systems.

In addition to a running as an ASP.NET Web App, Gistlyn is also available as a self-hosting Winforms Desktop or cross-platform OSX/Linux/Windows Console App.

Running Gistlyn on your Desktop lets you take advantage of the full resources of your CPU for faster build and response times and as they're run locally they'll be able to access your RDBMS or other Networked Servers and Services available from your local Intranet.

Gistlyn's Github Repo provides a good example of a modern medium-sized ServiceStack, React + TypeScript App that takes advantage of a number of different ServiceStack Features:

TypeScript

One of ServiceStack's primary use-cases is the development of Single Page Apps which we like as it enables both a productive development experience for creating Web Apps as well as delivering a great responsive UX for end users.

First class development experience

TypeScript has become a core part of our overall recommended solution that's integrated into all ServiceStackVS's React and Aurelia Single Page App VS.NET Templates offering a seamless development experience with access to advanced ES6 features like modules, classes and arrow functions whilst still being able to target most web browsers with its down-level ES5 support. TypeScript also goes beyond ES6 with optional Type Annotations enabling better tooling support and compiler type feedback than what's possible in vanilla ES6 - invaluable when scaling large JavaScript codebases.

We're actively tracking TypeScript's evolution and looking forward to integrating TypeScript 2.0 once it leaves beta.

Ideal Typed Message-based API

We've added even deeper integration with TypeScript in this release which has graduated to a 1st class supported Add ServiceStack Reference language that together with the new TypeScript JsonServiceClient available in the servicestack-client npm package enables the same productive, typed API development experience available in our other 1st-class supported client platforms.

The additional type hints ServiceStack embeds in each Request DTO lets us achieve the ideal typed, message-based API we want - a feature heavily utilized in Gistlyn so all API requests benefit from a succinct, boilerplate-free Typed API.

Here's a quick look at what it looks like. The example below shows how to create a C# Gist in Gislyn after adding a TypeScript ServiceStack Reference to gistlyn.com and installing the servicestack-client npm package:

import { JsonServiceClient } from 'servicesack-client';
import { StoreGist, GithubFile } from './Gistlyn.dtos';

var client = new JsonServiceClient("http://gistlyn.com");

var request = new StoreGist();
var file = new GithubFile();
file.filename = "main.cs";
file.content = 'var greeting = "Hi, from TypeScript!";';
request.files = { [file.filename]: file };

client.post(request)
    .then(r => { // r:StoreGistResponse
        console.log(`New C# Gist was created with id: ${r.gist}`);
        location.href = `http://gistlyn.com?gist=${r.gist}`;
    })
    .catch(e => {
        console.log("Failed to create Gist: ", e.responseStatus);
    });

Where the r param in the returned then() Promise callback is typed to StoreGistResponse DTO Type.

Isomorphic Fetch

The servicestack-client is a clean "jQuery-free" implementation based on JavaScript's new Fetch API standard, utilizing the isomorphic-fetch implementation so it can be used in both JavaScript client web apps as well as node.js server projects.

ServerEventsClient

In addition to JsonServiceClient we've ported most of the JavaScript utils in ss-utils.js, including the new ServerEventsClient which Gistlyn uses to process real-time Server Events from the executing C# Gist with:

const channels = ["gist"];
const sse = new ServerEventsClient("/", channels, {
    handlers: {
        onConnect(activeSub:ISseConnect) {                       // Successful SSE connection
            store.dispatch({ type: 'SSE_CONNECT', activeSub });  // Tell Redux Store we're connected 
            fetch("/session-to-token", {                         // Convert Session to JWT
                method:"POST", credentials:"include" 
            }); 
        },
        ConsoleMessage(m, e) {                                   // C# Gist Console Logs
            batchLogs.queue({ msg: m.message });
        },
        ScriptExecutionResult(m:ScriptExecutionResult, e) {      // Script Status Updates
            //...
        }
    }
});

We've upgraded all ServiceStackVS TypeScript projects to use the pure servicestack-client client and switched over to use the lighter and jQuery-free bootstrap.native CSS framework which is more suitable for use in modern React, AngularJS and Aurelia frameworks.

Other TypeScript or ES6 projects can install servicestack-client with:

jspm install servicestack-client

node server projects can instead install it with:

npm install servicestack-client --save

Then fetch the Type Definitions for either project type with:

typings install servicestack-client --save
typings install dt~isomorphic-fetch --global --save

TypeScript DTO enhancements

As they provide a better development experience we've switched the Add > TypeScript Reference dialog to import concrete Types by default. To get TypeScript .d.ts definitions, check the Only TypeScript Definitions checkbox.

Enum support

For C# Enums that are returned as a string TypeScript now generates wire-compatible type aliases, e.g:

export type ScriptStatus = "Running" | "Completed" | "Cancelled" | "CompiledWithErrors";

Whilst normal TypeScript enums are used for C# Enums returned in integer values, e.g:

// @Flags()
export enum EnumFlags
{
    Value1 = 1,
    Value2 = 2,
    Value3 = 4,
}

Module-less Types

In keeping with idiomatic style of local .ts sources, generated types are no longer wrapped within a module by default. This lets you reference the types you want directly using normal import destructuring syntax:

import { MyRequest } from './dtos.ts';

Or import all Types into your preferred variable namespace with:

import * as dtos from './dtos.ts';

const request = new dtos.MyRequest();

The previous module behavior can be restored by specifying a GlobalNamespace option:

/* Options:
Date: 2016-08-09 17:24:02
Version: 1
BaseUrl: http://api.example.com

GlobalNamespace: dtos
...
*/

Updating TypeScript References

As it conflicts with "auto compile on Save" feature of .ts files in VS.NET 2015, ServiceStackVS no longer updates the generated .dtos.ts on Save and now requires you to explicitly select Update Reference on the *.dtos.ts Context Menu:

.NET Core support for ServiceStack.Client

We're happy to be able to release our initial library support for .NET Core with .NET Core builds for ServiceStack.Client and its dependencies, available in the following NuGet packages:

Until we've completed our transition, we'll be maintaining .NET Core builds in separate NuGet packages containing a .Core suffix as seen above. This leaves our existing .NET packages unaffected, whilst letting us increase our release cadence of .NET Core packages until support for .NET Core libraries has stabilized.

We were able to make most of the features available in the .NET Core builds however there are some limitations where WCF Soap clients or EncryptedServiceClient are not available and heartbeats are not enabled in ServerEventsClient which require a new implementation for .NET Core.

We've published a step-by-step guide showing how to Install ServiceStack.Client in a .NET Core App and how to use the generated types from Add ServiceStack Reference to make a Typed API Request to a Remote ServiceStack Service in VS.NET on Windows and on Linux from scratch:

ServiceStack.Text is now Free!

To celebrate our initial release supporting .NET Core, we're now making ServiceStack.Text completely free for commercial or non-commercial use. We've removed all free-quota restrictions and are no longer selling licenses for ServiceStack.Text. By extension this also extends to our client libraries that just depend on ServiceStack.Text, including: ServiceStack.Client and Stripe which are also both free of any technical restrictions.

ServiceStack.Text is our high-performance library containing ServiceStack's core text processing powers that contains a multitude of battle tested core utilities simplifying many programming tasks which includes:

We view it as an essential dependency that has been a staple in every .NET Project we create since the dawn of ServiceStack, which we're happy to make as widely available as possible.

Available on most popular .NET platforms

The new .NET Core support extends the reach of ServiceStack.Text and our C#/.NET Service Clients libraries to support the most popular .NET platforms including:

  • .NET 4.x / Mono
  • Xamarin iOS / Android / OSX
  • Windows Store
  • Silverlight 5
  • .NET Core

Encrypted Service Clients for iOS, Android and OSX

The EncryptedServiceClient is now available in Xamarin iOS, Android and OSX packages so your Xamarin Mobile and OSX Desktop Apps are now able to benefit from transparent encrypted service client requests without needing to configure back-end HTTP servers with SSL:

var client = new JsonServiceClient(BaseUrl);
IEncryptedClient encryptedClient = client.GetEncryptedClient(publicKeyXml);

var response = encryptedClient.Send(new Hello { Name = "World" });

Last release supporting .NET 4.0

As announced earlier this year in preparation for .NET Core, this will be our last release supporting .NET 4.0. Starting from next release all projects will be upgraded to .NET 4.5. Should you need it, the .NET 4.0 compatible ServiceStack source code will remain accessible in the net40 branches of all major ServiceStack Github repositories.

ServiceStackVS

Aurelia updated to 1.0

To coincide with the v1.0 release of Aurelia the Aurelia VS.NET template has been updated to v1.0 using bootstrap.native and is now pre-configured with both the new servicestack-client and local src/dtos.ts TypeScript Reference that includes an end-to-end Typed DTO example showing them used together:

var req = new Hello();
req.Name = newValue;
this.client.get(req).then((helloResponse) => {
    this.result = helloResponse.Result
});

Which lets you immediately start adding ServiceStack Services and access their generated types in Typed API requests by selecting Update ServiceStack Reference on src/dtos.ts Context Menu.

Improved Razor intellisense

We've updated all our ASP.NET Razor VS.NET Templates to use the ideal Web.config configuration for editing Razor pages without designer errors in VS.NET 2015. Previously the Razor intellisense for ServiceStack Razor Content and View Pages relied on an existing version of MVC3 installed in previous upgraded versions of VS.NET which are no longer available in clean VS.NET 2015 installs.

Each ServiceStack ASP.NET Razor project now adopts the optimal Web.config template below:

<configuration>
    <configSections>
        <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
            <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false"/>
            <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false"/>
        </sectionGroup>
    </configSections>

    <appSettings>
        <add key="webPages:Enabled" value="false" />
    </appSettings>

    <system.web.webPages.razor>
        <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <pages pageBaseType="ServiceStack.Razor.ViewPage">
            <namespaces>
                <add namespace="System" />
                <add namespace="System.Linq" />
                <add namespace="ServiceStack" />
                <add namespace="ServiceStack.Html" />
                <add namespace="ServiceStack.Razor" />
                <add namespace="ServiceStack.Text" />
                <add namespace="ServiceStack.OrmLite" />
                <add namespace="ProjectNamespace" />
                <add namespace="ProjectNamespace.ServiceModel" />
            </namespaces>
        </pages>
    </system.web.webPages.razor>
</configuration>

The ServiceStack.Razor NuGet package has also been upgraded to be able to use the official Microsoft.AspNet.Razor but to keep VS.NET's Razor editor happy, the templates also reference MVC's Microsoft.AspNet.WebPages NuGet package which ServiceStack doesn't use or need itself, but helps remove designer warnings.

Then to remove the last designer error Content pages can inherit:

@inherits ViewPage

And Typed View Pages:

@inherits ViewPage<TResponse>

Which also doesn't affect the pages behavior, but can remove the final design-time warning showing up in VS.NET's error list.

The JwtAuthProvider has added support for specifying multiple fallback AES Auth Keys and RSA Public Keys allowing for smooth key rotations to newer Auth Keys whilst simultaneously being able to verify JWT Tokens signed with a previous key.

The fallback keys can be configured in code when registering the JwtAuthProvider:

new JwtAuthProvider {
    AuthKey = authKey2016,
    FallbackAuthKeys = {
        authKey2015,
        authKey2014,
    },
    PrivateKey = privateKey2016,
    FallbackPublicKeys = {
        publicKey2015,
        publicKey2014,
    },
}

Or in AppSettings:

<appSettings>
    <add key="jwt.AuthKeyBase64" value="{AuthKey2016Base64}" />
    <add key="jwt.AuthKeyBase64.1" value="{AuthKey2015Base64}" />
    <add key="jwt.AuthKeyBase64.2" value="{AuthKey2014Base64}" />

    <add key="jwt.PrivateKeyXml" value="{PrivateKey2016Xml}" />
    <add key="jwt.PublicKeyXml.1" value="{PublicKeyXml2015Xml}" />
    <add key="jwt.PublicKeyXml.2" value="{PublicKeyXml2014Xml}" />
</appSettings>

There's also a new option for disabling returning JWT Tokens in AuthenticateResponse:

new JwtAuthProvider {
    SetBearerTokenOnAuthenticateResponse = false
}

Multitenancy RDBMS AuthProvider

ServiceStack's IAuthProvider has been refactored to use the central and overridable GetAuthRepository(IRequest) AppHost factory method where just like ServiceStack's other "Multitenancy-aware" dependencies now lets you dynamically change which AuthProvider should be used based on the incoming request.

This can be used with the new OrmLiteAuthRepositoryMultitenancy provider to maintain isolated User Accounts per tenant in all major supported RDBMS

Since each tenant database uses their own isolated UserAuth tables we need to provide the list of db connection strings that the OrmLite AuthRepository uses to check and create any missing User Auth tables:

var connectionStrings = 100.Times(i => GetConnectionStringForTenant(i));
container.Register<IAuthRepository>(c =>
    new OrmLiteAuthRepositoryMultitenancy(c.TryResolve<IDbConnectionFactory>(),
        connectionStrings));

container.Resolve<IAuthRepository>().InitSchema(); // Create any missing UserAuth tables

However if you've already created all UserAuth table schema's for each tenant or are manually creating them out-of-band you can register it without the list of connection strings:

container.Register<IAuthRepository>(c =>
    new OrmLiteAuthRepositoryMultitenancy(c.TryResolve<IDbConnectionFactory>()));

Then to specify which AuthRepository should be used for each request we can override GetAuthRepository() in your AppHost and return the OrmLiteAuthRepositoryMultitenancy configured to use the same Multitenant DB connection used in that request, e.g:

public override IAuthRepository GetAuthRepository(IRequest req = null)
{
    return req != null
        ? new OrmLiteAuthRepositoryMultitenancy(GetDbConnection(req)) //At Runtime
        : TryResolve<IAuthRepository>();                              //On Startup
}

So now when GetAuthRepository() is called within the context of a request it uses the same Multitenancy DB as your other services, otherwise when called outside (e.g. on Startup) it uses the default IOC Registration configured with the connectionStrings for each Multitenant DB that it can use to create any missing UserAuth table schemas not found in any of the Multitenant databases.

Breaking Changes

In order to support an overridable IAuthRepository the User Session's HasRole() and HasPermission() methods now require a IAuthRepository parameter, e.g:

bool HasRole(string role, IAuthRepository authRepo);
bool HasPermission(string permission, IAuthRepository authRepo);

Which you can get from base.AuthRepository property in your Services, Razor Views, ASP.NET or MVC ServiceStackController or can be resolved outside of ServiceStack with HostContext.AppHost.GetAuthRepository().

The deprecated OnRegistered(IServiceBase) callback was removed and should be updated to:

void OnRegistered(IRequest httpReq, IAuthSession session, IServiceBase service);

AuthRepositories should be registered against the IAuthRepository interface (i.e. not IUserAuthRepository), e.g:

container.Register<IAuthRepository>(c => ...);

OrmLite

OrmLite continues to see improvements with many of the new features in this release contributed by the Community.

SELECT JOIN enhancements

You can now SELECT all fields for a table by returning the entire instance in the custom anonymous type, e.g:

var q = db.From<Table>()
    .Join<JoinedTable>()
    .OrderBy(x => x.Id)
    .Select<Table, JoinedTable>((a, b) => new { a, b.TableId });

var rows = db.Select<CombinedResult>(q);

Which selects all columns from the primary Table as well as TableId from JoinedTable.

You can also specify SQL Aliases for ambiguous columns using anonymous properties, e.g:

var q = db.From<Table>()
    .Join<JoinedTable>()
    .Select<Table, JoinedTable>((a, b) => new { a, JoinId = b.Id, JoinName = b.Name });

Which is roughly equivalent to:

SELECT a.*, b.Id AS JoinId, b.Name AS JoinName

Where it selects all columns from the primary Table as well as Id and Name columns from JoinedTable, returning them in the JoinId and JoinName custom aliases.

Being able to select all columns works in other areas as well, e.g. you can GROUP BY all columns of a table with:

var q = db.From<Table>()
    .GroupBy(x => new { x });

Which would return the same results as a SELECT DISTINCT on all columns of Table.

Special thanks to @shift-evgeny for this feature.

Nested JOIN Table Expressions

@OlegNadymov has added several features in this release where you can now query nested POCO References on JOIN Tables in a Where() expression, e.g:

var q = db.From<Table>()
    .Join<Join1>()
    .Join<Join1, Join2>()
    .Where(x => !x.IsValid.HasValue && 
        x.Join1.IsValid &&
        x.Join1.Join2.Name == theName &&
        x.Join1.Join2.IntValue == intValue);

var results = db.Select(q);

As well as in GroupBy() and Having() Expressions:

var q = db.From<Table>()
    .Join<Join1>()
    .Join<Join1, Join2>()
    .Where(x => !x.IsValid.HasValue && 
        x.Join1.IsValid &&
        x.Join1.Join2.Name == theName &&
        x.Join1.Join2.IntValue == intValue)
    .GroupBy(x => x.Join1.Join2.IntValue)
    .Having(x => Sql.Max(x.Join1.Join2.IntValue) != 10)
    .Select(x => x.Join1.Join2.IntValue);

Implicit String casting

There's also support for implicit string casting when you use .ToString() to compare INT columns with strings where OrmLite will now generate the appropriate implicit string cast in SQL, e.g:

var q = Db.From<Table>()
.Join<Join1>()
.Where(x => x.NullableIntCol.ToString() == numberText 
    && x.Join1.NullableIntCol.ToString().EndsWith("0"));

String concatenation

Support for server-side string concatenation is also available when using either + operator or explicit string.Concat() method, e.g:

var q = db.From<Table>()
    .Where(x => x.TextCol + "." + x.NullableIntCol.ToString() == numberText + "." + 100);

var q = db.From<Table>()
    .Where(x => string.Concat(x.TextCol, ".", x.NullableIntCol.ToString())
                == string.Concat(numberText, ".", 100));

JOIN filters

@bryancrosby added support for JOIN Fitlers letting you enance Table JOIN expressions with a custom filter.

SQL Server Table Hints

With this feature OrmLite now supports SQL Server Hints on JOIN Table expressions, e.g:

var q = db.From<Car>()
    .Join<Car, CarType>((c, t) => c.CarId == t.CarId, SqlServerTableHint.ReadUncommitted);

Which emits the appropriate SQL Server hints:

SELECT "Car"."CarId", "CarType"."CarTypeName" 
FROM "Car" INNER JOIN "CarType" WITH (READUNCOMMITTED) ON ("Car"."CarId" = "CarType"."CarId")

JOIN aliases

JOIN Filters was also used to add typed support for JOIN Aliases, where previously we would've needed to use a CustomJoin() and raw SQL fragments in order to select the same columns from multiple self table joins, e.g:

var q = db.From<Sale>()
    .CustomJoin("LEFT JOIN Contact seller ON (Sale.SellerId = seller.Id)")
    .CustomJoin("LEFT JOIN Contact buyer ON (Sale.BuyerId = buyer.Id)")
    .Select(@"Sale.*
        , buyer.FirstName AS BuyerFirstName
        , buyer.LastName AS BuyerLastName
        , seller.FirstName AS SellerFirstName
        , seller.LastName AS SellerLastName");

Now thanks to JOIN filters and anonymous type aliases we can perform the same query using a typed SqlExpression, e.g:

var q = db.From<Sale>()
    .LeftJoin<ContactIssue>((s,c) => s.SellerId == c.Id, db.JoinAlias("seller"))
    .LeftJoin<ContactIssue>((s,c) => s.BuyerId == c.Id, db.JoinAlias("buyer"))
    .Select<Sale, ContactIssue>((s,c) => new {
        s,
        BuyerFirstName = Sql.JoinAlias(c.FirstName, "buyer"),
        BuyerLastName = Sql.JoinAlias(c.LastName, "buyer"),
        SellerFirstName = Sql.JoinAlias(c.FirstName, "seller"),
        SellerLastName = Sql.JoinAlias(c.LastName, "seller"),
    });

Ordering by Column Index

OrmLite now includes overloads for ordering by Column Index:

var q = db.From<Track>()
    .Where(x => x.Name.Contains("fire"))
    .GroupBy(x => x.Year)
    .OrderByDescending(2)
    .Select(x => new { x.Year, Total = Sql.Count("*") });

Ordering by Alias

As well as Alias using the custom property name of the Selected anonymous type, e.g:

var q = db.From<Track>()
    .Where(x => x.Name.Contains("fire"))
    .GroupBy(x => x.Year)
    .OrderByDescending("Total")
    .Select(x => new { x.Year, Total = Sql.Count("*") });

Sql.CountDistinct

The new Sql.CountDistinct() can be used for selecting COUNT(Distinct ColumnName), e.g:

var q = db.From<Table>().Select(x => Sql.CountDistinct(x.Letter));
var uniqueLetters = db.Scalar<long>(q);

OrmLite ExceptionFilter

The new ExceptionFilter lets you trap Exceptions which you can set a breakpoint on to analyze the generated SQL and any DB Params used, e.g:

OrmLiteConfig.ExceptionFilter = (dbCmd, ex) => {
    var lastSql = dbCmd.CommandText;
    var lastParam = (IDbDataParameter)dbCmd.Parameters[0];
};

ServiceStack.Text

To improve their utility in Gistlyn C# gists for quickly dumping and inspecting the contents of an object the T.PrintDump() and T.Dump() extension methods can now be used on objects with cyclical references where it will display the first-level ToString() value of properties that have circular references.

The Dump() utils are invaluable when explanatory coding or creating tests as you can quickly see what's in an object without having to set breakpoints and navigate nested properties in VS.NET's Watch window, e.g:

var response = client.Send(request);
response.PrintDump(); // Dumps contents to Console in human-friendly format

"Top Technologies: {0}".Print(response.TopTechnologies.Dump());

Whilst our Text Serializers don't support serializing DTOs with cyclical dependencies (which we actively discouraged), the new APIs below can be used instead to partially serialize objects where it uses the ToString() on any properties containing Circular references:

  • T.ToSafeJson()
  • T.ToSafeJsv()
  • T.ToSafePartialObjectDictionary()

The API used to detect whether an object has Circular References is also available for your use:

if (obj.HasCircularReferences()) {
}

PATCH APIs added to HttpUtils

The same HTTP Utils extension methods for Post and Put now also have Patch() equivalents.

We use the new Patch() support in Gistlyn's GitHubServices.cs to update contents of existing Gists:

var updateResponse = GithubApiBaseUrl.CombineWith("gists", gist)
    .PatchJsonToUrl(new UpdateGithubGist {
        description = request.Description,
        files = request.Files,
    }, 
    requestFilter: req => {
        req.UserAgent = "Gistlyn";
        req.Headers["Authorization"] = "token " + github.AccessTokenSecret;
    });

ServiceStack.Redis

Transaction support for Complex Type APIs

APIs returning Complex RedisText and RedisData responses can now be used in Redis Transactions:

RedisText result = null;
using (var trans = Redis.CreateTransaction())
{
    trans.QueueCommand(r => r.ExecLua("return {'myval', 'myotherval'}"), s => result = s);
    trans.Commit();
}

Improved Resiliency using Sentinels

Resiliency has improved around auto-retrying of failing and non-responsive Sentinels.

The default Auto Retry Timeout has increased to 10 seconds which can be changed with:

RedisConfig.DefaultRetryTimeout = 3000;

Try out ServiceStack.Redis on Gistlyn

We've added a local redis-server instance on both Windows and Linux/Mono Gistlyn servers which you can use to try out ServiceStack.Redis:

PocoDynamo now has Typed API support for DynamoDB Conitional Expressions, e.g:

var q = db.UpdateExpression<Customer>(customer.Id)
    .Set(() => new Customer { Nationality = "Australian" })
    .Add(() => new Customer { Age = decrBy })
    .Remove(x => new { x.Name, x.Orders })
    .Condition(x => x.Age == 27);

var succeeded = db.UpdateItem(q);

As well as Support for string and int-based Enum Types and creating Typed Global Indexes without a RangeKey.

Try out PocoDynamo on Gistlyn

We've configured a Local DynamoDB instance on both Windows and Linux/Mono versions of Gistlyn which you can use to try out PocoDynamo:

The StripeGateway now supports sending and Receiving Customer Metadata, BusinessVatId and returning the Customers Currency:

var customer = gateway.Post(new CreateStripeCustomer {
    //...
    BusinessVatId = "vat-1234",
    Metadata = new Dictionary<string, string> {
        {"order_id", "1234"}
    }
});

customer.BusinessVatId          //= vat-1234
customer.Metadata["order_id"]   //= 1234
customer.Currency               //= usd

Other ServiceStack Features

Find free Tcp Port

The new HostContext.FindFreeTcpPort() lets you find the first free TCP port within a specified port-range which you can use to start your AppHost on the first available port:

var port = HostContext.FindFreeTcpPort(startingFrom:5000, endingAt:6000);
new AppHost()
    .Init()
    .Start($"http://localhost:{port}/");

IOC - Named support for Funq's AutoWired APIs

@donaldgray added named support to Funq's autowired APIs, e.g:

container.RegisterAs<AutoWireService, IService>("one");
container.RegisterAs<AutoWireService, IService>("two");

var one = container.ResolveNamed<IService>("one");
var two = container.ResolveNamed<IService>("two");

Alternative autowired API examples:

container.RegisterAutoWired<AutoWireService>("one");
container.RegisterAutoWiredAs<AutoWireService, IService>("one");
container.RegisterAutoWiredType("one", typeof(AutoWireService), typeof(IService));
container.RegisterAutoWiredType("one", typeof(AutoWireService));

Disable Compression of [CacheResponse] responses

Compression of cached responses can now be disabled with the NoCompression property:

[CacheResponse(NoCompression = true)]
public object Any(Request request)
{
}

Add ServiceStack Reference

The C# / F# / VB.NET generated DTOs were updated to include the new MakeInternal option for setting the visibility of all DTO Types to internal which can be used to prevent DTO Types from leaking outside of the Assembly where the ServiceStack reference was added:

MakeInternal: true

The new hidden ?ExcludeNamespace=true option was added to C# DTOs to generate naked C# DTOs without a namespace as required by Roslyn Scripting that's used in Gistlyn.

Server Events

The new Action<IEventSubscription, Exception> OnError callback can be used to trap and inspect ServerEvent Exceptions.

A new isAuthenticated boolean property is returned to Server Event Clients which can be used to check whether a subscriber is Authenticated or not. In previous releases you can check authenticated users with userId > 0.

Disable Total in AutoQuery

You can save the SQL query to calculate the total count for each AutoQuery Request with:

Plugins.Add(new AutoQueryFeature { 
    IncludeTotal = false
});

This disables the 2nd query in AutoQuery requests making it as fast as manually constructing the same Request in OrmLite directly.

Customizing generated AutoQuery Service implementations

The generated AutoQuery Services implementation can be enhanced with GenerateServiceFilter which lets you apply additional behavior to all AutoQuery implementations by extending the generated Service implementation with Reflection.Emit.

Service Gateway

Service Gateways now execute any Validators defined on each Request DTO that's sent.

Gateway Request / Response Filters

You can also add Custom logic to execute before and after Service Gateway requests by registering Gateway Request / Response Filters:

this.GatewayRequestFilters.Add((req, requestDto) => {
    //Add Custom logic or validation
});

this.GatewayResponseFilters.Add((req, response) => {
    //modify response DTO before returning to callee
});

Custom Request / Response Filter Plugins

The new CustomRequestFilter can be used to dynamically create and register a plugin in-line with a custom Request Filter. This can be used to register a Global Request Filter to fire directly after another Plugins Global Request Filter without needing to create an explicit plugin.

So you can have it fire immediately after the ValidationFeature Global RequestFilters with:

Plugins.Add(new ValidationFeature());
Plugins.Add(new CustomRequestFilter((req,res,dto) => {
    // Fired directly after ValidationFeature's Global Request Filters
}));