Skip to main content

C# Starter Template

Professional plugin template for C# with async/await patterns and modern .NET features.

Overview

The C# starter template provides a complete, production-ready foundation for building HyperHQ plugins in C# with:

  • Modern async/await patterns throughout
  • Challenge-response authentication
  • SocketIOClient library integration
  • Microsoft.Extensions.Logging for structured logging
  • Single-file deployment option

Prerequisites

  • .NET SDK 6.0 or later
  • Visual Studio, VS Code, or Rider (optional)
  • Basic understanding of C# and async programming

Quick Start

1. Get the Template

Navigate to the templates directory in your HyperHQ installation:

cd "C:\HyperHQ\docs\templates\csharp-starter"

Or copy the csharp-starter folder from HyperHQ's docs/templates directory to your development location.

2. Restore Dependencies

dotnet restore

3. Build

# Standard build
dotnet build -c Release

# Single-file executable
dotnet publish -c Release -r win-x64 \
--self-contained \
-p:PublishSingleFile=true \
-o ./publish

4. Install in HyperHQ

# Create plugin directory
mkdir "C:\HyperHQ\plugins\my-csharp-plugin"

# Copy files
copy publish\*.exe "C:\HyperHQ\plugins\my-csharp-plugin\"
copy plugin.json "C:\HyperHQ\plugins\my-csharp-plugin\"

Key Features

Environment Variables

The template validates required environment variables in the constructor:

Program.cs
public Plugin()
{
_pluginId = Environment.GetEnvironmentVariable("HYPERHQ_PLUGIN_ID");
if (string.IsNullOrEmpty(_pluginId))
{
throw new InvalidOperationException(
"Missing HYPERHQ_PLUGIN_ID - plugin must be launched by HyperHQ"
);
}

_authChallenge = Environment.GetEnvironmentVariable("HYPERHQ_AUTH_CHALLENGE");
// ... more validation
}

Async Socket.IO Communication

Full async/await pattern support:

Program.cs
_socket.On("authenticated", async response =>
{
var data = response.GetValue<Dictionary<string, object>>();
if (data["success"] is true)
{
_sessionToken = data["sessionToken"].ToString();
_isAuthenticated = true;

await RegisterPlugin();
await SendNotification("Connected to HyperHQ", "info");
}
});

Structured Logging

Built-in logging with Microsoft.Extensions.Logging:

Program.cs
_logger.LogInformation("Authentication successful");
_logger.LogDebug("Data request sent: {Method} (ID: {RequestId})", method, requestId);
_logger.LogError(ex, "Failed to connect to Socket.IO server");

Authenticated Requests

Helper method for making authenticated data requests:

Program.cs
private async Task<string> RequestData(string method, object parameters)
{
if (!_isAuthenticated)
{
throw new InvalidOperationException("Not authenticated with HyperHQ");
}

var requestId = $"{method}-{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";

await _socket.EmitAsync("request_data", new
{
method = method,
@params = parameters,
requestId = requestId,
sessionToken = _sessionToken
});

return requestId;
}

Template Structure

csharp-starter/
├── Program.cs # Main plugin implementation
├── Plugin.csproj # Project configuration
├── plugin.json # Plugin manifest
├── build.sh # Build script (Unix)
└── build.bat # Build script (Windows)

Customization

1. Update Project Settings

Edit Plugin.csproj:

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<AssemblyName>MyPlugin</AssemblyName>
</PropertyGroup>

2. Add Your Logic

Implement custom actions:

Program.cs
public async Task<object> Execute(Dictionary<string, object> data)
{
var action = data.ContainsKey("action") ? data["action"].ToString() : "default";

return action switch
{
"my_action" => await HandleMyAction(data),
"sync_data" => await HandleSyncData(data),
_ => new { error = $"Unknown action: {action}" }
};
}

3. Add Event Handlers

Program.cs
_socket.On("my:custom:event", response =>
{
var data = response.GetValue<Dictionary<string, object>>();
HandleCustomEvent(data);
});

Building for Production

Single-File Deployment

dotnet publish -c Release -r win-x64 \
--self-contained \
-p:PublishSingleFile=true \
-p:PublishTrimmed=true \
-o ./dist

Reduce File Size

dotnet publish -c Release -r win-x64 \
--self-contained \
-p:PublishSingleFile=true \
-p:PublishTrimmed=true \
-p:PublishReadyToRun=true \
-p:TrimMode=Link

Performance Tips

  1. Use async/await consistently - Don't mix sync and async
  2. Dispose resources properly - Use using statements
  3. Configure logging levels - Set to Warning/Error in production
  4. Use object pooling for frequently allocated objects

Troubleshooting

"Microsoft.Extensions.Logging not found"

dotnet restore
dotnet add package Microsoft.Extensions.Logging
dotnet add package Microsoft.Extensions.Logging.Console

"SocketIOClient not found"

dotnet add package SocketIOClient

Plugin crashes on startup

  1. Check dependencies are included in publish
  2. Use --self-contained flag
  3. Test executable from command line first

Authentication timeout

// Increase connection timeout
var options = new SocketIOOptions
{
ConnectionTimeout = TimeSpan.FromSeconds(10),
// ...
};

Advanced Features

Progress Reporting

for (int progress = 0; progress <= 100; progress += 10)
{
await _socket.EmitAsync("plugin:progress", new
{
task = "processing",
progress = progress,
message = $"Processing... {progress}%"
});

await Task.Delay(100);
}

Error Handling

try
{
await ProcessData();
}
catch (Exception ex)
{
_logger.LogError(ex, "Processing failed");

await _socket.EmitAsync("plugin:notify", new
{
type = "error",
message = "Processing failed: " + ex.Message
});
}

Learn More