VirtualTerminal.SecureShell
1.0.0
dotnet add package VirtualTerminal.SecureShell --version 1.0.0
NuGet\Install-Package VirtualTerminal.SecureShell -Version 1.0.0
<PackageReference Include="VirtualTerminal.SecureShell" Version="1.0.0" />
<PackageVersion Include="VirtualTerminal.SecureShell" Version="1.0.0" />
<PackageReference Include="VirtualTerminal.SecureShell" />
paket add VirtualTerminal.SecureShell --version 1.0.0
#r "nuget: VirtualTerminal.SecureShell, 1.0.0"
#:package VirtualTerminal.SecureShell@1.0.0
#addin nuget:?package=VirtualTerminal.SecureShell&version=1.0.0
#tool nuget:?package=VirtualTerminal.SecureShell&version=1.0.0
VirtualTerminal.SecureShell
VirtualTerminal.SecureShell is an addon for the core VirtualTerminal library that provides an SSH-based SecureShellSession.
It uses the SSH.NET library under the hood and connects a remote shell (e.g. /bin/bash on Linux) to the VirtualTerminalView control.
Getting started
Reference the project
- Add a project reference from your WPF app to:
VirtualTerminal.SecureShellVirtualTerminal(core – already referenced by the addon).
- Ensure your app targets
net10.0-windowsand has WPF enabled.
VirtualTerminal.SecureShell already references SSH.NET via:
<PackageReference Include="SSH.NET" Version="2025.1.0" />
So you don’t need to add it manually.
Basic usage with VirtualTerminalView
XAML (same as core README):
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vt="clr-namespace:VirtualTerminal;assembly=VirtualTerminal">
<Grid>
<vt:VirtualTerminalView x:Name="Terminal"
AllowDirectInput="True"
ScrollDownVisible="True" />
</Grid>
</Window>
Code-behind example connecting with password authentication:
using System;
using System.Threading.Tasks;
using System.Windows;
using VirtualTerminal;
public partial class MainWindow : Window
{
private SecureShellSession? _session;
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private async void OnLoaded(object? sender, RoutedEventArgs e)
{
_session = new SecureShellSession("my-server.example.com", "user", "password");
Terminal.Session = _session;
bool connected = await _session.TryConnectAsync();
if (!connected)
{
MessageBox.Show("Failed to connect SSH session.");
}
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_session?.Dispose();
}
}
Note: For real applications you should never hardcode credentials; use secure storage / UI prompts.
SecureShellSession API
Located in SecureShellSession.cs (namespace VirtualTerminal).
Purpose
- Concrete
TerminalSessionimplementation backed by SSH:- Manages an
ISshClient(SshClientin practice). - Creates a
ShellStreamand forwards its output toVirtualTerminalBuffer. - Forwards user input from the terminal UI into the SSH shell.
- Manages an
Core properties
ISshClient? Client- The underlying
SSH.NETclient.
- The underlying
ShellStream? ShellStream- Interactive shell stream created from the client.
bool IsConnected- Indicates whether the client is currently connected.
bool AutoFlush { get; set; } = true- If
true, flushes the shell stream after each write to ensure prompt output.
- If
Constructors
SecureShellSession has multiple overloads for flexibility:
SecureShellSession(ISshClient client, Encoding? encoding = null)- Wraps an externally-created client.
- Does not own the client (won’t dispose it automatically).
SecureShellSession(ConnectionInfo connectionInfo, Encoding? encoding = null)- Creates and owns a new
SshClientfrom aConnectionInfo.
- Creates and owns a new
SecureShellSession(string host, int port, string username, string password, Encoding? encoding = null)SecureShellSession(string host, string username, string password, Encoding? encoding = null)SecureShellSession(string host, int port, string username, Encoding? encoding = null, params IPrivateKeySource[] keyFiles)SecureShellSession(string host, string username, Encoding? encoding = null, params IPrivateKeySource[] keyFiles)
These overloads cover password and key-based authentication, with or without custom ports.
All constructors call the TerminalSession base with the specified or default encoding (UTF8).
Connecting and reconnecting
Task ConnectAsync(CancellationToken cancellationToken = default)- Validates
_client, setsKeepAliveInterval = 30s, connects the client. - Creates a
ShellStreamwith stream name"xterm"and subscribes toDataReceived.
- Validates
Task<bool> TryConnectAsync(CancellationToken cancellationToken = default)- Wraps
ConnectAsyncin a try/catch, returningtrueon success andfalseon failure.
- Wraps
Task ReconnectAsync(CancellationToken cancellationToken = default)- Attempts to reconnect up to
MaxReconnectAttemptstimes (default: 3) with a delay (ReconnectDelayMs, default: 2000ms).
- Attempts to reconnect up to
Task<bool> TryReconnectAsync(CancellationToken cancellationToken = default)- Same as
ReconnectAsyncbut returnsboolinstead of throwing.
- Same as
Task DisconnectAsync(CancellationToken cancellationToken = default)- Disconnects the SSH client, disposes the
ShellStream, then nulls out the reference.
- Disconnects the SSH client, disposes the
If you need to fully reset the client, use the internal helper:
protected void ClosePreviousClient()- Disposes
_clientonly if_ownsClientistrue, then clears the field.
- Disposes
Input / output and resizing
override void Resize(int columns, int rows)- Calls
Buffer.ResizeBuffer(columns, rows)to update the local buffer. - Derives window and buffer sizes from
CONSOLE_SCREEN_BUFFER_INFO. - Calls
_shellStream.ChangeWindowSize(nCols, nRows, nWidth, nHeight)to inform the remote side.
- Calls
override void WriteInput(ReadOnlySpan<byte> data)- Writes directly to
_shellStreamand flushes ifAutoFlushistrue.
- Writes directly to
ValueTask WriteInputAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken = default)- Asynchronous variant using
ShellStream.WriteAsync.
- Asynchronous variant using
Task WriteInputAsync(byte[] data, CancellationToken cancellationToken = default)- Another async variant with
byte[]parameter.
- Another async variant with
virtual void Flush()/virtual void FlushAsync(CancellationToken cancellationToken = default)- Explicit flush operations on the
ShellStream.
- Explicit flush operations on the
DataReceived handler
SecureShellSession subscribes to ShellStream.DataReceived:
protected virtual void DataReceived(object? sender, ShellDataEventArgs args)- Converts received bytes from
InputEncodingintoVirtualTerminalBuffer.Encoding. - Writes to
Bufferand callsNotifyBufferUpdated()to trigger UI re-render.
- Converts received bytes from
Disposal
protected override void Dispose(bool disposing)- If still connected, calls
DisconnectAsync().Wait(5000). - Disposes
_clientif_ownsClientistrue.
- If still connected, calls
Always dispose sessions you create:
_session?.Dispose();
Example: key-based authentication
using Renci.SshNet;
using VirtualTerminal;
// Private key from file
var keyFile = new PrivateKeyFile(@"C:\Users\me\.ssh\id_rsa");
var session = new SecureShellSession(
host: "my-server.example.com",
username: "me",
encoding: null, // use default UTF-8
keyFiles: keyFile);
Terminal.Session = session;
await session.ConnectAsync();
The resulting shell behaves like an xterm-compatible remote terminal inside your WPF app.
Error handling and reconnection
- Use
TryConnectAsyncwhen you want to handle connection failures gracefully without exceptions:
if (!await session.TryConnectAsync())
{
// show message, retry, etc.
}
- Use
TryReconnectAsyncwhen you want a best-effort reconnection:
bool reconnected = await session.TryReconnectAsync();
if (!reconnected)
{
// maybe notify user and close tab
}
If ValidateClient() detects that the SSH client is not connected (or _shellStream is null), it throws ClientUninitializedException.
This typically means you forgot to call ConnectAsync / TryConnectAsync, or the connection was lost and not re-established.
Notes & limitations
- Transport: Only interactive shell via
ShellStreamis supported out of the box (no SFTP / exec channels here). - Encoding: Defaults to UTF‑8; you can override by passing your own
Encodingto the constructor. - Remote terminal type: The shell stream is created with name
"xterm"because many systems expect this for full interactivity.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-windows7.0 is compatible. |
-
net10.0-windows7.0
- SSH.NET (>= 2025.1.0)
- VirtualTerminal (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 87 | 1/20/2026 |