Web Apps

Web Apps are a new approach to dramatically simplify .NET Wep App development
and provide the most productive development experience possible whilst maximizing reuse and component sharing.
They also open up a number of new use-cases for maintaining clean isolation between front-end and back-end development with
front-end developers not needing any knowledge of C#/.NET to be able to develop UIs for high-performance .NET Web Apps.
Web Apps also make it easy to establish and share an approved suite of functionality amongst multiple websites all
consuming the same back-end systems and data stores.

Web Apps leverages Templates to develop entire content-rich, data-driven websites without needing to write any C#,
compile projects or manually refresh pages - resulting in the easiest and fastest way to develop Web Apps in .NET!

Ultimate Simplicity

Not having to write any C# code or perform any app builds dramatically reduces the cognitive overhead and conceptual knowledge
required for development where the only thing front-end Web developers need to know is Template's syntax
and what filters are available to call.
Because of Template's high-fidelity with JavaScript, developing a Website with Templates will be instantly familiar to JavaScript
devs despite calling and binding directly to .NET APIs behind the scenes.

All complexity with C#, .NET, namespaces, references, .dlls, strong naming, packages, MVC, Razor, build tools, IDE environments, etc
has been eliminated leaving all Web Developers needing to do is run a cross-platform
web/app.dll .NET Core 2.0 executable and configure a simple
web.settings
text file to specify which website folder to use, which ServiceStack features to enable, which db or redis providers to connect to, etc.
Not needing to build also greatly simplifies deployments where multiple websites can be deployed with a
single rsync or xcopy command or
if deploying your App in a Docker Container, you just need to
copy your website files, or just the web.settings
if you're using an S3 or Azure Virtual File System.

Rapid Development Workflow

The iterative development experience is also unparalleled for a .NET App, no compilation is required so you can just leave
the web/app.dll running whilst you add the template .html files needed to build your App and thanks
to the built-in Hot Reloading support, pages will refresh automatically as you save.
You'll just need to do a full page refresh when modifying external .css/.js files to bypass the browser cache and
you'll need to restart web/app.dll to pick up any changes to your web.settings or added any
.dlls to your /plugins folder.

Getting Started

The easiest way to get started to either clone the WebAppStarter GitHub project:

This contains 2 folders, /app contains all source code and
assets for your Web App and /web contains a copy of the WebApp
binaries from ServiceStack/WebApp. There's also
start-app.bat and
start-app.sh scripts for running your app in
Windows, OSX and Linux. Both scripts run the same command:

dotnet web/app.dll ../app/web.settings

Which can be run instead of the script, it also means cat start-app.bat | sh will also run the app on OSX and Linux.

Once running you can view your App on http://localhost:5000/ which you can keep running whilst developing your app
which will reload the page you're currently viewing on each file save using the built-in Hot Reloading.

/app is an example of a single Web App, you can have multiple Web Apps in different folders and run any of them with:

dotnet web/app.dll ../<app name>/web.settings

Cloud Apps Starter Projects

If you intend to deploy your Web App on AWS or Azure you may prefer to start with one of the example
Cloud Apps below which come pre-configured with deployment scripts for deploying with Travis CI and Docker:

Example Web Apps

We've developed a number of Web Apps to illustrate the various features available and to showcase the different kind of Web Apps
that can easily be developed. The source code for each app is available either individually from
[github.com/NetCoreWebApps](https://github.com/NetCoreWebApps) or all combined in the same repo at
NetCoreWebApps/WebApp/apps.
Each app runs the same unmodified [Web App Binary](https://github.com/NetCoreWebApps/Web) that's also used in the WebAppStarter project above.

Running Web Apps locally

Each of these apps can be run locally by cloning NetCoreWebApps/WebApp
and running the start.bat scripts in the /apps folder.
If you want to use your local RDBMS you can use
/support/northwind-data to quickly
populate it with the Northwind database and
/support/copy-files to populate your own
S3 Bucket or Azure Blob Container with the
/rockwind-vfs Web App's files.
As each app runs on http://localhost:5000 you'll need to do a hard refresh with Ctrl+Shift+F5 after
launching each App to tell the browser to ignore the cached .css and .js from the previous App.

Web App Starter

The Getting Started project contains a copy of the bare.web-app.io project below
which is representative of a typical Company splash Website:

The benefits over using a static website is improved maintenance
as you can extract and use its common _layout.html
instead of having it duplicated in each page.
The menu.html partial also makes menu items
easier to maintain by just adding an entry in the JavaScript object literal. The dynamic menu also takes care of highlighting the active menu item.

Ideal for Web Designers and Content Authors

The other primary benefit is that this is an example of a website that can be maintained by employees who don't have any
programming experience as Templates in their basic form are intuitive and approachable to non-developers, e.g:
The title of each page is maintained as metadata HTML comments:

<!--
title: About Us
-->

Template's syntax is also the ideal way to convey variable substitution, e.g: <title>{{ title }}</title>
and even embedding a partial reads like english {{ 'menu' | partial }} which is both intuitive and works well
with GUI HTML designers.

Below is the web.settings for a Basic App, with contentRoot being the only setting required as the
rest can be inferred but including the other relevant settings is both more descriptive to other developers as well
making it easier to
use tools like sed or
powershell to replace them
during deployment.

Redis HTML

For the Redis Browser Web App, we wanted to implement an App that was an ideal candidate for a Single Page App but constrain ourselves
to do all HTML rendering on the server and have each interaction request a full-page reload to see how a traditional server-generated
Web App feels like with the performance of .NET Core 2.0 and Templates. We're pleasantly surprised with the result as when
the App is run locally the responsiveness is effectively indistinguishable from an Ajax App. When hosted on the Internet
there is a sub-second delay which causes a noticeable flicker but it still retains a pleasant UX that's faster than most websites.

The benefits of a traditional website is that it doesn't break the web where the back button and deep linking work without effort
and you get to avoid the complexity train of adopting a premier JavaScript SPA Framework's configuration, dependencies, workflow
and build system which has become overkill for small projects.

We've had a sordid history developing Redis UI's which we're built using the popular JavaScript frameworks that appeared
dominant at the time but have since seen their ecosystem decline, starting with the
Redis Admin UI (src)
built using
Google's Closure Library that as it works different to everything else
needed a complete rewrite when creating redisreact.servicestack.net
(src) using the hot new React framework, unfortunately it uses React's old
deprecated ES5 syntax and Reflux which is sufficiently different from our current recommended
TypeScript + React + Redux + WebPack JavaScript SPA Stack,
that is going to require a significant refactor to adopt our preferred SPA tech stack.

Beautiful, succinct, declarative code

The nice thing about generating HTML is that it's the one true constant in Web development that will always be there.
The entire functionality for the Redis Web App is contained in a single
/RedisHtml/app/index.html which includes
all Template and JavaScript Source Code in < 200 lines which also includes all as server logic as it doesn't rely on any
back-end Services and just uses the Redis Filters to interface with Redis directly.
The source code also serves as a good
demonstration of the declarative coding style that Templates encourages that in addition to being highly-readable requires orders
of magnitude less code than our previous Redis JavaScript SPA's with a comparable feature-set.

Having a much smaller code-base makes it much easier to maintain and enhance whilst being less susceptible to becoming obsolete
by the next new JavaScript framework as it would only require rewriting 75 lines of JavaScript instead of the complete rewrite
that would be required to convert the existing JavaScript Apps to a use different JavaScript fx.

The web.settings for Redis is similar to Web App Starter above except it adds a redis.connection
to configure a RedisManagerPool at the
connection string provided
as well as Redis Filters to give Templates access to the Redis instance.

Redis Vue

Whilst the above server-generated HTML Redis UI shows how you can easily develop traditional Web Apps using Templates, we've also
rewritten the Redis UI as a Single Page App which is the more suitable choice for an App like this as it provides a more
optimal and responsive UX by only loading the HTML page once on Startup then utilizes Ajax to download and dynamically update
incremental parts of the App's UI that needs changing.

Instead of using jQuery and server-side HTML this version has been rewritten to use Vue
where the UI has been extracted into isolated Vue components utilizing
Vue X-Templates to render the App on the client where
all Redis Vue's functionality is contained within the
Redis/app/index.html page.

Simple Vue App

Templates also provides a great development experience for Single Page Apps which for the most part gets out of your way letting you
develop the Single Page App as if it were a static .html file, but also benefits from the flexibility of a
dynamic web page when needed.

The containing _layout.html
page can be separated from the index.html page
that contains the App's functionality, where it's able to extract the title of the page and embed it in the
HTML <head/> as well as embed the page's <script /> in its optimal location at the bottom of the
HTML <body/>, after the page's blocking script dependencies:

Redis Vue avoids the complexity of adopting a npm build system by refrencing Vue libraries as a simple script include:

<script src="../assets/js/vue{{ '.min' | if(!debug) }}.js">

Where it uses the more verbose and developer-friendly
vue.js
during development whilst using the production optimized
vue.min.js
for deployments. So despite avoiding the complexity tax of an npm-based build system it still gets some of its benefits
like conditional deployments and effortless hot reloading.

Server Templates

Whilst most of index.html is a static Vue
app, templates is leveraged to generate the body of the <redis-info/> Component on the initial home page render:

This technique increases the time to first paint by being able to render the initial Vue page without waiting for an Ajax call response
whilst benefiting from improved SEO from server-generated HTML.

Server Handling

Another area Templates is used is to handle the HTTP POST where it calls the redisChangeConnection filter to change
the current Redis connection before rendering the
connection-info.html partial with the
current connection info:

The benefits of using API Pages instead of a normal C# Service is being able to retain the productive development workflow
of Web Apps where the entire Redis Vue App can be built without any compilation.

Deep linking and full page reloads

The Redis Vue Single Page App also takes advantage of HTML5's history.pushState API to enable deep-linking and back-button
support where most UI state changes is captured on the query string and used to initialize the Vue state on full-page reloads
to proivde transparent history navigation and back-button support that functions like a traditional Web App but with the performance
of a Single Page App.

Rockwind

The Rockwind website shows an example of combining multiple websites in a single Web App - a
Rockstars Content Website and a dynamic data-driven UI for the Northwind database which can
run against either SQL Server, MySql or SQLite database using just configuration. It also includes
API Pages examples for rapidly developing Web APIs.

Rockstars

/rockstars is an
example of a Content Website that itself maintains multiple sub sections with their own layouts -
/rockstars/alive
for living Rockstars and
/rockstars/dead
for the ones that have died. Each Rockstar maintains their own encapsulated
mix of HTML, markdown content and splash image
that intuitively uses the closest _layout.html, content.md and splash.jpg from the page they're
referenced from. This approach makes it easy to move entire sub sections over by just moving a folder and it will automatically
use the relevant layout and partials of its parent.

SQLite uses a file system database letting you bundle your database with your App. So we can share the
northwind.sqlite database across multiple Apps,
the contentRoot is set to the /apps directory which can only be accessed by your App, whilst
the webRoot is configured to use the Web Apps folder that hosts all the publicly accessible files of your App.

To switch to use the Northwind database in SQL Server we just need to update the configuration to point to a SQL Server database
instance. Since the App no longer need access to the northwind.sqlite database, the contentRoot can be reverted
back to the Web Apps folder:

The /support/northwind-data
project lets you quickly try out Rockwind against your local RDBMS by populating it with a copy of the Northwind database
using the same sqlserver identifier and connection string from the App, e.g:

The example Azure configuration is also configured to use a different Virtual File System where instead of sourcing
Web App files from the filesystem they're sourced from an
Azure Blob Container.
In this case we're not using any files from the App so we don't need to set a contentRoot or webRoot path.
This also means that for deployment we're just deploying the WebApp
binary with just this web.settings since both the Web App files and database are sourced remotely.

Multi-RDBMS SQL

As Templates is unable to use a Typed ORM like OrmLite
to hide the nuances of each database, we need to be a bit more diligent in Templates to use parameterized SQL that works across
multiple databases by using the
sql* DB Filters to avoid using RDBMS-specific
SQL syntax. The
/northwind/customer.html
contains a good example containing a number of things to watch out for:

Use sqlConcat to concatenate strings using the RDBMS-specific SQL for the configured database. Likewise
sqlCurrency utilizes RDBMS-specific SQL functions to return monetary values in a currency format, whilst
sqlQuote is used for quoting tables named after a reserved word.

Of course if you don't intend on supporting multiple RDBMS's, you can ignore this and use RDBMS-specific syntax.

Rockwind VFS

/rockwind-vfs is a clone of
the Rockwind Web App with 3 differences: It uses the resolveAsset filter for each .js, .css and
image web asset so that it's able to generate external URLs directly to the S3 Bucket, Azure Blob Container or CDN
hosting a copy of your files to both reduce the load on your Web App and maximize the responsiveness to the end user.

The other difference is that each table and column has been quoted in "double-quotes" so that it works in PostgreSQL which
otherwise treats unquoted symbols as lowercase. This version of Rockwind also works with SQL Server and SQLite as they also
support "Table" quotes but not MySql which uses `BackTicks` or [SquareBrackets]. It's therefore
infeasible to develop Apps that support both PostgreSQL and MySql unless you're willing to use all lowercase,
snake_case or the sqlQuote filter for every table and column.

resolveAsset

If using a remote file storage like AWS S3 or Azure Blob Storage it's a good idea to use the resolveAsset filter
for each external file reference. By default it returns the same path it was called with so it will continue to work locally
but then ServiceStack effectively becomes a proxy where it has to call the remote Storage Service for each requested download.

ServiceStack asynchronously writes each file to the Response Stream with the last Last-Modified HTTP Header to
enable browser caching so it's still a workable solution but for optimal performance you can specify an args.assetsBase
in your web.settings to populate the assetsBase TemplateContext Argument the resolveAsset filter uses to generate
an external URL reference to the file on the remote storage service, reducing the load and improving the performance of your App,
especially if it's configured to use a CDN.

With all files being sourced from S3 and the App configured to use AWS RDS PostgreSQL, the AWS settings is an example of
a Pure Cloud App where the entire App is hosted on managed cloud services that's decoupled from the .NET Core 2.0 binary
that runs it that for the most part won't require redeploying the Web App binary unless making configuration changes or
upgrading the web/app.dll as any App changes can just be uploaded straight to S3 which changes reflected within the
checkForModifiedPagesAfterSecs setting, which tells the Web App how long to wait before checking for file changes
whilst defaultFileCacheExpirySecs specifies how long to cache files like content.md for.

We can also create Azure Cloud Apps in the same we've done for AWS above, which runs the same
/rockwind-vfs
Web App but using an Azure hosted SQL Server database and its files hosted on Azure Blob Storage:

Plugins

Up till now the Apps above only have only used functionality built into ServiceStack, to enable even greater functionality
but still retain all the benefits of developing Web Apps you can drop .dll with custom functionality into your
Web App's /plugins folder. The plugins support in Web Apps is as friction-less as we could make it, there's no
configuration to maintain or special interfaces to implement, you're able to drop your existing implementation .dll's
as-is into the App's `/plugins` folder.

All plugins listed in features will be added to your Web App's AppHost in the order they're specified.
They can further customized by adding a separate config entry with the Plugin Name and a JavaScript Object literal to
populate the Plugin at registration, e.g the config above is equivalent to:

Where as it was first registered in the list will appear before any links registered by other plugins:

Built-in Plugins

It also tells the ValidationFeature to scan all Service Assemblies for Validators and to automatically register them
which is how ServiceStack was able to find the
ContactValidator
used to validate the StoreContact request.

ServiceStack Ecosystem

All Services loaded by plugins continue to benefit from ServiceStack's rich metadata services, including being listed
in the /metadata page, being able to explore and interact with Services using
/swagger-ui/ as well as being able to generate Typed APIs for the most popular
Mobile, Web and Desktop platforms.

Chat

/chat is an example of the ultimate form
of extensibility where instead of just being able to add Services, Filters and Plugins, etc. You can add your entire
AppHost which Web Apps will use instead of its own. This vastly expands the use-cases that can be built with
Web Apps as it gives you complete fine-grained control over how your App is configured.

Customizations from the original
.NET Core Chat implementation
includes removing MVC and Razor dependencies and configuration, extracting its
_layout.html and
converting index.html
to use Templates from its original
default.cshtml.
It's also been enhanced with the ability to evaluate Templates from the Chat window, as seen in the screenshot above.

Reusing Web App's web.setting and files

One nice thing from being able to reuse existing AppHost's is being able to develop all back-end C# Services and Custom Filters
as a stand-alone .NET Core Project where it's more productive with access to .NET IDE tooling and debugging.

To account for these 2 modes we use AddIfNotExists to only register the TemplatePagesFeature plugin
when running as a stand-alone App and add an additional constructor so it reuses the existing web.settings as its
IAppSettings provider for is custom App configuration like OAuth App keys
required for enabling Sign-In's via with Twitter, Facebook and GitHub when running on http://localhost:5000:

After the back-end has been implemented we can build and copy the compiled Chat.dll into the Chat's
/plugins folder where
we can take advantage of the improved development experience for rapidly developing its UI.