| applyTo | ** |
|---|
Cross-platform remote access and control. .NET 10 backend (ASP.NET Core), Blazor WebAssembly frontend, Avalonia desktop apps.
- Build:
dotnet build ControlR.slnx --verbosity quiet(no output = success) - Run: Use IDE launch profiles — "Full Stack" in VS/Rider; "Full Stack (Debug)" or "Full Stack (Hot Reload)" in VS Code.
- Don't attempt to fix warning
BB0001: Member '{member_name}' is not in the correct order.
- Exclude
ControlR.Web.Server/novnc/and anynode_modules/directories from context.
Services use extension methods, not direct Program.cs registrations:
| Project | Method | File |
|---|---|---|
| ControlR.Agent | AddControlRAgent |
ControlR.Agent.Common\Startup\HostBuilderExtensions.cs |
| ControlR.Web.Server | AddControlrServer |
ControlR.Web.Server\Startup\WebApplicationBuilderExtensions.cs |
| ControlR.Web.Client | AddControlrWebClient |
ControlR.Web.Client\Startup\IServiceCollectionExtensions.cs |
| ControlR.DesktopClient | AddControlrDesktop |
ControlR.DesktopClient\StaticServiceProvider.cs |
- AgentHub — device heartbeats → forwarded to ViewerHub groups.
- ViewerHub — web client connections and remote control requests.
- Hub groups organized by tenant, device tags, and user roles via
HubGroupNames.GetTenantDevicesGroupName(),GetTagGroupName(), etc. - Agent ↔ DesktopClient IPC via named pipes (
IIpcConnection). Agent forwardsRemoteControlRequestIpcDtoto the user-session DesktopClient; DesktopClient reports back for relay to server.
DTOs go under \Libraries\ControlR.Libraries.Api.Contracts\Dtos\:
HubDtos/— SignalR hub payloadsIpcDtos/— Agent ↔ DesktopClient IPCServerApi/— REST APIRemoteControlDtos/— remote control, routed through websocket relay
- Platform implementations in
ControlR.Agent.CommonunderServices.Windows/,Services.Linux/,Services.Mac/. - Desktop client isolates native code in
ControlR.DesktopClient.Windows/,.Linux/,.Mac/with shared code inControlR.DesktopClient.Common. - Conditional compilation symbols:
IS_WINDOWS,IS_MACOS,IS_LINUX,IS_UNIX(defined inDirectory.Build.props). - Use
[SupportedOSPlatform]for platform-specific code. - Platform detection via
ISystemEnvironment.PlatformandRuntimeInformation. - macOS debug builds: disable app-bundle output; emit managed launch files (
.dll,.deps.json,.runtimeconfig.json) so VS Code can launch viadotnet.
- 2-space indent. Braces on own lines. Prefer
var. Use collection expressions ([]). - No null-forgiving operator (
!) outside tests, except within EF Core queries that execute server-side. Userequiredwhere applicable. - No TODOs, placeholder code, or "in production you should..." comments. Every implementation must be complete.
- No "Async" suffix on async methods unless distinguishing from a sync overload.
- When an interface has only one implementation, place the interface in the same file as the implementation rather than a separate file.
- Don't create extra public classes in files containing other classes. Use
Result<T>fromControlR.Libraries.Shared.Primitivesfor result types. - Reduce indentation by returning/continuing early and inverting conditions when appropriate.
- Component-scoped JS/CSS:
MyComponent.razor.jsandMyComponent.razor.cssalongsideMyComponent.razor. - JS interop: inherit
JsInteropableComponentin both.razorand code-behind.csfiles. - Prefer code-behind
.razor.csfiles for C# logic. Check for existing code-behind before editing.razorfiles. - Use MudBlazor components.
- Avalonia UI with MVVM pattern.
- All UI text bound via
x:Static common:Localization.KeyName. Add keys to JSON files under/ControlR.DesktopClient.Common/Resources/Strings/. - Icons: https://avaloniaui.github.io/icons.html — add to
Icons.axamlresource dictionary as needed. IMessengerfor cross-component communication.
- xUnit v3. Run tests with
dotnet run, notdotnet test. - Server test helpers in
Tests\ControlR.Web.Server.Tests\Helpers\.
- Central package management via
Directory.Packages.props. - Add packages with
dotnet add <project> package <name>— never addVersionattributes to<PackageReference>elements.
- Planning documents and implementation notes go in
/.plans/(not committed).