ServiceStack v8.2

With ServiceStack now fully integrated with .NET 8, our focus has shifted from providing platform-agnostic solutions that supports all ServiceStack's .NET Framework and .NET hosts to building on the new capabilities of .NET 8 by enhancing ASP .NET Core's built-in features and templates with ServiceStack's high-productivity features.

New Vue SPA Template

The latest Vue SPA template is a good example of this, building on and enhancing the built-in ASP.NET Core Vue SPA template with many high-productivity features.

Vite Vue SPA Template

Explore the high productivity features in the new ServiceStack Vue SPA template

Live Demo

ASP.NET Core Vue SPA Template

The Vue and ASP.NET Core template provides a seamless starting solution which runs both the .NET API backend and Vite Vue frontend during development.

It's a modern template capturing the best Vue has to offer, configured with Vite's fast HMR (Hot Module Reload) and TypeScript support - it allows App's to be developed with Vue's typed Single File Components enabling both a productive development experience and an optimal high-performance production build at runtime.

Minimal API integration

Whilst a great starting point, it's still only a basic template configured with a bare-bones Vue Vite App that's modified to show an example of calling a Minimal API.

Built-in API Integration

Although the approach used isn't very scalable, with a proxy rule needed for every user-defined API route:

export default defineConfig({
    //...
    server: {
        proxy: {
            '^/weatherforecast': {
                target,
                secure: false
            }
        },
    }
})

And the need for hand maintained Types to describe the shape of the API responses with Stringly Typed fetch API calls referencing string routes:

import { defineComponent } from 'vue';

type Forecasts = {
    date: string,
    temperatureC: string,
    temperatureF: string,
    summary: string
}[];

interface Data {
    loading: boolean,
    post: null | Forecasts
}

export default defineComponent({
    data(): Data {
        return {
            loading: false,
            post: null
        };
    },
    created() {
        // fetch the data when the view is created and the data is
        // already being observed
        this.fetchData();
    },
    watch: {
        // call again the method if the route changes
        '$route': 'fetchData'
    },
    methods: {
        fetchData(): void {
            this.post = null;
            this.loading = true;

            fetch('weatherforecast')
                .then(r => r.json())
                .then(json => {
                    this.post = json as Forecasts;
                    this.loading = false;
                    return;
                });
        }
    },
});

Which is used to render the API response in a hand rolled table:

<div v-if="post" class="content">
    <table>
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            <tr v-for="forecast in post" :key="forecast.date">
                <td>{‎{ forecast.date }‎}</td>
                <td>{‎{ forecast.temperatureC }‎}</td>
                <td>{‎{ forecast.temperatureF }‎}</td>
                <td>{‎{ forecast.summary }‎}</td>
            </tr>
        </tbody>
    </table>
</div>

ServiceStack API Integration

Fortunately ServiceStack can significantly improve this development experience with the /api pre-defined route where only a single proxy rule is needed to proxy all APIs:

export default defineConfig({
    //...
    server: {
        proxy: {
            '^/api': {
                target,
                secure: false
            }
        },
    }
})

End-to-end Typed APIs

Instead of hand-rolled types and Stringly Typed API calls, it utilizes server generated TypeScript DTOs with a generic JsonServiceClient to enable end-to-end Typed APIs:

import { ref, onMounted } from 'vue'
import { ApiResult } from "@servicestack/client"
import { useClient } from "@servicestack/vue"
import { GetWeatherForecast } from "@/dtos"

const client = useClient()
const api = ref(new ApiResult())

onMounted(async () => {
    api.value = await client.api(new GetWeatherForecast())
})

This benefits in less code to maintain, immediate static typing analysis to ensure correct usage of APIs and valuable feedback when APIs are changed, that's easily updated with a single command:

npm run dtos

High Productivity Vue Components

With access to the ServiceStack Vue Components library there's also less code to maintain in the UI, where you can render a beautiful tailwind styled DataGrid with just:

<DataGrid :items="api.response" />

ServiceStack Vue SPA Features

Other high-productivity features available in the ServiceStack Vue SPA template include:

Integrated Identity Auth

Pre-configured with ASP.NET Core Identity Auth, including Sign In and Custom Registration APIs and UI Pages which can be customized as needed, examples of Role-based security as well as a turn key solution for Integrating Identity Auth Registration workflow with your SMTP Provider with all emails sent from a managed non-blocking Background MQ for optimal responsiveness and execution.

tailwindcss

Tailwind has quickly become the best modern CSS framework for creating scalable, mobile-first responsive websites built upon a beautiful expert-crafted constraint-based Design System that enables effortless reuse of a growing suite of Free Community and professionally-designed Tailwind UI Component Libraries, invaluable for quickly creating beautiful websites.

Dark Mode

In addition to revolutionizing how we style mobile-first responsive Apps, Tailwind's Dark Mode does the same for enabling Dark Mode a feature supported throughout all of ServiceStack's Vue Component Library.

Built for Productivity

So that you're immediately productive out-of-the-box, the template includes a rich set of high-productivity features, including:

tailwind/typography Beautiful css typography for markdown articles & blog posts
tailwind/forms Beautiful css form & input styles that's easily overridable
Markdown Native Markdown integration
plugin/press Static markdown for creating blogs, videos and other content
plugin/vue-router Conventional file system based routing for Vue 3 on Vite
plugin/layouts Support for multiple page layouts
plugin/components Auto importing & registering of components on-demand
plugin/svg Load SVG files as Vue components
Iconify Unified registry to access 100k+ high quality SVG icons

Bookings CRUD Pages

Bookings CRUD example shows how you can rapidly develop beautiful responsive, customized CRUD UIs with minimal effort using AutoQuery APIs, AutoForms & AutoQueryGrid Vue Components.

Admin Pages

Whilst Bookings CRUD is a good example of creating custom UI for end users, you may also want to quickly develop a set of back-office CRUD Admin UIs to manage your App's Database tables, which is easily achievable AutoQueryGrid's default behavior:

The development UX of Admin Pages is further improved in Vue Vite which is able to use SFC Pages and conventional file system routing to quickly add Admin Pages to manage an App's back-end tables, e.g:

/admin/coupons.vue

<AutoQueryGrid type="Coupon" />

/admin/bookings.vue

<AutoQueryGrid type="Booking"
selected-columns="id,name,roomType,roomNumber,bookingStartDate,cost,couponId,discount"
  :header-titles="{ roomNumber:'Room No', bookingStartDate:'Start Date' }"
   :visible-from="{ roomNumber:'lg', cost:'md', couponId:'xl', discount:'never' }" />

ServiceStack React SPA Template

Just as we've enhanced the built-in ASP.NET Core React SPA template we've also enhanced the built-in ASP.NET Core React SPA template with the new TypeScript Vite React SPA template with many new high-productivity features.

Vite React SPA Template

Explore the high productivity features in the new ServiceStack React SPA template

Live Demo

ASP.NET Core React SPA Template

The React and ASP.NET Core like the Vue template is a good minimal starting point with great Vite integration and the same shortcomings using Stringly Typed HTTP API calls and hand maintained Types:

interface Forecast {
    date: string;
    temperatureC: number;
    temperatureF: number;
    summary: string;
}

function App() {
    const [forecasts, setForecasts] = useState<Forecast[]>();

    useEffect(() => {
        populateWeatherData();
    }, []);
    //...
}

async function populateWeatherData() {
    const response = await fetch('weatherforecast');
    const data = await response.json();
    setForecasts(data);
}

and uses a hand rolled table to render the API response in:

function App() {
    //...
    const contents = forecasts === undefined
        ? <p><em>Loading... Please refresh once the ASP.NET backend has started. See 
            <a href="https://aka.ms/jspsintegrationreact">jsps</a> for more details.
            </em></p>
        : <table className="table table-striped" aria-labelledby="tabelLabel">
            <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
            </thead>
            <tbody>
                {forecasts.map(forecast =>
                    <tr key={forecast.date}>
                        <td>{forecast.date}</td>
                        <td>{forecast.temperatureC}</td>
                        <td>{forecast.temperatureF}</td>
                        <td>{forecast.summary}</td>
                    </tr>
                )}
            </tbody>
        </table>;
}

ServiceStack API Integration

Instead of hand-rolled types and Stringly Typed API calls, the new React SPA template utilizes server generated TypeScript DTOs with a generic JsonServiceClient to enable end-to-end Typed APIs:

import { useState, useEffect } from "react"
import { useClient } from "@/gateway"
import { GetWeatherForecast } from "@/dtos"

const client = useClient()
const [forecasts, setForecasts] = useState<Forecast[]>([])

useEffect(() => {
    (async () => {
        const api = await client.api(new GetWeatherForecast())
        if (api.succeeded) {
            setForecasts(api.response!)
        }
    })()
}, [])

React Component Ecosystem

Given it's popularity, React has arguably the richest ecosystem of freely available libraries and components, a good example are the popular shadcn/ui Tailwind components. Unlike most libraries they're source copied piecemeal into your project where they're locally modifiable, i.e. instead of an immutable package reference.

As they're just blueprints, they're not dependent on a single library and will utilize the best library to implement each component if needed. E.g. the Data Table component documents how to implement your own Data Table utilizing the headless TanStack Table - a version of which we've built into DataTable.tsx which is used in the template to implement both complex CRUD UIs and weather.tsx simple table results:

import { columnDefs, DataTable, getCoreRowModel } from "@/components/DataTable.tsx"

const columns = columnDefs(['date', 'temperatureC', 'temperatureF', 'summary'],
  ({ temperatureC, temperatureF}) => {
    temperatureC.header = "Temp. (C)"
    temperatureF.header = "Temp. (F)"
    temperatureC.cell = temperatureF.cell = ({ getValue }) => <>{getValue()}&deg;</>
  })

return (<LayoutPage title="Weather">
  <DataTable columns={columns} data={forecasts} getCoreRowModel={getCoreRowModel()} />
</LayoutPage>)

To render the /weather customized Data Table:

The template also includes customizable Form.tsx Input components which can be used to create beautiful validation-bound forms which effortlessly integrates with ServiceStack's Error Handling and Declarative Validation attributes.

ServiceStack React SPA Features

Other high-productivity features available in the ServiceStack React SPA template include:

Integrated Identity Auth

Pre-configured with ASP.NET Core Identity Auth, including Sign In and Custom Registration APIs and UI Pages which can be customized as needed, examples of Role-based security as well as a turn key solution for Integrating Identity Auth Registration workflow with your SMTP Provider with all emails sent from a managed non-blocking Background MQ for optimal responsiveness and execution.

tailwindcss with Dark Mode

In addition to revolutionizing how we style mobile-first responsive Apps, Tailwind's Dark Mode does the same for enabling Dark Mode a feature supported throughout the template and its Tailwind UI Components.

Built for Productivity

So that you're immediately productive out-of-the-box, the template includes a rich set of high-productivity features, including:

tailwind/typography Beautiful css typography for markdown articles & blog posts
tailwind/forms Beautiful css form & input styles that's easily overridable
Markdown Native mdx Markdown integration
React Router Full featured routing library for React
plugin/press Static markdown for creating blogs, videos and other content
plugin/pages Conventional file system based routing for Vite
plugin/svg Load SVG files as React components
Iconify Unified registry to access 100k+ high quality SVG icons

Bookings CRUD Pages

The Bookings CRUD example shows how you can utilize a customized Data Table and templates Form components to create a beautifully styled CRUD UI with minimal effort.

Vite Press Plugin

The Vite Press Plugin is an alternative to VitePress for adding Markdown features to existing Vite Vue or React projects. It's a non-intrusive plugin for Vue and React Vite apps that want to add markdown powered content features without needing to adopt an opinionated framework for their entire App.

Universal Markdown Features

A goal for vite-press-plugin is to implement a suite of universal markdown-powered features that can be reused across Vue, React and .NET Razor and Blazor projects, allowing you to incorporate same set of markdown feature folders to power markdown content features across a range of websites built with different technologies.

Vite Apps with vite-press-plugin

The vite-press-plugin currently powers the markdown features in the static Vite Vue and React templates which are ideal for creating static websites, blogs, documentation and marketing websites that can be hosted FREE on GitHub Pages CDN:

Static Vite Templates with vite-press-plugin

Vite Vue Static SPA Template

Vite React Static SPA Template

The vite-press-plugin makes the Markdown features available to the Vite App, whilst the markdown rendering itself is optimally implemented in:

.NET 8 API backend with Vite Vue & React SPA frontend

When more capabilities are required and you want a .NET API backend to your Vite Vue or React SPA frontend, you can use one of our integrated .NET 8 SPA templates:

  • vue-spa - .NET 8 API with Vite Vue SPA frontend
  • react-spa - .NET 8 API with Vite React SPA frontend

.NET Templates with C# and Markdig

Whilst the same Markdown feature folders are implemented in C# and rendered with Markdig and either Razor Pages or Blazor Components:

.NET 8 Razor SSG and Blazor SSR Templates

  • razor-ssg - .NET Razor SSG Blog and Marketing Website with Markdig
  • razor-press - .NET Razor SSG Documentation Website with Markdig
  • blazor-vue - .NET 8 Blazor Server Rendered Website with Markdig

Markdown Feature Folders

The content for each Markdown feature is maintained within its own feature folder with a _ prefix:

_includes
_posts
_videos
_whatsnew

Markdown Document Structure

Additional metadata for each markdown page is maintained in the frontmatter of each markdown page, e.g. the front matter for this blog post contains:

---
title:   Vite Press Plugin
summary: Introducing the Vite Press Plugin
author:  Lucy Bates
tags:    [docs,markdown]
image:   https://source.unsplash.com/random/2000x1000/?stationary
---

The frontmatter is used in combination with file attributes to populate the document metadata. The schema used to support the current markdown features include:

type Doc = {
    title: string     // title of Markdown page (frontmatter)
    slug: string      // slug to page (populated)
    path: string      // path to page (populated)
    fileName: string  // filename of markdown file (populated)
    content: string   // markdown content (populated)
    date: string      // date of page (frontmatter)
    tags: string[]    // related tags (frontmatter)
    order?: number    // explicit page ordering (frontmatter)
    group?: string    // which group page belongs to (populated)
    draft?: boolean   // make visible in production (frontmatter)
    wordCount: number      // (populated)
    lineCount: number      // (populated)
    minutesToRead: number  // (populated)
}

type Post = Doc & {
    summary: string // short summary of blog post (frontmatter)
    author: string  // author of blog post (frontmatter)
    image: string   // hero image of blog post (frontmatter)
}

type Video = Doc & {
    url: string // URL of YouTube Video
}

type WhatsNew = Doc & {
    url: string    // URL of YouTube Video
    image: string  // Image to display for feature
}

Markdown files can contain additional frontmatter which is also merged with the document metadata.

Accessing Markdown Metadata

In Vue App's the Metadata is available as an injected dependency that's navigable with the typed VirtualPress schema, e.g:

import type { VirtualPress } from "vite-plugin-press"

const press:VirtualPress = inject('press')!

In React App's it's available via an injected context:

import { PressContext } from "@/contexts"

const press = useContext(PressContext)

Which is defined as:

import { createContext } from 'react'
import type { VirtualPress } from 'vite-plugin-press'

export const PressContext = createContext<VirtualPress>({} as VirtualPress)

This VirtualPress metadata is used to power all markdown features.

Blog

The blog maintains its markdown posts in a flat /_posts folder which each Markdown post containing its publish date and URL slug it should be published under, e.g:

_posts
2023-01-21_start.md
2024-02-11_jwt-identity-auth.md
2024-03-01_vite-press-plugin.md

Supporting all Blog features requires several different pages to render each of its view:

Description Example Vue React
Main Blog layout /blog blog.vue blog.tsx
Navigable Archive of Posts /posts index.vue index.tsx
Individual Blog Post (like this!) /posts/vite-press-plugin [slug].vue [slug].tsx
Display Posts by Author /posts/author/lucy-bates [name].vue [name].tsx
Display Posts by Tag /posts/tagged/markdown [tag].vue [tag].tsx
Display Posts by Year /posts/year/2024 [year].vue [year].tsx

Configuration

Additional information about the Website Blog is maintained in _posts/config.json

{
  "localBaseUrl": "http://localhost:5173",
  "publicBaseUrl": "https://press-vue.servicestack.net",
  "siteTwitter": "@Vue",
  "blogTitle": "From the blog",
  "blogDescription": "Writing on software design and aerospace industry.",
  "blogEmail": "email@example.org (Vue)",
  "blogImageUrl": "https://servicestack.net/img/logo.png"
}

Authors

Whilst information about Post Authors are maintained in _posts/authors.json

[
  {
    "name": "Lucy Bates",
    "email": "lucy@email.org",
    "bio": "Writing on software design and aerospace industry.",
    "profileUrl": "/img/profiles/user1.svg",
    "twitterUrl": "https://twitter.com/lucy",
    "threadsUrl": "https://threads.net/@lucy",
    "gitHubUrl": "https://github.com/lucy"
  },
]

To associate an Author the name property is used to match a posts frontmatter author.

General Features

Most unique markdown features are captured in their Markdown's frontmatter metadata, but in general these features are broadly available for all features:

  • Live Reload - Latest Markdown content is displayed during Development
  • Drafts - Prevent posts being worked on from being published with draft: true
  • Future Dates - Posts with a future date wont be published until that date

What's New Feature

The /whatsnew page is an example of creating a custom Markdown feature to implement a portfolio or a product releases page where a new folder is created per release, containing both release date and release or project name, with all features in that release maintained markdown content sorted in alphabetical order:

_whatsnew
2023-03-08_Animaginary
feature1.md
2023-03-18_OpenShuttle
feature1.md
2023-03-28_Planetaria
feature1.md

What's New follows the same structure as Pages feature which is rendered in:

Videos Feature

The videos feature maintained in the _videos folder allows grouping of related videos into different folder groups, e.g:

_videos
vue
admin.md
autoquerygrid.md
components.md
react
locode.md
bookings.md
nextjs.md

These can then be rendered as UI fragments using the <VideoGroup> component, e.g:

<VideoGroup
  title="Vue Components"
  summary="Learn about productive features in Vue Component Library"
  group="vue"
  learnMore="https://docs.servicestack.net/vue/" />

Includes Feature

The includes feature allows maintaining reusable markdown fragments in the _includes folder, e.g:

_includes
features
videos.md
whatsnew.md
privacy.md

Which can be included in other Markdown files with:

:::include privacy.md:::

:::include features/include.md:::

Alternatively they can be included in other Vue, React or Markdown pages with the <Include> component, e.g:

<Include src="privacy.md" />

<Include src="features/include.md" />

Metadata APIs Feature

To support external clients from querying static markdown metadata you can export it to pre-rendered static *.json data structures by configuring metadataPath to the location you the *.json files published to, e.g:

export default defineConfig({
    plugins: [
        Press({
            metadataPath: 'public/api',
        }),
    ]
})

This will publish all the content of each content type in the year they were published in, along with an all.json containing all content published in that year as well aso for all time, e.g:

meta
2022
all.json
posts.json
videos.json
2023
all.json
posts.json
2024
all.json
posts.json
videos.json
whatsnew.json
all.json
index.json

With this you can fetch the metadata of all the new Blog Posts added in 2023 from:

/api/2024/blog.json

Or all the website content added in 2024 from:

/api/2024/all.json

Or ALL the website metadata content from:

/api/all.json

This feature makes it possible to support use-cases like CreatorKit's Generating Newsletters feature which generates a Monthly Newsletter Email with all new content added within a specified period.

Markdown Containers

Most of VitePress Containers are also implemented, enabling rich markup to enhance markdown content and documentation universally across all Markdown App implementations:

Input

:::info
This is an info box.
:::

:::tip
This is a tip.
:::

:::warning
This is a warning.
:::

:::danger
This is a dangerous warning.
:::

Output

INFO

This is an info box.

TIP

This is a tip.

WARNING

This is a warning.

DANGER

This is a dangerous warning.

Custom Title

You can specify a custom title by appending the text right after the container type:

Input

:::danger STOP
Danger zone, do not proceed
:::

Output

STOP

Danger zone, do not proceed

copy

The copy container is ideal for displaying text snippets in a component that allows for easy copying:

Input

:::copy
Copy Me!
:::

Output

Copy Me!

HTML or XML fragments can also be copied by escaping them first:

Input

:::copy
`<PackageReference Include="ServiceStack" Version="8.*" />`
:::

Output

<PackageReference Include="ServiceStack" Version="8.*" />

sh

Similarly the sh container is ideal for displaying and copying shell commands:

Input

:::sh
npm run dev
:::

Output

npm run dev

YouTube

For embedding YouTube Videos, optimally rendered using the <LiteYouTube> component, e.g:

Input

:::youtube YIa0w6whe2U
Vue Components Library
:::

Output

Markdown Fenced Code Blocks

For more flexibility you can utilize custom fenced components like the files fenced code block which can be used to capture ascii representation of a structured documentation like a folder & file structure, e.g:

```files
/_videos
  /vue
    admin.md
    autoquerygrid.md
    components.md
  /react
    locode.md
    bookings.md
    nextjs.md
```

That we can render into a more UX-friendly representation by calling the Files component with the body of the code-block to convert the structured ascii layout into a more familiar GUI layout:

_videos
vue
admin.md
autoquerygrid.md
components.md
react
locode.md
bookings.md
nextjs.md

The benefit of this approach of marking up documentation is that the markdown content still remains in an optimal human-readable form even when the markdown renderer lacks the custom fenced components to render the richer UI.

Components In Markdown

Up till now all above features will let you render the same markdown content in all available Vue, React, Razor or Blazor templates. At the cost of reduced portability, you're also able to embed rich Interactive Vue or React components directly in markdown.

Kotlin Compose Multiplatform

The last few years of neglect of Xamarin has slid it into irrelevance, removing itself from consideration in the already shortlist of viable development options for creating native multi-platform iOS, Android and Desktop Apps, which leaves us just Flutter and React Native as the only viable options.

Thanks to the vast language ecosystem covered by Add ServiceStack Reference, which ever technology you end up choosing to develop native Mobile and Desktop Apps with, you'll always be able to develop with the productivity and type safety benefits of end-to-end typed APIs in your preferred language, whether it's TypeScript or JavaScript for React Native, Dart for Flutter, Java or Kotlin for Android, or Swift for iOS.

Fortunately JetBrains has stepped in to fill the void with Compose Multiplatform offering a modern alternative for creating native Mobile, Desktop & Web Apps which can also leverage Kotlin ServiceStack Reference for end-to-end typed APIs.

Compose Multiplatform builds on Jetpack Compose - Google's modern toolkit for building native Android UIs bringing it to more platforms, including Windows, macOS and Linux Desktops, Web UIs with Kotlin Wasm and on iOS with Kotlin/Native.

We'll look at the latest Compose Multiplatform v1.6 Release and use it to build a cross-platform Desktop App integrated with a .NET API backend utilizing Kotlin ServiceStack Reference to generate Kotlin DTOs that can be used with the generic ServiceStack Java JsonServiceClient to enable its end-to-end typed API integration.

JVM Platform Required

Whilst Compose Multiplatform supports both JVM and non-JVM platforms, targeting a non JVM platform is very limited as you won't be able to reference and use any Java packages like ServiceStack's Java Client library in net.servicestack:client which is required for this example utilizing Kotlin ServiceStack Reference typed Kotlin DTOs.

Compose Multiplatform iOS & Android Apps

The quickest way to a working Compose Multiplatform App integrated with a .NET API backend is to create a new project from the Compose Desktop template:

Create a new Compose Desktop App

Create a new Kotlin Multiplatform App with your preferred project name:

Or install from the command-line with the x dotnet tool:

x new kmp-desktop MyApp

Install JetBrains IDE

As a JetBrains technology, you're spoilt for choice for which IDE to use.

Android Studio

If you're primarily developing for Android, Android Studio is likely the the best option, which you can setup by following their Getting Started with Android Studio guide.

JetBrains Fleet

Otherwise if you're primarily developing a Desktop App it's recommended to use Fleet - JetBrains alternative to VS Code as a lightweight IDE for Kotlin Multiplatform Development. It's the preferred IDE when developing against a .NET API as you can develop both Kotlin front-end UI and backend .NET APIs from a single IDE.

To get setup with Fleet, follow the Getting Started with JetBrains Fleet.

Open Project with Fleet

Once you've installed Fleet, you can open your Desktop App project by opening the Folder in the Fleet IDE, or like VS Code you can launch it to open your Project's folder from the command-line with:

fleet MyApp

Setup Fleet

When first opening fleet you'll start with an empty canvas. I'd recommend adding the Files tool window on the left panel to manage the Kotlin UI and the Solution tool window on the bottom left panel to manage the .NET API backend.

Run .NET API and Kotlin Desktop App

Once setup, you can run both the Desktop App and the .NET API backend with from the Run Dialog with the Ctrl+R keyboard shortcut, or by clicking on the play button icon in the top menu bar:

You'll want to run the .NET API backend first by selecting your Project Name which should launch your browser at https://localhost:5001, then launch the Desktop App by selecting the composeApp [Desktop] configuration which should launch a working Desktop App that calls your .NET API on each keystroke to search for matching files in your project:

Majority of the UI is maintained in /commonMain/kotlin/App.kt created using Jetpack Compose's declarative Kotlin UI.

Update Kotlin DTOs

The typed Kotlin DTOs for your .NET APIs is generated in dtos.kt. Which can be regenerated by running Update DTOs in the Run Dialog.

Alternatively they can also be regenerated by running the dtos npm script from the command-line in your .NET Host project:

npm run dtos

Android Studio

If you're using Android Studio, you can also install the ServiceStack Plugin from the JetBrains Marketplace:

Which provides a Add ServiceStack Reference UI on the Context Menu, by right-clicking the folder where you want the DTOs generated:

Then to update just right-click the dtos.kt and click Update ServiceStack Reference on the context menu:

Command Line

For any other Text Editors or IDEs a Kotlin ServiceStack Reference can also be added from the command-line using the x dotnet tool by specifying the BaseUrl where the ServiceStack APIs are hosted, e.g:

x kotlin https://localhost:5001

To update and regenerate all Kotlin DTOs within a folder, run:

x kotlin

Create a new Kotlin Multiplatform App from Scratch

For a customized Compose Multiplatform App, you can create a new App with Kotlin Multiplatform Wizard with just the options you need:

Which you can download in an empty Web Project:

x new web MyApp

Then open the folder with both the Kotlin Multiplatform and .NET Web App in fleet:

fleet MyApp