# Source: https://raw.githubusercontent.com/ServiceStack/docs.servicestack.net/refs/heads/main/MyApp/_pages/templates/desktop.md

---
title: Desktop Project Templates
slug: templates-desktop
---

<div class="not-prose my-8 ml-20 flex justify-center"><svg xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" id="svg3039">
    <defs id="defs3043">
        <linearGradient id="linearGradient3803">
            <stop style="stop-color:#d7def0;stop-opacity:1;" offset="0" id="stop3805" />
            <stop id="stop3811" offset="0.5" style="stop-color:#ffffff;stop-opacity:1" />
            <stop style="stop-color:#d5def0;stop-opacity:1" offset="1" id="stop3807" />
        </linearGradient>
        <linearGradient id="linearGradient3776">
            <stop id="stop3778" offset="0" style="stop-color:#b2cde9;stop-opacity:1" />
            <stop id="stop3780" offset="1" style="stop-color:#c4dbee;stop-opacity:1" />
        </linearGradient>
        <linearGradient id="linearGradient3750">
            <stop id="stop3752" offset="0" style="stop-color:#d0e2f1;stop-opacity:1" />
            <stop style="stop-color:#cadef0;stop-opacity:1" offset="0.85580856" id="stop3756" />
            <stop id="stop3754" offset="1" style="stop-color:#95bee3;stop-opacity:1" />
        </linearGradient>
        <linearGradient id="linearGradient3708">
            <stop style="stop-color:#658db6;stop-opacity:1" offset="0" id="stop3710" />
            <stop id="stop3716" offset="0.76777935" style="stop-color:#527fab;stop-opacity:1;" />
            <stop style="stop-color:#4071a0;stop-opacity:1" offset="1" id="stop3712" />
        </linearGradient>
        <linearGradient id="linearGradient3698">
            <stop style="stop-color:#96d0e1;stop-opacity:1" offset="0" id="stop3700" />
            <stop id="stop3706" offset="0.67819428" style="stop-color:#89b7e1;stop-opacity:1" />
            <stop style="stop-color:#699dd3;stop-opacity:1" offset="1" id="stop3702" />
        </linearGradient>
        <linearGradient id="linearGradient3647">
            <stop style="stop-color:#3b79bc;stop-opacity:1;" offset="0" id="stop3649" />
            <stop style="stop-color:#94b8e0;stop-opacity:1" offset="1" id="stop3651" />
        </linearGradient>
        <linearGradient id="linearGradient3588">
            <stop style="stop-color:#ffffff;stop-opacity:1" offset="0" id="stop3590" />
            <stop style="stop-color:#000000;stop-opacity:0;" offset="1" id="stop3592" />
        </linearGradient>
        <radialGradient xlink:href="#linearGradient3588" id="radialGradient3594" cx="-118.77966" cy="121.49152" fx="-118.77966" fy="121.49152" r="25.491526" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.02177942,-0.95743591,0.97872327,0.02221687,-235.0993,5.0684454)" />
        <linearGradient xlink:href="#linearGradient3647" id="linearGradient3653" x1="-397.81323" y1="149.18764" x2="-397.55933" y2="51.355946" gradientUnits="userSpaceOnUse" />
        <radialGradient xlink:href="#linearGradient3698" id="radialGradient3704" cx="-383.2746" cy="217.91029" fx="-383.2746" fy="217.91029" r="59.401995" gradientTransform="matrix(-1.2861568,-0.08596317,0.11453678,-1.7136762,-425.01982,469.50099)" gradientUnits="userSpaceOnUse" />
        <radialGradient xlink:href="#linearGradient3708" id="radialGradient3714" cx="-123.5" cy="-11.570732" fx="-123.5" fy="-11.570732" r="95.627118" gradientTransform="matrix(-0.00756512,0.55751399,-1.0314585,-0.01398286,113.23967,103.212)" gradientUnits="userSpaceOnUse" />
        <radialGradient xlink:href="#linearGradient3750" id="radialGradient3748" cx="-94.87291" cy="165.27281" fx="-94.87291" fy="165.27281" r="60.481357" gradientTransform="matrix(0.81293878,1.6998003,-2.1519091,1.0291615,564.39485,118.47915)" gradientUnits="userSpaceOnUse" />
        <linearGradient xlink:href="#linearGradient3776" id="linearGradient3774" x1="162.07127" y1="85.239708" x2="220.76114" y2="78.875748" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.3917128,7.418629)" />
        <linearGradient xlink:href="#linearGradient3803" id="linearGradient3809" x1="-382.04123" y1="37.280548" x2="-381.39438" y2="165.56691" gradientUnits="userSpaceOnUse" />
    </defs>
    <path style="fill:url(#radialGradient3594);fill-opacity:1;fill-rule:nonzero;stroke:none" id="path2814" d="m -92.745764,122.57627 a 25.491526,25.491526 0 1 1 -50.983056,0 25.491526,25.491526 0 1 1 50.983056,0 z" transform="matrix(4.680851,0,0,4.7978723,685.10478,-449.69946)" />
    <path style="fill:url(#linearGradient3774);fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 232.17258,88.120422 c 0,15.673918 -19.79135,34.931518 -45.84395,34.931518 -26.0526,0 -59.92241,-16.08123 -59.92241,-31.755152 0,-15.673924 21.11981,-28.38015 47.17241,-28.38015 19.90254,0 46.36122,18.293224 56.45971,20.3521 0.79179,1.710571 1.36862,2.925087 2.13424,4.851684 z" id="path3655" />
    <path style="fill:#2e5c91;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 38.822019,65.971523 c 12.38148,-9.610993 35.314514,-1.245318 51.289554,19.334679 15.975027,20.579998 17.694937,51.065068 5.31349,60.676058 -12.38147,9.61099 -34.17571,-5.29155 -50.15074,-25.87156 -12.20392,-15.72181 -4.05062,-41.19089 -8.61646,-50.430553 0.61589,-1.122052 1.381696,-2.456607 2.164156,-3.708624 z" id="path3655-4-8" />
    <path style="fill:url(#radialGradient3714);fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 230.04347,83.261765 c -7.0081,-0.03265 -61.07025,0.289575 -107.66568,0.0654 -17.371,5.108098 -31.704627,13.258827 -39.181777,29.154945 -5.33639,-4.54237 -40.74576,-42.215609 -44.40678,-46.440684 31.38983,-41.648805 74.528017,-45.559321 82.915257,-45.559321 8.38724,0 70.64407,-8.631855 108.33898,62.77966 z" id="path3596" sodipodi:nodetypes="ccccsc" />
    <path style="fill:#699dd3;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 117.12454,243.96815 c -12.49835,-9.45851 -14.5752,-36.93927 1.14635,-57.71356 15.72155,-20.77428 41.03582,-34.94753 53.53417,-25.48904 12.49834,9.4585 7.44792,38.96701 -8.27364,59.74129 -12.01027,15.87024 -35.4911,16.88498 -43.22681,23.69505 -1.23894,-0.0455 -1.95523,-0.0605 -3.18007,-0.23374 z" id="path3655-4" />
    <path style="fill:url(#radialGradient3748);fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 120.3032,244.20103 c 3.58354,-6.02268 28.85859,-52.8991 52.69131,-92.9389 4.41104,-17.56095 5.34663,-33.64185 -4.5584,-48.14993 6.62173,-2.29412 58.23852,-13.976353 63.73684,-14.987686 19.9656,48.180076 1.44992,87.338276 -2.80522,94.565966 -4.25515,7.22768 -28.40179,65.25666 -109.06453,61.51055 z" id="path3596-1" sodipodi:nodetypes="ccccsc" />
    <path style="fill:url(#radialGradient3704);fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 36.696853,69.642524 c 3.46858,6.089612 30.72312,52.780196 53.77852,93.272576 13.094367,12.50527 27.684997,19.48512 45.191737,18.03328 -1.2738,6.89113 -16.62898,57.75037 -18.4638,63.03126 -51.756237,-6.42158 -76.669777,-41.85476 -80.854757,-49.1233 -4.18497,-7.26855 -42.7297502,-56.91452 0.3483,-125.213816 z" id="path3596-1-7" sodipodi:nodetypes="ccccsc" />
    <path transform="matrix(0.77294737,0,0,0.77619098,435.90647,53.275706)" style="fill:url(#linearGradient3653);fill-opacity:1;stroke:url(#linearGradient3809);stroke-width:10.07013607;stroke-miterlimit:4;stroke-opacity:1" d="m -338.44068,101.42373 c 0,32.65032 -26.46832,59.11864 -59.11865,59.11864 -32.65032,0 -59.11864,-26.46832 -59.11864,-59.11864 0,-32.650327 26.46832,-59.118646 59.11864,-59.118646 32.65033,0 59.11865,26.468319 59.11865,59.118646 z" id="path3645" />
    <path style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 163.54619,108.89582 c 18.52979,17.09836 16.03302,29.55794 10.0625,44 -3.10892,-22.25001 -2.34478,-32.42697 -10.0625,-44 z" id="rect3782" />
    <path style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 101.42092,173.63924 c -22.645593,-14.47335 -29.809884,-45.71983 -8.813354,-62.99032 -10.847561,19.77514 -6.225429,32.39863 8.813354,62.99032 z" id="rect3782-4" />
</svg>
</div>

## Vue .NET Core Windows Desktop App Template

The [vue-desktop](https://www.vuedesktop.com) Project Template lets you create .NET Core Vue Single Page Apps 
that can also be packaged & deployed as [Gist Desktop Apps](https://sharpscript.net/sharp-apps/gist-desktop-apps) which is 
ideal for quickly & effortlessly creating & deploying small to medium .NET Core Windows Desktop Apps packaged within a 
Chromium Web Vue UI within minutes!

Create new project with [app dotnet tool](/netcore-windows-desktop):

```bash
$ dotnet tool install -g app
$ app new vue-desktop ProjectName
```

> YouTube: [youtu.be/kRnQSWdqH6U](https://youtu.be/kRnQSWdqH6U)

[![](/img/pages/app/vue-desktop/vuedesktop-screenshot.png)](https://youtu.be/kRnQSWdqH6U)

### Why Chromium Desktop Apps?

With the investment into advancing Web Browsers & Web technologies, many new modern Desktop Apps developed today like: 
Spotify, VS Code, GitHub Desktop, Skype, Slack, Discord, Whats App, Microsoft Teams, etc.
are being built using Web Technologies and rendered with a Chromium webview, using either the popular [Electron Framework](https://www.electronjs.org/) 
or the [Chromium Embedded Framework (CEF)](http://opensource.spotify.com/cefbuilds/index.html) directly.

Following [VS Code frequent releases](https://code.visualstudio.com/updates/) makes it clear why they've decided on 
developing it with Web Technologies using Electron where they've been able to iterate faster and ship new features at 
an unprecedented pace. In addition to its superior productivity, they're able to effortlessly support multiple Operating Systems
as well as enable reuse for running on the Web as done with its [Monaco Editor](https://microsoft.github.io/monaco-editor/)
powering VS Code as well as innovative online solutions like [GitHub Code Spaces](https://github.com/features/codespaces).

These attributes in addition to the amount of investment that major technology companies like Google, Apple, Microsoft & 
Firefox invest each year in improving Web & browser technologies will ensure the platform will be continually supported
& improved unlike most Desktop UI Technologies. 

## Comparison with Blazor WASM

What technology to use for Chromium Desktop Apps?

The latest solution for building Single Page Apps being promoted for .NET is https://blazor.net/ where for Client Apps
suggests to use Blazor WASM which in an overview lets you run C# in the browser by running linked/tree-shaken .dll's in 
[interpreted mode](https://blog.stevensanderson.com/2018/02/06/blazor-intro/#interpreted-mode) by the dotnet runtime 
which is itself compiled & running as WASM. We can see a glimpse of this in action by viewing .dll's being loaded in the 
JS Debug Inspector: 

![](/img/pages/app/vue-desktop/blazor-jsdebug.png)

### Disadvantages of Blazor

The main value proposition of Blazor appears to be running C# in the browser, which while a technically impressive feat,
requires a tonne of complexity to achieve that results in worse end-user UX. It works using a development model based on 
Razor - a technology [we're not fond of](/why-not-razor) due to its reliance on 
heavy/complicated tooling and should be noted that historically whenever .NET invented their own development model
for the Web in ASP.NET Web Forms or Silverlight, they've ended up being abandoned.

Another reason we're not fond of technologies like Blazor is from experience in having to support "crippled" .NET Runtimes 
on platforms where only a subset of functionality of .NET is available, where we've lost untold time & effort trying to 
diagnose & track down runtime issues in Windows Phone, Silverlight & Xamarin iOS due to platform restrictions
([we're already seeing](https://forums.servicestack.net/t/possible-to-allow-setting-of-usecookies-property-in-jsonhttpclient/8618) reported in Blazor), 
differing implementation behavior or .NET libraries heavy use of reflection that's problematic in AOT environments.

Even without the drawbacks, going against the momentum of established Web UI Technologies like [Vue](https://github.com/vuejs/vue) 
& [React](https://github.com/facebook/react), their vibrant communities & [awesome ecosystems](https://github.com/vuejs/awesome-vue)
in favor of an uncertain foreign development model reliant on heavy/complex tooling that only a single vendor can provide 
serving only a single language ecosystem just to be able to use C# in the browser isn't a desirable goal as modern JS/TypeScript 
offer a more productive & enjoyable Reactive UI development model than any C#/XAML UI Framework we've used.

Ultimately as [staunch enemy's of complexity](/service-complexity-and-dto-roles) we're
philosophically against reliance on heavy complicated tooling and instead have adopted a Vue Chromium Desktop approach
for the development of [ServiceStack Studio](/studio) - an App that 
[wouldn't have been feasible](/releases/v5_9#highly-productive-live-reloading-development-experience)
if needing to use any C# & XAML UI FX or WinForms historically used to develop .NET Desktop Apps.  

### Blazor WASM Starting Project Template

But as it's the latest technology developed & promoted by .NET PR it's going to be the Web UI technology compared to most,
so this project template is based on the UI of an empty Blazor WASM project, rewritten to use Vue SPA UI & a back-end 
.NET Core App. It's an enhanced version that also includes examples of commonly useful features: 

  1. [Home page](https://github.com/NetCoreTemplates/vue-desktop/blob/master/src/components/Home.ts) includes example of using 
[TypeScript Service Reference](/typescript-add-servicestack-reference) to consume typed APIs  
  2. [Fetch data page](https://github.com/NetCoreTemplates/vue-desktop/blob/master/src/components/FetchData.ts) sources it's
data from an embedded SQLite database querying an [AutoQuery Service](/autoquery/rdbms)
  3. Utilizes [built-in SVG support](/svg) for using Material Design & Custom SVG Icons 
  4. Utilizes [Win 32 Integration](https://sharpscript.net/sharp-apps/win32) showcasing how to call Win32 APIs from the UI

#### Distributed App Size

The first comparison is a direct result of the approaches used in each technology, where in addition to all your App's 
assets Blazor WASM has to also bundle a dotnet WASM runtime & linked/tree-shaken .dll's. Whilst `app` Desktop Apps
is on opposite side of the spectrum where it only requires distribution of **App-specific functionality** as all popular 
Vue JS libraries, Bootstrap CSS, Material Design SVG icons or ServiceStack .dll's used are pre-bundled with the global `app` dotnet tool.

For the comparison we ran the `publish-app` script & Blazor's **Publish to Folder** tool & compared the **.zip** of each folder which resulted in:

#### `15kb` Vue Desktop App vs `6207kb` Blazor WASM (413x smaller)

The end result that even our **enhanced** Blazor WASM starting project template is **413.8x** or **2.6x** orders of magnitude smaller than Blazor WASM.
A more apt comparison of its tiny footprint, is the enhanced Vue Desktop App is roughly equivalent to 
[Blazor WASM's 12kb partial screenshot of its App](https://docs.microsoft.com/en-us/aspnet/core/blazor/?view=aspnetcore-3.1): 

![](https://docs.microsoft.com/en-us/aspnet/core/blazor/index/_static/dialog.png?view=aspnetcore-3.1)

In addition, the `app` tool also bundles a Chromium Desktop App shell in order for your Vue Desktop Apps to appear like Native Desktop Apps, 
to get the same experience with Blazor WASM App you would also need to manage the installation of a Chromium wrapper like 
[Chromely](https://github.com/chromelyapps/Chromely). 

When App sizes are this small you have a lot more flexibility in how to distribute & manage the App, which is how Vue Desktop Apps
can be published to Gists and always download & open the latest released version - enabling **transparent updates by default**.  

#### Live Reload

A notable omission from a modern UI FX is there doesn't to be any kind of Live Reload capability for any page, including static **.html** or **.css** resources.

Vue Desktop Apps naive live reload feature works as you'd expect where the UI automatically refreshes on each file change, e.g:

![](/img/pages/app/vue-desktop/vuedesktop-livereload.gif)

This is a good example of why we prefer to avoid complex tooling as what's normally a [trivially implementable feature](/hot-reloading) 
requires much more effort & time to implement when you're reliant on a complex architecture & heavy tooling.

The only build tool required to enable Live Reload in Vue Desktop Apps is TypeScript's watch feature which monitors and automatically 
transpiles all `*.ts` file changes: 

```bash
$ tsc -w
```

#### Reload Time

The lack of a live reload feature is exacerbated when having to manually reload your App to view every change which has
noticeable delay in Blazor WASM which is otherwise instant in a normal .NET Core Web App:

#### Blazor WASM
![](/img/pages/app/vue-desktop/blazorwasm-refresh.gif)

#### Vue Desktop
![](/img/pages/app/vue-desktop/vuedesktop-refresh.gif)

### Opinionated App Launcher

The `app` dotnet tool is essentially just a .NET Core Desktop App launcher hosted within a Chromium Desktop Shell, 
whether it's launching our [app Desktop Apps](https://sharpscript.net/sharp-apps/) or existing 
[.NET Core Web App .dll or .exe's](/netcore-windows-desktop#launch-net-core-app-inside-a-windows-chromium-desktop-app).

It's opinionated in the shared libraries it includes, namely:
 - Vue, React & jQuery
 - Bootstrap CSS
 - Material Design & Fontawesome SVG icons
 - [ServiceStack .NET Packages](https://www.nuget.org/profiles/servicestack) & Dependencies

::: info
You can use your own client/server libraries but they'd need to be distributed with the App  
:::

Intended for developing small/medium Desktop Apps that can be published to a GitHub Gist (or repo) & opened over a URL, e,g:
[Redis Admin UI](https://sharpscript.net/sharp-apps/redis), generic [DB Viewer](https://sharpscript.net/sharp-apps/sharpdata)
or our [ServiceStack Studio](/studio) API Management tool which all package down to small footprints. 

Given you can [build & distribute an App within minutes](https://youtu.be/kRnQSWdqH6U), it's suitable for quick UI's around 
a single purpose Task you may want to distribute internally, e.g. a dynamic reporting viewer, edit forms, surveys, email composer, or
see the [Desktop App Index](https://sharpscript.net/sharp-apps/app-index) for other examples.

### FREE!

To remove friction & barriers to adoption all [app](/netcore-windows-desktop) and 
[x](/dotnet-tool) dotnet tools used to run all [Sharp and Gist Desktop Apps](https://sharpscript.net/sharp-apps/) 
utilize an unrestricted suite of [ServiceStack](https://servicestack.net) Software that can be developed & distributed free without a commercial license.

Should it be needed if exceeding [free-quotas](https://servicestack.net/download#free-quotas) (most [Sharp Apps](https://sharpscript.net/) don't) 
when developing locally as a .NET Core Web App (i.e. instead of running using the `app` tool), you can bypass any restrictions 
(from referencing ServiceStack's commercial NuGet packages) with a [Trial License Key](https://servicestack.net/trial).

#### Alternative Modern Desktop Solutions

We don't recommend this template for flagships Desktop App worked on by large teams, in that case you're better off building your own 
custom Chromium Desktop App bundle [as Spotify does](https://engineering.atspotify.com/2019/03/25/building-spotifys-new-web-player/) where
you're able to access full control over CEF APIs, it's rendering, integration and Chromium features.
If you're looking looking to Chromotize a .NET Core Desktop App you can use our [ServiceStack.CefGlue](https://github.com/ServiceStack/ServiceStack.CefGlue)
.NET Standard 2.0 NuGet package of the [CefGlue](https://gitlab.com/xiliumhq/chromiumembedded/cefglue) C# CEF Bindings project.

If you're not using .NET Core, [Electron](https://www.electronjs.org/) is the most likely best choice for building Desktop Apps with Web Technologies.  

If you'd also want to develop native iOS / Android Apps from a shared code-base then [Flutter Desktop](https://medium.com/flutter/flutter-and-desktop-3a0dd0f8353e)
is looking like the most promising technology under active development in that space.

## Overview of Gist Desktop Apps 

Whilst on the face of it [Gist Desktop Apps](https://sharpscript.net/sharp-apps/gist-desktop-apps) appear to be similar to 
Electron Apps that utilizes a .NET Core backend instead of Node.js, it employs a shared architecture where
all Apps are run with the same [app dotnet tool](/netcore-windows-desktop) installable with:

```bash
$ dotnet tool install -g app
```

Where it enables a number of unique features: 

### Ultra Lightweight Desktop Apps

Unlike Electron which bundles Chromium with every install, all [Sharp Desktop Apps](https://sharpscript.net/sharp-apps/) utilize the same 
[app dotnet tool](/netcore-windows-desktop) which in addition to the 
latest version of Chromium, also includes many popular .NET server + client JS/CSS framework libraries - 
saving Vue Desktop Apps from having to include them. This effectively reducing their footprint to just App-specific Server + Client logic, 
so whilst a Hello World Electron App can require **>100MB**, this Vue Desktop Project Template bundles down 
to a **15kb .zip** - which includes the 14kb uncompressed .NET Server **.dll**. 

### Launch Desktop Apps from URLs

Thanks to their light footprint Desktop Apps can be launched directly from URLs using the `app://` URL Scheme, e.g.
a modified version of this Project Template can be launched from:

<h4 id="app-vuedesktop" tabindex="-1"><a href="app://vuedesktop">app://vuedesktop</a> <a class="header-anchor" href="#app-vuedesktop" aria-hidden="true">#</a></h4>

Which uses the unique [global alias your app was published with](https://sharpscript.net/sharp-apps/gist-desktop-apps#publishing-gist-apps). 

### Deep Links

It's also possible to pass additional params to enable deep links into Apps 
[ServiceStack Studio utilizes](/studio#starting-servicestack-studio)
to be able download, run & immediately invoke App specific functionality like connecting to a remote site, e.g:

<h3><a href="app://studio?connect=https://localhost:5001">app://studio?connect=https://localhost:5001</a></h3>

### Create customized Apps by mixing in Gists

Another unique feature of Gist Desktop Apps is being able to mix in multiple files into the App's directory to
create custom App builds, e.g. the [SharpData](https://sharpscript.net/sharp-apps/sharpdata) generic RDBMS UI viewer
utilizes this feature to copy & immediately open an embedded SQLite database for querying: 

<ul>
    <li>
        <a href="app://sharpdata?mix=northwind.sharpdata">app://sharpdata?mix=northwind.sharpdata</a></li><li><a href="app://sharpdata?mix=chinook.sharpdata">app://sharpdata?mix=chinook.sharpdata</a>
    </li>
</ul>

### Launch from public or private GitHub Repos

If preferred Desktop Apps can also be published & launched directly from your GitHub Repo which can be launched with `app://{user}/{repo}`, e.g`:

<ul>
<li><strong><a href="app://sharp-apps/redis">app://sharp-apps/redis</a></strong> - Redis Admin App</li>
<li><strong><a href="app://sharp-apps/blog">app://sharp-apps/blog</a></strong> - SQLite powered Blog App</li>
<li><strong><a href="app://sharp-apps/spirals">app://sharp-apps/spirals</a></strong> - SVG Spirals App</li>
<li><strong><a href="app://sharp-apps/rockwind">app://sharp-apps/rockwind</a></strong> - Multi Layout CMS + DB Admin UI Example</li>
</ul>

> Can open by pasting above links in browsers URL as GitHub doesn't render links with custom URL Schemes

If your repo has published releases it will use your most recent release, otherwise it uses the master archive. 

### Private Repos & Gists

Apps can also be launched from private Gists and Repos by either having end users configure the GitHub Access Token
with access to the private gist or repo in the `GITHUB_TOKEN` Environment variable or can be specified in the URL
or command-line with: 

```bash
app://user/repo?token={GITHUB_TOKEN}
$ app open user/repo -token {GITHUB_TOKEN}
```

### Copy Directory

Another way to distribute & run Apps is to **XCOPY** the `/dist` folder which users can launch by running `app` command in 
the App's folder or by specifying the path to the app's `app.settings`, e.g: 

```bash
$ app C:\path\to\app\app.settings
```

Where you can also [create a Windows Shortcut](/netcore-windows-desktop#create-windows-desktop-shortcuts) 
for a more integrated Desktop App: 

```bash
$ cd C:\path\to\app
$ app shortcut
```

::: info Tip
Add `favicon.ico` to use your own icon in the shortcut
:::

### Cross Platform Support

Whilst the `app` dotnet tool is Windows-only, all Sharp Apps can also be run cross-platform on macOS/Linux with the 
[x dotnet tool](/dotnet-tool) where it will open in the users preferred browser, e.g:

```bash
$ x open vuedesktop 
```

### Always uses latest version

Thanks to their tiny footprints the default behavior is to always download & run the latest version of the App when 
published to a Gist or Repo which automatically happens when launching Apps using the `app://` URL Scheme or `app open` command.

If preferred you can save 1-3 seconds on an App's launch time by using the `app:` URL scheme or `app run` command where
it will instead load the previously downloaded version, e.g:

<h3><a href="app:vuedesktop">app:vuedesktop</a></h3>

```bash
$ app run vuedesktop
```

### Native Win32 API Interop

As [#Script](https://sharpscript.net/) is a scripting language utilizing JS syntax to invoke .NET APIs, the 
[Win 32 support](https://sharpscript.net/sharp-apps/win32) ends up being both simple & intuitive.

Where it calls the [CustomMethods.cs](https://github.com/NetCoreTemplates/vue-desktop/blob/master/CustomMethods.cs) .NET Win 32 APIs
(wrapped in a [#Script method](https://sharpscript.net/docs/methods)) directly from JS as done in 
[App.ts](https://github.com/NetCoreTemplates/vue-desktop/blob/master/src/App.ts) which can be invoked using JS syntax
using the `evaluateCode` TypeScript API, e.g:

```ts
import { evaluateCode } from '@servicestack/desktop';

await evaluateCode(`chooseColor()`);
await evaluateCode(`chooseColor('#336699')`);
```

The `app` dotnet tool already includes these [dotnet/pinvoke](https://github.com/dotnet/pinvoke) .NET Wrapper API NuGet packages
below so they can be used within your App without needing to distribute them with your App:

```xml
<PackageReference Include="PInvoke.AdvApi32" Version="0.6.49" />
<PackageReference Include="PInvoke.BCrypt" Version="0.6.49" />
<PackageReference Include="PInvoke.Crypt32" Version="0.6.49" />
<PackageReference Include="PInvoke.DwmApi" Version="0.6.49" />
<PackageReference Include="PInvoke.Gdi32" Version="0.6.49" />
<PackageReference Include="PInvoke.Hid" Version="0.6.49" />
<PackageReference Include="PInvoke.Kernel32" Version="0.6.49" />
<PackageReference Include="PInvoke.Magnification" Version="0.6.49" />
<PackageReference Include="PInvoke.MSCorEE" Version="0.6.49" />
<PackageReference Include="PInvoke.Msi" Version="0.6.49" />
<PackageReference Include="PInvoke.Fusion" Version="0.6.49" />
<PackageReference Include="PInvoke.NCrypt" Version="0.6.49" />
<PackageReference Include="PInvoke.NetApi32" Version="0.6.49" />
<PackageReference Include="PInvoke.NTDll" Version="0.6.49" />
<PackageReference Include="PInvoke.Psapi" Version="0.6.49" />
<PackageReference Include="PInvoke.SetupApi" Version="0.6.49" />
<PackageReference Include="PInvoke.Shell32" Version="0.6.49" />
<PackageReference Include="PInvoke.SHCore" Version="0.6.49" />
<PackageReference Include="PInvoke.User32" Version="0.6.49" />
<PackageReference Include="PInvoke.Userenv" Version="0.6.49" />
<PackageReference Include="PInvoke.UxTheme" Version="0.6.49" />
<PackageReference Include="PInvoke.WtsApi32" Version="0.6.49" />
```

See [Win32 App](https://sharpscript.net/sharp-apps/win32) for more info & examples on Win32 integration.

## Desktop or Server Deployments

Whilst this project template is intended for creating Desktop Apps, it's essentially just a .NET Core Web App wrapped 
in a shared Chromium Desktop Shell which means it can also be deployed the same as any other .NET Core Web App by
generating a published build:

```bash
$ dotnet publish -c Release
```

Then [copying the published release builds for Server deployments](/netcore-deploy-rsync).

### Development Model

To avoid needing to use webpack, npm or any other build tooling, Vue components are written in TypeScript
[Class-Style Vue Components](https://vuejs.org/v2/guide/typescript.html#Class-Style-Vue-Components)
utilizing annotations in [vue-class-component](https://github.com/vuejs/vue-class-component) & 
[vue-property-decorator](https://github.com/kaorun343/vue-property-decorator), e.g. here's Blazor WASM Counter Page:

```html
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
```

Written as a TypeScript Class-Style Vue Component:

```ts
@Component({ template:`
<div>
    <h1>Counter</h1>
    
    <p>Current count: {{currentCount}}</p>
    
    <button class="btn btn-primary" @click="incrementCount()">Click me</button>
</div>`})
export class Counter extends Vue {
    currentCount = 0;

    incrementCount() {
        this.currentCount++;
    }
}
```

::: info
Vue's integration with TypeScript is set to improve in Vue 3 which will be written in TypeScript
:::

### Typed DTOs

The typing benefits of C# is also available when using TypeScript with 
[type definitions](https://github.com/NetCoreTemplates/vue-desktop/tree/master/typings) available for all libraries
which provides rich intelli-sense & type checking during development. 

Thanks to ServiceStack's [Add TypeScript Reference](/typescript-add-servicestack-reference)
feature, Types are also available for your C# Services which can be updated by running 
[npm run dtos](https://github.com/NetCoreTemplates/vue-desktop/blob/master/package.json#L4) or `app ts` directly, e.g: 

    $ app ts

Which will update all [dtos.ts](https://github.com/NetCoreTemplates/vue-desktop/blob/master/src/shared/dtos.ts) TypeScript
Reference DTOs with the latest changes which can be used together with the [@servicestack/client](https://github.com/ServiceStack/servicestack-client)
generic Service Client to provide both a terse & typed API for consuming back-end end-to-end Typed C# APIs: 

```ts
import { Hello } from "../shared/dtos";
import { client } from "../shared";

@Component({ template:`
<div>
    <h1>Hello, world!</h1>
    Welcome to your new app.
    
    <div class="row mt-4 p-0">
        <div class="col col-3">
            <v-input placeholder="Your name" v-model="txtName" />
        </div>
        <h3 class="col col-5 result mt-2">{{ result }}</h3>
    </div>
</div>`})
export class Home extends Vue {
    public txtName: string = '';
    public result: string = '';

    @Watch('txtName')
    async onNameChanged(value: string, oldValue: string) {
        await this.nameChanged(value);
    }

    async nameChanged(name: string) {
        if (name) {
            const r = await client.get(new Hello({ name }));
            this.result = r.result;
        } else {
            this.result = '';
        }
    }
}
```

### AutoQuery Services

Another major productivity boost for rapidly developing data-driven APIs is [AutoQuery RDBMS](/autoquery/rdbms)
where you can simply **create queryable APIs by just declaratively defining** which fields you want to query using any of the 
[registered conventions](/autoquery/rdbms#implicit-conventions), e.g:

```csharp
[Route("/forecasts")]
[Route("/forecasts/{Id}")]
public class QueryWeatherForecasts : QueryDb<WeatherForecast>
{
    public int? Id { get; set; }
    public DateTime? BeforeDate { get; set; }
    public DateTime? AfterDate { get; set; }
    public int? BelowTemperatureC { get; set; }
    public int? AboveTemperatureC { get; set; }
}

public class WeatherForecast
{
    [AutoIncrement]
    public int Id { get; set; }
    public DateTime Date { get; set; }
    public int TemperatureC { get; set; }
    public string Summary { get; set; }
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
```

Which is all that's required for ServiceStack to automatically implement the Service where it has access to all standard Typed API metadata services 
like being included in the generated TypeScript client DTOs: 

```bash
$ npm run dtos 
```

Which [FetchData.ts](https://github.com/NetCoreTemplates/vue-desktop/blob/master/src/components/FetchData.ts) uses to power its 
dynamic Queryable UI by sending a populated `QueryWeatherForecasts` Request DTO configured with any filters and re-executed 
on every input change:

![](/img/pages/app/vue-desktop/vuedesktop-fetchdata.png)

```html
<form class="form-inline mb-2" @submit.prevent="">
    <label for="txtId">Filters: </label>
    <input class="form-control form-control-sm mx-1" type="number" placeholder="[Id]" v-model="id" @input="filter"> 
    <input type="date" v-model="afterDate" @change="filter">
    <input type="date" v-model="beforeDate" @change="filter">
    <input class="form-control form-control-sm mx-1" type="number" placeholder="Above (C)" v-model="aboveTemp" @input="filter">
    <input class="form-control form-control-sm mr-1" type="number" placeholder="Below (C)" v-model="belowTemp" @input="filter"> 
    <button class="btn btn-secondary btn-sm" @click="reset">reset</button>
</form>
```

Triggering a call to `filter()` to populate and resend the `QueryWeatherForecasts` Request DTO with the latest filters and update the `forecasts` Reactive UI Model: 

```ts
export class FetchData extends Vue {
    forecasts:WeatherForecast[]|null = null;

    id = '';
    beforeDate = '';
    afterDate = '';
    belowTemp = '';
    aboveTemp = '';

    async filter() {
        const request = new QueryWeatherForecasts();
        if (this.id) request.id = parseInt(this.id);
        if (this.beforeDate) request.beforeDate = this.beforeDate;
        if (this.afterDate) request.afterDate = this.afterDate;
        if (this.belowTemp) request.belowTemperatureC = parseInt(this.belowTemp);
        if (this.aboveTemp) request.aboveTemperatureC = parseInt(this.aboveTemp);
        this.forecasts = (await client.get(request)).results;
    }
}
```


### React Desktop Apps Template

[![React Desktop Apps](https://raw.githubusercontent.com/ServiceStack/Assets/master/img/gap/react-desktop-splash.png)](https://github.com/ServiceStackApps/ReactDesktopApps)

The React Desktop Template lets you take advantage the adaptiveness, navigation and deep-linking benefits of a 
Web-based UI, the productivity and responsiveness of the 
[React framework](https://reactjs.org) in a rich 
native experience and OS Integration possible from a Native Desktop App - all in a single VS .NET template which 
supports packaging your Web App into 4 different ASP.NET, Winforms, OSX Cocoa and cross-platform Console App Hosts:

<table class="table">
<tr>
    <th>.NET Framework</th>
    <th>React Desktop Apps Template</th>
</tr>
<tr>
    <td><a href="https://github.com/NetFrameworkTemplates/react-desktop-apps-netfx">react-desktop-apps-netfx</a></td>
    <td align="center">
        <a href="http://react-desktop-apps-netfx.web-templates.io"><img src="https://raw.githubusercontent.com/ServiceStack/Assets/master/csharp-templates/react-desktop-apps-netfx.png" width="500" /></a>
        <p><a href="http://react-desktop-apps-netfx.web-templates.io">react-desktop-apps-netfx.web-templates.io</a></p>
    </td>
</tr>
</table>

## Learn more

To learn more about how Webpack is used in this Template see [Tour of Webpack](/templates/webpack).