Skip to content

Instantly share code, notes, and snippets.

@gistlyn
Last active November 22, 2023 03:35
Show Gist options
  • Save gistlyn/8026c4c2a7202b99885539109145e12b to your computer and use it in GitHub Desktop.
Save gistlyn/8026c4c2a7202b99885539109145e12b to your computer and use it in GitHub Desktop.
Empty .NET 6 ServiceStack App
using Funq;
using ServiceStack;
using MyApp.ServiceInterface;
[assembly: HostingStartup(typeof(MyApp.AppHost))]
namespace MyApp;
public class AppHost : AppHostBase, IHostingStartup
{
public void Configure(IWebHostBuilder builder) => builder
.ConfigureServices(services => {
// Configure ASP.NET Core IOC Dependencies
});
public AppHost() : base("MyApp", typeof(MyServices).Assembly) {}
public override void Configure(Container container)
{
// Configure ServiceStack only IOC, Config & Plugins
SetConfig(new HostConfig {
UseSameSiteCookies = true,
});
}
}
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Using Include="MyApp" />
<Using Include="ServiceStack" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ServiceStack" Version="8.*" />
</ItemGroup>
</Project>
{
"scripts": {
"dtos": "x mjs"
}
}
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
app.UseHttpsRedirection();
}
app.UseServiceStack(new AppHost());
app.Run();
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "https://localhost:5001/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"MyApp": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001/"
}
}
}
using System;
using ServiceStack;
using MyApp.ServiceModel;
namespace MyApp.ServiceInterface
{
public class MyServices : Service
{
public object Any(Hello request)
{
return new HelloResponse { Result = $"Hello, {request.Name}!" };
}
}
}
using ServiceStack;
namespace MyApp.ServiceModel
{
[Route("/hello")]
[Route("/hello/{Name}")]
public class Hello : IReturn<HelloResponse>
{
public string? Name { get; set; }
}
public class HelloResponse
{
public string? Result { get; set; }
}
}
<html>
<head>
<title>My App</title>
<style>
body { padding: 1em 1em 5em 1em; }
body, input[type=text] { font: 20px/28px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif }
input { padding:.25em .5em; margin-right:.5em; }
a { color:#007bff; text-decoration:none }
a:hover { text-decoration:underline }
#result { display:inline-block; color:#28a745; font-size:28px }
pre { border-radius:10px; overflow:hidden }
h2, h3, strong { font-weight:500 }
</style>
<link rel="stylesheet" href="https://unpkg.com/@highlightjs/[email protected]/styles/atom-one-dark.min.css">
<script async src="https://ga.jspm.io/npm:[email protected]/dist/es-module-shims.js"></script><!--safari polyfill-->
<script type="importmap">
{
"imports": {
"@servicestack/client": "https://unpkg.com/@servicestack/client@2/dist/servicestack-client.min.mjs"
}
}
</script>
</head>
<body>
<h2><a href="/ui/Hello">Hello</a> API</h2>
<input type="text" id="txtName">
<div id="result"></div>
<script type="module">
import { JsonApiClient, $1, on } from '@servicestack/client'
import { Hello } from '/types/mjs'
const client = JsonApiClient.create()
on('#txtName', {
/** @param {Event} el */
async keyup(el) {
const api = await client.api(new Hello({ name:el.target.value }))
$1('#result').innerHTML = api.response.result
}
})
$1('#txtName').value = 'World'
$1('#txtName').dispatchEvent(new KeyboardEvent('keyup'))
</script>
<div id="content" style="max-width:105ch"></div>
<template id="docs">
## View in API Explorer
- [Call API](/ui/Hello)
- [View API Details](/ui/Hello?tab=details)
- [Browse API source code in different langauges](/ui/Hello?tab=code)
### Using JsonServiceClient in Web Pages
Easiest way to call APIs is to use [@servicestack/client](https://docs.servicestack.net/javascript-client) with
the built-in [/types/mjs](/types/mjs) which returns your APIs in annotated typed ES6 class DTOs where it can be
referenced directly from a [JavaScript Module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules).
We recommend using an [importmap](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap)
to specify where to load **@servicestack/client** from, e.g:
```html
&lt;script type="importmap"&gt;
{
"imports": {
"@servicestack/client":"https://unpkg.com/@servicestack/client@2/dist/servicestack-client.mjs"
}
}
&lt;/script&gt;
```
This lets us reference the **@servicestack/client** package name in our source code instead of its physical location:
```html
&lt;input type="text" id="txtName"&gt;
&lt;div id="result"&gt;&lt;/div&gt;
```
```html
&lt;script type="module"&gt;
import { JsonApiClient, $1, on } from '@servicestack/client'
import { Hello } from '/types/mjs'
const client = JsonApiClient.create()
on('#txtName', {
async keyup(el) {
const api = await client.api(new Hello({ name:el.target.value }))
$1('#result').innerHTML = api.response.result
}
})
&lt;/script&gt;
```
### Enable static analysis and intelli-sense
For better IDE intelli-sense during development, save the annotated Typed DTOs to disk with the [x dotnet tool](https://docs.servicestack.net/dotnet-tool):
```bash
$ x mjs
```
Then reference it instead to enable IDE static analysis when calling Typed APIs from JavaScript:
```js
import { Hello } from '/js/dtos.mjs'
client.api(new Hello({ name }))
```
To also enable static analysis for **@servicestack/client**, install the dependency-free library as a dev dependency:
```bash
$ npm install -D @servicestack/client
```
Where only its TypeScript definitions are used by the IDE during development to enable its type-checking and intelli-sense.
</template>
<script src="https://unpkg.com/@highlightjs/[email protected]/highlight.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
function decode(html) {
const txt = document.createElement("textarea")
txt.innerHTML = html
return txt.value
}
document.querySelector('#content').innerHTML = marked.parse(decode(document.querySelector('#docs').innerHTML))
hljs.highlightAll()
</script>
</div>
</body>
</html>
/* Options:
Date: 2023-02-09 18:15:17
Version: 6.60
Tip: To override a DTO option, remove "//" prefix before updating
BaseUrl: https://localhost:5001
//AddServiceStackTypes: True
//AddDocAnnotations: True
//AddDescriptionAsComments: True
//IncludeTypes:
//ExcludeTypes:
//DefaultImports:
*/
"use strict";
export class HelloResponse {
/** @param {{result?:string}} [init] */
constructor(init) { Object.assign(this, init) }
/** @type {?string} */
result;
}
export class Hello {
/** @param {{name?:string}} [init] */
constructor(init) { Object.assign(this, init) }
/** @type {?string} */
name;
getTypeName() { return 'Hello' }
getMethod() { return 'POST' }
createResponse() { return new HelloResponse() }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment