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:
Gistlyn Collections​
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.
OrmLite Interactive Tour​
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()
andT.Dump()
extension methods are ideal for dumping and quickly seeing the results of any variable to the Console.
Add ServiceStack Reference​
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("https://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.
Run Gistlyn on your Desktop​
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.
Source Code​
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:
- React Desktop Apps - tooling for packaging Gistlyn's ASP.NET Web App into a Winforms Desktop and Console App
- Server Events - providing real-time Script Status updates and Console logging
- TypeScript - enabling end-to-end Typed API requests
- Github OAuth - authentication with Github
- JWT Auth Provider - enabling both JWT and JWE ecrypted stateless Sessions
- HTTP Utils - consuming Github's REST API and creating an authenticated HTTP Proxy in GitHubServices.cs
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 '@servicestack/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
//...
}
}
});
TypeScript @servicestack/client​
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
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.
Limitations​
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.
Using ServiceStack.Client on .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:
- JSON, JSV and CSV Text Serializers
- AutoMapping Utils
- HTTP Utils
- Dump Utils
- Several String Extensions, Collection extensions, Reflection Utils and lots more.
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.
JWT Auth Provider​
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​
Dump Utils​
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:
- gistlyn.com/redis-todo - Windows Server / .NET 4.6
- mono.gistlyn.com/redis-todo - Ubuntu / Mono
PocoDynamo​
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:
- gistlyn.com/pocodynamo-todo - Windows Server / .NET 4.6
- mono.gistlyn.com/pocodynamo-todo - Ubuntu / Mono
Stripe​
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
}));