v5 Release Notes
The theme of this major v5 release is integration and unification with the newly released .NET Standard 2.0 which offers the broadest compatibility and stabilized API surface for .NET Core and the version we’ve chosen to standardize around.
We’ll do our best to summarize new features here but if you have time we encourage you to read the full v5 Release Notes, as this is a major version upgrade we recommend at least reviewing the v5 Changes and Migration Notes before upgrading. Whilst the user-facing source code impact is minimal, we’ve taken the opportunity of a major version window to perform some logical re-structuring and some potentially breaking changes from replacing PCL clients to use .NET Standard 2.0, moving .NET Framework implementations to different projects, making SOAP Support, Mini Profiler and Markdown Razor opt-in and to be able to utilize the latest NuGet package dependencies ServiceStack.RabbitMQ requires .NET v4.5.1 and ServiceStack.Azure requires .NET v4.5.2.
All .NET Standard builds have been upgraded to .NET Standard 2.0 where now both .Core
and .Signed
NuGet package variants have been unified into ServiceStack’s main NuGet packages - unifying them into a single suite of NuGet packages and release cadence. All .NET 4.5 builds are Strong Named by default using the servicestack.snk
signing key that’s in the /src folder of each Project. The .NET Standard builds continue to remain unsigned so they can be built on each platform with .NET Core’s dotnet build
command.
New .NET Core 2.0 and .NET Framework Project Templates!
ServiceStack’s maintains exceptional source compatibility between .NET Core and .NET Framework projects which is visible in our new .NET Core 2.0 and .NET Framework project templates where all templates utilize the same recommended Physical Project Structure, reference the same NuGet packages, share the same source code for its Server and Client App implementations as well as Client and Server Unit and Integration Tests.
v5 includes 11 new .NET Core 2.0 project templates for each of ServiceStack’s most popular starting templates. Each .NET Core 2.0 template has an equivalent .NET Framework template except for ServiceStack’s Templates WebApp which is itslef a pre-built .NET Core 2.0 App that lets you develop Web Applications and HTTP APIs on-the-fly without any compilation.
All .NET Core 2.0 Templates can be developed using your preferred choice of either VS Code, VS.NET or JetBrains Project Rider on your preferred Desktop OS. Given the diverse ecosystem used to develop .NET Core Applications, the new Project Templates are being maintained on GitHub and made available via our new dotnet-new command-line utility, installable from npm with:
$ npm install -g @servicestack/cli
This makes the dotnet-new
command globally available which can be run without arguments to view all templates available:
That can be used to create new projects with:
$ dotnet-new <template-name> <project-name>
Example of creating a new Vue SPA project called Acme:
$ dotnet-new vue-spa Acme
The resulting Acme.sln
can be opened in VS 2017 which will automatically restore and install both the .NET and npm packages upon first load and build.
If using JetBrains Rider the npm packages can be installed by opening package.json
and clicking on the “npm install” tooltip on the bottom right. In VS Code you’ll need to run npm install
manually from the command-line.
ServiceStackVS VS.NET Templates Updated
The VS.NET Templates inside ServiceStackVS have also been updated to use the latest .NET Framework templates which you can continue to use to create new projects within VS.NET. For all other IDEs and non-Windows Operating Systems you can use the cross-platform dotnet-new
tooling to create new .NET Core 2.0 Projects.
.NET Core 2.0 TypeScript Webpack Templates
There’s a project template for each of the most popular Single Page Application JavaScript frameworks, including a new Angular 5.1 template built and managed using Angular’s new angular-cli tooling. All other SPA Templates (inc. Angular 4) utilize a modernized Webpack build system, pre-configured with npm scripts to perform all necessary debug, production and live watched builds and testing. The included gulpfile.js provides a Gulp script around each npm script so they can be run without the command-line, by running them using VS.NET’s built-in Task Runner Explorer GUI.
All SPA templates are configured to use Typed DTOs from TypeScript Add Reference with the generic @servicestack/client JsonServiceClient
with concrete Type Definitions except for the Angular 5 template which uses Angular’s built-in Rx-enabled HTTP Client with ServiceStack’s ambient TypeScript declarations, as it’s often preferable to utilize Angular’s built-in dependencies when available.
All Single Page App Templates are available for both .NET Core 2.0 and ASP.NET Framework projects which can be live-previewed and used to create new projects using the template names below:
Angular 5 CLI Bootstrap Template
- .NET Core: angular-cli
- .NET Framework: angular-cli-netfx
- Live Preview: angular-cli.web-templates.io
Angular 4 Material Design Lite Template
- .NET Core: https://github.com/NetCoreTemplates/angular-lite-spa
- .NET Framework: angular-lite-spa-netfx
- Live Preview: angular-lite-spa.web-templates.io
React 16 Webpack Bootstrap Template
- .NET Core: react-spa
- .NET Framework: react-spa-netfx
- Live Preview: react-spa.web-templates.io
Vue 2.5 Webpack Bootstrap Template
- .NET Core: vue-spa
- .NET Framework: vue-spa-netfx
- Live Preview: vue-spa.web-templates.io
Aurelia Webpack Bootstrap Template
- .NET Core: aurelia-spa
- .NET Framework: aurelia-spa
- Live Preview: aurelia-spa.web-templates.io
Optimal Dev Workflow with Hot Reloading
The Webpack templates have been updated to utilize Webpack’s DllPlugin which splits your App’s TypeScript source code from its vendor dependencies for faster incremental build times. With the improved iteration times our recommendation for development is to run a normal Webpack watched build using the dev
npm (or Gulp) script:
$ npm run dev
Which will watch and re-compile your App for any changes. These new templates also include a new hot-reload feature which works similar to ServiceStack Templates hot-reloading where in DebugMode it will long poll the server to watch for any modified files in /wwwroot
and automatically refresh the page. This provides a hot-reload alternative to npm run dev-server
to run a Webpack Dev Server proxy on port http://localhost:3000
Deployments
When your App is ready to deploy, run the publish
npm (or Gulp) script to package your App for deployment:
npm run publish
Which generates a production Webpack client build and dotnet publish
release Server build to package your App ready for an XCOPY, rsync or MSDeploy deployment. We used rsync and supervisord to deploy each packaged Web template to our Ubuntu Server at the following URL:
http://<template-name>.web-templates.io
/wwwroot WebRoot Path for .NET Framework Templates
To simplify migration efforts of ServiceStack projects between .NET Core and .NET Framework, all SPA and Website Templates are configured to use .NET Core’s convention of /wwwroot
for its public WebRoot Path. The 2 adjustments needed to support this was configuring ServiceStack to use the /wwwroot
path in AppHost:
SetConfig(new HostConfig {
WebHostPhysicalPath = MapProjectPath("~/wwwroot"),
});
Then instructing MSBuild to include all wwwroot\**\*
files when publishing the project using MS WebDeploy which is contained in the Properties/PublishProfiles/PublishToIIS.pubxml of each project.
Website Templates
There are 3 templates for each of the different technologies that can be used with ServiceStack to develop Server HTML Generated Websites and HTTP APIs:
ASP.NET MVC
- .NET Core: mvc
- .NET Framework: mvc-netfx
- Live Preview: mvc.web-templates.io
ServiceStack.Razor
- .NET Core:
- .NET Framework:
- Live Preview: .web-templates.io
ServiceStack Templates
- .NET Core: templates
- .NET Framework: templates-netfx
- Live Preview: templates.web-templates.io
Hot Reloading
Both razor
and templates
project enjoy Hot Reloading where in development a long poll is used to detect and reload changes in the current Template Page or static files in /wwwroot
.
Empty Web and SelfHost Templates
Those who prefer starting from an Empty slate can use the web
template to create the minimal configuration for a Web Application whilst the selfhost
template can be used to develop Self-Hosting Console Apps. Both templates still follow our recommended physical project layout but are configured with the minimum number of dependencies.
Empty Web Template
- .NET Core: web
- .NET Framework: web-netfx
- Live Preview: web.web-templates.io
Empty SelfHost Console App Template
- .NET Core: selfhost
- .NET Framework: selfhost-netfx
- Live Preview: selfhost.web-templates.io
.NET Core 2.0 ServiceStack WebApp Template
The only .NET Core 2.0 project template not to have a .NET Framework equivalent is templates-webapp as it’s a pre-built .NET Core 2.0 App that dramatically simplifies .NET Wep App development by enabling Websites and APIs to be developed instantly without compilation.
- .NET Core: templates-webapp
- Live Preview: templates-webapp.web-templates.io
See templates.servicestack.net/docs/web-apps to learn the different use-cases made possible with Web Apps.
.NET Framework Templates
Likewise there are 2 .NET Framework Templates without .NET Core 2.0 equivalents as they contain Windows-only .NET Framework dependencies. This includes our React Desktop Template which supports packaging your Web App into 4 different ASP.NET, Winforms, OSX Cocoa and cross-platform Console App Hosts:
React Desktop Apps Template
- .NET Framework: react-desktop-apps-netfx
- Live Preview: react-desktop-apps-netfx.web-templates.io
Windows Service Template
You can use winservice-netfx to create a Windows Service but as this requires Visual Studio it’s faster to continue creating new Windows Service projects within VS.NET using the ServiceStack Windows Service Empty Project Template.
All Apps and Live Demos Upgraded
All existing .NET Core 1.x projects have been upgraded to .NET Core 2.0 and ServiceStack v5, including all .NET Core Live Demos, all .NET Core 2.0 Web Apps and all .NET Framework Live Demos.
ServiceStack WebApps
The .NET Core 2.0 Web Apps now use the default WebHost.CreateDefaultBuilder()
builder to bootstrap WebApp’s letting you use ASPNETCORE_URLS
to specify which URL and port to bind on, simplifying deployment configurations.
The ASPNETCORE_ENVIRONMENT
Environment variable can also be used to configure WebApp’s to run in Production
mode. If preferred you can continue using the existing bind
, port
and debug
options in your web.settings
to override the default configuration.
Multi-stage Docker Builds
The .NET Core Apps deployed using Docker now use the ASP.NET Team’s recommended multi-stage Docker Builds where the App is built inside an aspnetcore-build
Docker container with its published output copied inside a new aspnetcore
runtime Docker container:
FROM microsoft/aspnetcore-build:2.0 AS build-env
COPY src /app
WORKDIR /app
RUN dotnet restore --configfile ../NuGet.Config
RUN dotnet publish -c Release -o out
# Build runtime image
FROM microsoft/aspnetcore:2.0
WORKDIR /app
COPY --from=build-env /app/Chat/out .
ENV ASPNETCORE_URLS http://*:5000
ENTRYPOINT ["dotnet", "Chat.dll"]
The smaller footprint required by the aspnetcore
runtime reduced the footprint of .NET Core Chat from 567MB to 126MB whilst continuing to run flawlessly in AWS ECS at chat.netcore.io.
.NET Core IAppSettings Adapter
Most .NET Core Templates are also configured to use the new NetCoreAppSettings
adapter to utilize .NET Core’s new IConfiguration
config model in ServiceStack by initializing the AppHost
with .NET Core’s pre-configured IConfiguration
that’s injected into the Startup.cs constructor, e.g:
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration) => Configuration = configuration;
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseServiceStack(new AppHost {
AppSettings = new NetCoreAppSettings(Configuration)
});
}
}
PBKDF2 Password Hashing implementation
ServiceStack now uses the same PBKDF2 password hashing algorithm ASP.NET Identity v3 uses to hash passwords by default for both new users and successful authentication logins where their password will automatically be re-hashed with the new implementation.
This also means if you wanted to switch, you’ll be able to import ASP.NET Identity v3 User Accounts and their Password Hashes into ServiceStack.Auth’s UserAuth
tables and vice-versa.
Retain previous Password Hashing implementation
If preferred you can revert to using the existing SaltedHash
implementation with:
SetConfig(new HostConfig {
UseSaltedHash = true
});
This also supports “downgrading” passwords that were hashed with the new IPasswordHasher
provider where it will revert to using the older/weaker SaltedHash
implementation on successful authentication.
Digest Auth Hashes only created when needed
Digest Auth Hashes are now only populated if the DigestAuthProvider
is registered. If you ever intend to support Digest access authentication in future but don’t want to register the DigestAuthProvider just yet, you can force ServiceStack to continue to maintain Digest Auth Hashes with:
new AuthFeature {
CreateDigestAuthHashes = true
}
JWT AuthProvider
Previously in order to be able to utilize RefreshToken’s you would need to be also be using an Auth Repository as it’s the data source used to populate the JWT Token.
Now Users who are not using an IAuthRepository
can instead implement the IUserSessionSource
interface:
public interface IUserSessionSource
{
IAuthSession GetUserSession(string userAuthId);
}
On either their Custom AuthProvider, or if preferred register it as a dependency in the IOC as an alternative source for populating Sessions in new JWT Tokens created using RefreshToken’s. The implementation should only return a populated IAuthSession
if the User is allowed to sign-in, i,e. if their account is locked or suspended it should throw an Exception, e.g:
throw HttpError.Forbidden("User is suspended");
Send JWTs in HTTP Params
The JWT Auth Provider can opt-in to accept JWT’s via the Query String or HTML POST FormData with:
new JwtAuthProvider {
AllowInQueryString = true,
AllowInFormData = true
}
This is useful for situations where it’s not possible to attach the JWT in the HTTP Request Headers or ss-tok
Cookie.
Runtime JWT Configuration
To allow for dynamic per request configuration as needed in Multi Tenant applications we’ve added a new IRuntimeAppSettings API which can be registered in your AppHost
to return custom per request configuration.
E.g. this can be used to return a custom AuthKey
that should be used to sign JWT Tokens for that request:
container.Register<IRuntimeAppSettings>(c => new RuntimeAppSettings {
Settings = {
{ nameof(JwtAuthProvider.AuthKey), req => (byte[]) GetAuthKey(GetTenantId(req)) }
}
});
Registration
The JWT BearerToken
and RefreshToken
properties added to RegisterResponse
are now populated on Registrations configured to AutoLogin=true
.
Routes with Custom Rules
The new Matches
property on [Route]
and [FallbackRoute]
attributes lets you specify an additional custom Rule that requests need to match. This feature is used in all SPA projects to specify that the [FallbackRoute]
should only return the SPA index.html
for unmatched requests which explicitly requests HTML, i.e:
[FallbackRoute("/{PathInfo*}", Matches="AcceptsHtml")]
public class FallbackForClientRoutes
{
public string PathInfo { get; set; }
}
This works by matching the AcceptsHtml
built-in RequestRules
below where the Route will only match the Request if it includes the explicit text/html
MimeType in the HTTP Request Accept
Header. The AcceptsHtml
rule prevents the home page from being returned for missing resource requests like favicon which returns a 404
instead.
The implementation of all built-in Request Rules.
Routes that contain a Matches
rule have a higher precedence then Routes without. We can use this to define multiple idential matching routes to call different Service depending on whether the Path Segment is an integer or not, e.g:
// matches /users/1
[Route("/users/{Id}", Matches = "**/{int}")]
public class GetUser
{
public int Id { get; set; }
}
// matches /users/username
[Route("/users/{Slug}")]
public class GetUserBySlug
{
public string Slug { get; set; }
}
Other examples utilizing {int}
Request Rules:
// matches /1/profile
[Route("/{UserId}/profile", Matches = @"{int}/**")]
public class GetProfile { ... }
// matches /username/profile
[Route("/{Slug}/profile")]
public class GetProfileBySlug { ... }
// matches /users/1/profile/avatar
[Route("/users/{UserId}/profile/avatar", Matches = @"path/{int}/**")]
public class GetProfileAvatar { ... }
// matches /users/username/profile/avatar
[Route("/users/{Slug}/profile/avatar")]
public class GetProfileAvatarBySlug { ... }
Another popular use-case is to call different services depending on whether a Request is from an Authenticated User or not:
[Route("/feed", Matches = "IsAuthenticated")]
public class ViewCustomizedUserFeed { ... }
[Route("/feed")]
public class ViewPublicFeed { ... }
This can also be used to call different Services depending if the Request is from a Mobile browser or not:
[Route("/search", Matches = "IsMobile")]
public class MobileSearch { ... }
[Route("/search")]
public class DesktopSearch { ... }
Instead of matching on a pre-configured RequestRule you can instead specify a Regular Expression using the format:
{Property} =~ {RegEx}
Where {Property}
is an IHttpRequest
property, e.g:
[Route("/users/{Id}", Matches = @"PathInfo =~ \/[0-9]+$")]
public class GetUser { ... }
An exact match takes the format:
{Property} = {Value}
Which you could use to provide a tailored feed for specific clients:
[Route("/feed", Matches = @"UserAgent = specific-client")]
public class CustomFeedView { ... }
ServiceStack Templates View Pages
ServiceStack Templates gains support for the last missing feature from ServiceStack.Razor with its new View Pages support which lets you use .html
Template Pages to render the HTML for Services Responses.
Just like ServiceStack.Razor you can also specify to use different Views or Layouts by returning a custom HttpResult
, e.g:
public object Any(MyRequest request)
{
...
return new HttpResult(response)
{
View = "CustomPage",
Template = "_custom-layout",
};
}
Or add the [ClientCanSwapTemplates]
Request Filter attribute to allow clients to specify which View and Template to use via the query string, e.g: ?View=CustomPage&Template=_custom-layout
.
Additional examples of dynamically specifying the View and Template are available in TemplateViewPagesTests.
Logging with Context
Rolf Kristensen added support for contextual logging with the new ILogWithContext
interface and PushProperty
extension method which lets you attach additional data to log messages, e.g:
using (log.PushProperty("Hello", "World"))
{
log.InfoFormat("Message");
}
Support for the additional context was added to Log4net
, NLog
and Serilog
logging providers.
Validation
Our internal implementation of FluentValidation has been upgraded to the latest 7.2 version which will let you take advantage of new features like implementing Custom Validators, e.g:
public class CustomValidationValidator : AbstractValidator<CustomValidation>
{
public CustomValidationValidator()
{
RuleFor(request => request.Code).NotEmpty();
RuleFor(request => request)
.Custom((request, context) => {
if (request.Code?.StartsWith("X-") != true)
{
var propName = context.ParentContext.PropertyChain.BuildPropertyName("Code");
context.AddFailure(new ValidationFailure(propName, error:"Incorrect prefix") {
ErrorCode = "NotFound"
});
}
});
}
}
Validators in ServiceAssemblies auto-wired by default
The ValidationFeature
plugin now scans and auto-wires all validators in the AppHost.ServiceAssemblies
that’s injected in the AppHost constructor so you’ll no longer need to manually register validators maintained in your ServiceInterface.dll
project:
//container.RegisterValidators(typeof(UserValidator).Assembly);
Expanded Async Support
To pre-emptively support .NET Core when they disable Sync Response writes by default in a future version, we’ve rewritten our internal implementations to write to Responses asynchronously.
New Async filters are now available to match existing sync filters. It’s very unlikely the classic ASP.NET Framework will ever disable sync writes, but if you’re on .NET Core you may want to consider switching to use the newer async API equivalents on IAppHost below:
GlobalRequestFiltersAsync
GlobalResponseFiltersAsync
GatewayRequestFiltersAsync
GatewayResponseFiltersAsync
GlobalMessageRequestFiltersAsync
GlobalMessageResponseFiltersAsync
Async Attribute Filters
Async Filter Attributes are available by inheriting the new RequestFilterAsyncAttribute
or ResponseFilterAsyncAttribute
base classes if you need to call async APIs within Filter Attributes.
All async equivalents follow the same Order of Operations and are executed immediately after any registered sync filters with the same priority.
Async Request and Response Converters
As they’re not commonly used, the RequestConverters
and ResponseConverters
were just converted to utilize an Async API.
Async ContentTypes Formats
There’s also new async registration APIs for Content-Type Formats which perform Async I/O, most serialization formats don’t except for HTML View Engines which can perform Async I/O when rendering views, so they were changed to use the new RegisterAsync
APIs:
appHost.ContentTypes.RegisterAsync(MimeTypes.Html, SerializeToStreamAsync, null);
appHost.ContentTypes.RegisterAsync(MimeTypes.JsonReport, SerializeToStreamAsync, null);
appHost.ContentTypes.RegisterAsync(MimeTypes.MarkdownText, SerializeToStreamAsync, null);
Async HttpWebRequest Service Clients
The Async implementation of the HttpWebRequest
based Service Clients was rewritten to use the newer .NET 4.5 Async APIs as the older APM APIs were found to have some async request hanging issues in the .NET Standard 2.0 version of Xamarin.iOS.
Minor Features
ToOptimizedResult()
now supportsHttpResult
responsesConfig.DebugMode
is being initialized withenv.IsDevelopment()
in .NET CoreMapProjectPath()
usesenv.ContentRoot
in .NET CoreMetadataDebugTemplate
no longer has dependencies onjquip
andss-utils.js
IMeta
,IHasSessionId
andIHasVersion
interfaces are now exported in Add ServiceStack ReferenceHtml.IncludeFile()
API for embedding file contents in Razor viewsVirtualFiles
andVirtualFileSources
properties added to base Razor View
@servicestack npm packages
ServiceStack’s npm packages are now being maintained in npm organization scoped @servicestack
packages, if you were using the previous packages you should uninstall them and use the new scoped packages instead:
$ npm uninstall servicestack-client
$ npm install @servicestack/client
$ npm uninstall -g servicestack-cli
$ npm install -g @servicestack/cli
You’ll also need to update your source code references to use the new packages:
import { JsonServiceClient } from "@servicestack/client";
ServiceStack.OrmLite
Support for MySqlConnector ADO.NET Provider
@Naragato from the ServiceStack Community contributed a MySqlConnector for OrmLite providing a true async ADO.NET Provider option for MySql, from their website:
This is a clean-room reimplementation of the MySQL Protocol and is not based on the official connector.
It’s fully async, supporting the async ADO.NET methods added in .NET 4.5 without blocking (or using Task.Run to run synchronous methods on a background thread). It’s also 100% compatible with .NET Core.
To use it, install:
PM> Install-Package ServiceStack.Ormlite.MySqlConnector
Then initialize your DB Factory with:
var dbFactory = new OrmLiteConnectionFactory(connectionString, MySqlConnectorDialect.Provider);
using (var db = dbFactory.Open())
{
...
}
Parametrized IN Values
You can now provide a collection of values and OrmLite will automatically modify the SQL statement and split the values into multiple DB parameters to simplify executing parameterized SQL with multiple IN Values, e.g:
var ids = new[]{ 1, 2, 3};
var results = db.Select<Table>("Id in (@ids)", new { ids });
var names = new List<string>{ "foo", "bar", "qux" };
var results = db.SqlList<Table>("SELECT * FROM Table WHERE Name IN (@names)", new { names });
RowVersion Byte Array
To improve reuse of OrmLite’s Data Models in Dapper, @daleholborow
added support for allowing byte[] RowVersion
as an alternative to OrmLite’s ulong RowVersion
which lets you use OrmLite Data Models with byte[] RowVersion
properties in Dapper queries.
OnOpenConnection Filter
The OnOpenConnection
filter lets you run custom commands after opening a new DB Connection. This feature can be used to easily enable Write-Ahead Logging in SQLite:
var dbFactory = new OrmLiteConnectionFactory("sqlite.db", SqliteDialect.Provider);
SqliteDialect.Provider.OnOpenConnection = db => db.ExecuteSql("PRAGMA journal_mode=WAL;");
OpenAsync APIs
The new OpenDbConnectionAsync()
and OpenAsync()
alias APIs can be used to Open DB connections asynchronously.
ServiceStack.Aws
PocoDynamo was updated to utilize AWS’s recommended Exponential Backoff And Jitter algorithm.
This is also available to be used independently with:
Thread.Sleep(ExecUtils.CalculateFullJitterBackOffDelay(retriesAttempted));
await Task.Delay(ExecUtils.CalculateFullJitterBackOffDelay(retriesAttempted));