Our x
and app
dotnet tools are a versatile invaluable companion for all ServiceStack developers where it's
jam packed with functionality to power a number of exciting scenarios where it serves as a Sharp App
delivery platform where they can be run as a .NET Core Windows Desktop App with app
or as a cross-platform Web App launcher
using web
and we've already how it's now a #Script
runner with x run
and into a
Live #Script
playground with x watch
.
These tools contains all the functionality ServiceStack Developers or API consumers need that can be used Create ServiceStack projects, run Gist Desktop Apps or generate typed endpoints for consuming ServiceStack Services by either Add/Update ServiceStack References or by generating gRPC client proxies.
Install​
To access available features, install with:
dotnet tool install --global x
Update​
Or if you had a previous version installed, update with:
dotnet tool update -g x
INFO
Both x
and app
have equivalent base functionality, whilst app
has superset features for richer Windows-only integration
Usage​
Then run x
without any arguments to view Usage:
x
Usage:
x new List available Project Templates
x new <template> <name> Create New Project From Template
x download <user>/<repo> Download latest GitHub Repo Release
x get <url> Download URL to file (-out <file|dir>)
x stream <url> Stream URL contents to console stdout
x mix Show available gists to mixin (Alias '+')
x mix <name> Write gist files locally, e.g: (Alias +init)
x mix init Create empty .NET Core ServiceStack App
x mix [tag] Search available gists
x mix <gist-url> Write all Gist text files to current directory
x gist <gist-id> Write all Gist text files to current directory
x publish Publish Current Directory to Gist (requires token)
x gist-new <dir> Create new Gist with Directory Files (requires token)
x gist-update <id> <dir> Update Gist ID with Directory Files (requires token)
x gist-open <gist> Download and open Gist folder (-out <dir>)
x <lang> Update all ServiceStack References in directory (recursive)
x <file> Update existing ServiceStack Reference (e.g. dtos.cs)
x <lang> <url> <file> Add ServiceStack Reference and save to file name
x csharp <url> Add C# ServiceStack Reference (Alias 'cs')
x typescript <url> Add TypeScript ServiceStack Reference (Alias 'ts')
x swift <url> Add Swift ServiceStack Reference (Alias 'sw')
x java <url> Add Java ServiceStack Reference (Alias 'ja')
x kotlin <url> Add Kotlin ServiceStack Reference (Alias 'kt')
x dart <url> Add Dart ServiceStack Reference (Alias 'da')
x fsharp <url> Add F# ServiceStack Reference (Alias 'fs')
x vbnet <url> Add VB.NET ServiceStack Reference (Alias 'vb')
x tsd <url> Add TypeScript Definition ServiceStack Reference
x proto <url> Add gRPC .proto ServiceStack Reference
x proto <url> <name> Add gRPC .proto and save to <name>.services.proto
x proto Update all gRPC *.services.proto ServiceStack References
x proto-langs Display list of gRPC supported languages
x proto-<lang> <url> Add gRPC .proto and generate language (-out <dir>)
x proto-<lang> <file|dir> Update gRPC .proto and re-gen language (-out <dir>)
x proto-<lang> Update all gRPC .proto's and re-gen lang (-out <dir>)
x open List of available Sharp Apps
x open <app> Install and run Sharp App
x run Run Sharp App in current directory
x run <name> Run Installed Sharp App
x run path/app.settings Run Sharp App at directory containing specified app.settings
x install List available Sharp Apps to install (Alias 'l')
x install <app> Install Sharp App (Alias 'i')
x uninstall List Installed Sharp Apps
x uninstall <app> Uninstall Sharp App
x alias Show all local gist aliases (for usage in mix or app's)
x alias <alias> Print local alias value
x alias <alias> <gist-id> Set local alias with Gist Id or Gist URL
x unalias <alias> Remove local alias
x shortcut Create Shortcut for Sharp App
x shortcut <name>.dll Create Shortcut for .NET Core App
x scripts List all available package.json scripts
x scripts <name> Run package.json script
x run <name>.ss Run #Script within context of AppHost (or <name>.html)
x watch <name>.ss Watch #Script within context of AppHost (or <name>.html)
Language File Extensions:
.ss - #Script source file
.sc - #Script `code` source file
.l - #Script `lisp` source file
x lisp Start Lisp REPL
dotnet tool update -g x Update to latest version
Options:
-h, --help, ? Print this message
-v, --version Print this version
-d, --debug Run in Debug mode for Development
-r, --release Run in Release mode for Production
-s, --source Change GitHub Source for App Directory
-f, --force Quiet mode, always approve, never prompt (Alias 'y')
-e, --eval Evaluate #Script Code
--token Use GitHub Auth Token
--clean Delete downloaded caches
--verbose Display verbose logging
--ignore-ssl-errors Ignore SSL Errors
Add/Update ServiceStack References​
This shows us we can Add a ServiceStack Reference with x <lang> <baseurl>
which will let us create a TypeScript Reference
to the new World Validation App using its ts
file extension alias:
Output:
Saved to: dtos.ts
Or create a C# ServiceStack Reference with:
Output:
Saved to: dtos.cs
To update run x <lang>
which will recursively update all existing ServiceStack References:
x ts
Output:
Updated: dtos.ts
Integrate with Visual Studio​
You can also easily integrate this within your VS.NET dev workflows by adding it as an External Tool in the External Tools dialog box by choosing Tools > External Tools
:
Title | Update TypeScript &Reference |
Command | web.exe |
Arguments | ts |
Initial directory | $(ProjectDir) |
Which will then let you update all your *dtos.ts
TypeScript References in your project by clicking on Tools > Update TypeScript Reference
or using the ALT+T R
keyboard shortcut.
If you wanted to Update your *dtos.cs
C# ServiceStack References instead, just change Arguments to cs
:
Title | Update C# &Reference |
Command | web.exe |
Arguments | cs |
Initial directory | $(ProjectDir) |
Refer to the x usage output above for the arguments or aliases for all other supported languages.
Integrate with Rider​
Just like with VS.NET above you can add an External Tool
in JetBrains Rider by opening the Settings dialog with CTRL+ALT+S
then searching for external tools
under the Tools category:
Name | Update TypeScript Reference |
Command | web.exe |
Arguments | ts |
Working directory | \(FileParentDir\) |
Now you can update your *dtos.ts
TypeScript References in your project by clicking on External Tools > Update TypeScript Reference
in the right-click context menu:
If you're updating references frequently you can save time by assigning it a keyboard shortcut.
Create new Project Templates​
See x new for available Project Templates you can create with:
x new
Mix Features into existing ASP.NET Core Apps​
The x
dotnet tool is a versatile utility belt packed with a number of features to simplify discovering, installing, running and deploying
.NET Core Apps. You can view the full list of supported commands by running x ?
, e.g. another useful command is using x mix
for generating pre-set templates:
x mix Show available gists to mixin (Alias '+')
x mix <name> Write gist files locally, e.g: (Alias +init)
x mix init Create empty .NET Core ServiceStack App
x mix [tag] Search available gists
x gist <gist-id> Write all Gist text files to current directory
View available gists with:
x mix
Where you can use x mix nginx
to generate a common nginx template configuration for reverse proxying .NET Core Apps, making configuring
Linux deployment servers for your .NET Core Apps less tedious.
In addition to the pre-set templates, you can create your own public GitHub gist with any number of different files customized for your Environment that anyone can write to their current directory with the gist id or gist URL:
x gist <gist-id>
Patch JSON files​
The x
dotnet tool also includes a number of utilities for patching JSON files, e.g. you can use x patch
to patch a JSON file with a JSON Patch.
The json.patch
file supports the following JSON Patch operations:
Operation | Notes |
---|---|
add | Add a property or array element. For existing property: set value. |
remove | Remove a property or array element. |
replace | Same as remove followed by add at same location. |
move | Same as remove from source followed by add to destination using value from source. |
copy | Same as add to destination using value from source. |
test | Return success status code if value at path = provided value. |
For example, we could have the following original.json
file:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"SmtpConfig": {}
}
We need to fill this smtp
object with settings such as username, password, host, port, and more. To automate filling these values, we can use the ServiceStack x
tool to apply a json.patch
. The json.patch
file to accomplish this would look something like:
[
{
"op": "add",
"path": "/SmtpConfig",
"value": {
"UserName": "AWS_ACCESS_KEY_ID",
"Password": "AWS_SECRET_ACCESS_KEY",
"Host": "email-smtp.us-east-1.amazonaws.com",
"Port": 587,
"FromName": "From Name",
"FromEmail": "email@address.com",
"Bcc": "bcc email address"
}
}
]
Once this patch is applied, our appsettings.json
transforms into:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"SmtpConfig": {
"UserName": "AWS_ACCESS_KEY_ID",
"Password": "AWS_SECRET_ACCESS_KEY",
"Host": "email-smtp.us-east-1.amazonaws.com",
"Port": 587,
"From": "email address",
"FromName": "From Name",
"Bcc": "bcc email address"
}
}
You can apply this patch using the x
tool's patch
command:
x patch appsettings.json.patch
This expects both the appsettings.json.patch
and appsettings.json
files to be local. Optionally, you can specify both files if their names differ.
x patch changes.json.patch appsettings.json
Lisp REPL​
Lisp's dynamism and extensibility makes it particularly well suited for explanatory programming whose access via a REPL is available
x
, web
and app
dotnet tools.
The quick demo below shows the kind of exploratory programming available where you can query the scriptMethods
available,
query an objects props
, query the Lisp interpreter's global symbols
table containing all its global state including all
defined lisp functions, macros and variables:
YouTube
Annotated REPL Walk through​
Here's an annotated version of the demo below which explains what each of the different expressions is doing.
Just like Sharp Scripts and Sharp Apps the Lisp REPL runs within the #Script Pages ScriptContext sandbox that when run from a Sharp App folder, starts a .NET Core App Server that simulates a fully configured .NET Core App. In this case it's running in the redis Sharp App directory where it was able to access its static web assets as well as its redis-server connection configured in its app.settings.
; quick lisp test!
(+ 1 2 3)
; List of ScriptMethodInfo that the ScriptContext running this Lisp Interpreter has access to
scriptMethods
; first script method
(:0 scriptMethods)
; show public properties of ScriptMethodInfo
(props (:0 scriptMethods))
; show 1 property per line
(joinln (props (:0 scriptMethods)))
; show both Property Type and Name
(joinln (propTypes (:0 scriptMethods)))
; view the Names of all avaialble script methods
(joinln (map .Name scriptMethods))
; view all script methods starting with 'a'
(globln "a*" (map .Name scriptMethods))
; view all script methods starting with 'env'
(globln "env*" (map .Name scriptMethods))
; print environment info about this machine seperated by spaces
(printlns envOSVersion envMachineName envFrameworkDescription envLogicalDrives)
; expand logical drives
(printlns envOSVersion envMachineName envFrameworkDescription "- drives:" (join envLogicalDrives " "))
; view all current global symbols defined in this Lisp interpreter
symbols
; view all symbols starting with 'c'
(globln "c*" symbols)
; see how many symbols are defined in this interpreter
(count symbols)
; see how many script methods there are available
(count scriptMethods)
; view the method signature for all script methods starting with 'all'
(globln "all*" (map .Signature scriptMethods))
; count all files accessible from the configured ScriptContext
(count allFiles)
; view the public properties of the first IVirtualFile
(props (:0 allFiles))
; display the VirtualPath of all available files
(joinln (map .VirtualPath allFiles))
; display the method signature for all script methods starting with 'findFiles'
(globln "findFiles*" (map .Signature scriptMethods))
; see how many .html files are available to this App
(count (findFiles "*.html"))
; see how many .js files are available to this App
(count (findFiles "*.js"))
; show the VirtualPath of all .html files
(joinln (map .VirtualPath (findFiles "*.html")))
; view the VirtualPath's of the 1st and 2nd .html files
(:0 (map .VirtualPath (findFiles "*.html")))
(:1 (map .VirtualPath (findFiles "*.html")))
; view the text file contents of the 1st and 2nd .html files
(fileTextContents (:0 (map .VirtualPath (findFiles "*.html"))))
(fileTextContents (:1 (map .VirtualPath (findFiles "*.html"))))
; display the method signatures of all script methods starting with 'redis'
(globln "redis*" (map .Signature scriptMethods))
; search for all Redis Keys starting with 'urn:' in the redis-server instances this App is configured with
(redisSearchKeys "urn:*")
; display the first redis search entry
(:0 (redisSearchKeys "urn:*"))
; display the key names of all redis keys starting with 'urn:'
(joinln (map :id (redisSearchKeys "urn:*")))
; find out the redis-server data type of the 'urn:tags' key
(redisCall "TYPE urn:tags")
; view all tags in the 'urn:tags' sorted set
(redisCall "ZRANGE urn:tags 0 -1")
; view the string contents of the 'urn:question:1' key
(redisCall "GET urn:question:1")
; parse the json contents of question 1 and display its tag names
(:Tags (parseJson (redisCall "GET urn:question:1")))
; extract the 2nd tag of question 1
(:1 (:Tags (parseJson (redisCall "GET urn:question:1"))))
; clear the Console screen
clear
; exit the Lisp REPL
quit
Enable features and access resources with app.settings​
You can configure the Lisp REPL with any of the resources and features that Sharp Apps and
Gist Desktop Apps have access to, by creating a plain text app.settings
file with all the
features and resources you want the Lisp REPL to have access to, e.g. this Pure Cloud App app.settings
allows the Lisp REPL to use Database Scripts against a AWS PostgreSQL RDS server and query remote
S3 Virtual Files using Virtual File System APIs:
# Note: values prefixed with '$' are resolved from Environment Variables
name AWS S3 PostgreSQL Web App
db postgres
db.connection $AWS_RDS_POSTGRES
files s3
files.config {AccessKey:$AWS_S3_ACCESS_KEY,SecretKey:$AWS_S3_SECRET_KEY,Region:us-east-1,Bucket:rockwind}
See the plugins app.settings for examples of how to load and configure ServiceStack Plugins.
Troubleshooting​
x: command not found​
If after installing any of the dotnet
tools it fails with bash: x: command not found
you'll need to add dotnet tools to your PATH
which you can do in Linux Bash with:
$ echo "export PATH=\$HOME/.dotnet/tools:\$PATH" >> ~/.bashrc
$ . ~/.bashrc
SSL Connection Errors​
To resolve SSL Connection errors you can try commenting out ssl_conf = ssl_sect, e.g:
$ sudo vi /etc/ssl/openssl.cnf
Comment out line in vi
using a #
prefix, write changes and quit:
:%s/^ssl_conf/#&/
:wq
If that doesn't resolve the issue you can try updating the local ca-certificates:
$ sudo update-ca-certificates --fresh
Or try updating the SSL_CERT Environment variables before running the tool again:
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
export SSL_CERT_DIR=/dev/null
Finally you can try running the x
tool with the --ignore-ssl-errors
switch, e.g:
$ x new vue-lite VueLite --ignore-ssl-errors