You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: Implement TenantAuthHealthService for runtime token-renewal monitoring
- Added TenantAuthHealthService to manage authentication state for tenants, including failure reporting and recovery.
- Integrated the service into the application startup process.
- Updated SettingsWindow to display re-authentication prompts and actions for tenants with expired tokens.
- Enhanced SettingsViewModel to handle tenant authentication state changes and provide a "Fix sign-in" command.
- Introduced unit tests for TenantAuthHealthService to ensure correct behavior of failure reporting and recovery mechanisms.
- Updated UI components to reflect authentication state and provide user feedback on sign-in status.
Add `<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>` to your `<PropertyGroup>`. This copies every transitive NuGet dependency into the build output so the host can resolve them at runtime without a global package cache.
# A plain build also works; the host falls back to sibling-DLL resolution
55
+
# when no .deps.json is present.
56
+
dotnet build YourPlugin.csproj -c Release
57
+
```
58
+
59
+
Do **not** ship `AzureTray.Plugin.Contracts.dll` in the output — the `PrivateAssets="all"` reference in your `.csproj` already excludes it. The host loads its own copy of that assembly; a second copy causes a type-identity mismatch and the `ITrayPlugin` cast silently fails.
60
+
61
+
### 3. Install into the plugins folder
62
+
63
+
The host scans `%LOCALAPPDATA%\AzureTray.Data\plugins\` at startup using two layouts:
64
+
65
+
| Layout | When to use | Steps |
66
+
|---|---|---|
67
+
|**Subfolder (recommended)**| Any plugin with transitive deps | Create `plugins\<YourPackageId>\`, copy your publish output there. The main DLL **must** be named `<folder-name>.dll` (e.g. `plugins\Acme.Plugin.Foo\Acme.Plugin.Foo.dll`). |
68
+
|**Flat (legacy)**| Single-DLL plugins with no private deps | Drop `YourPlugin.dll` directly in `plugins\`. |
69
+
70
+
For the subfolder layout the loader first tries `plugins\<folder>\<folder>.dll`; if that name doesn't exist it scans for any DLL in the folder that contains an `ITrayPlugin` implementation. Framework assemblies whose name starts with `System.`, `Microsoft.`, `Azure.`, or `Newtonsoft.` are skipped during the scan.
71
+
72
+
### 4. Runtime trust mode
73
+
74
+
The default trust mode is `AllowUnsigned` (development). For your own testing this means no signing is needed. Deployments configured with `RequireSigned` or `RequireTrustedPublisher` will reject the plugin unless it carries a valid Authenticode signature.
75
+
34
76
## Version gate
35
77
36
-
Plugins declare `ITrayPlugin.ApiVersion` and the host rejects any plugin whose value doesn't equal `PluginApiVersion.Current`. The contract version bumps only on breaking changes — minor host releases keep loading existing plugins.
78
+
Plugins declare `ITrayPlugin.ApiVersion` (the `PluginApiVersion.Current` value they were built against). The host loads a plugin when that value falls within its **supported range**`[PluginApiVersion.MinSupported, PluginApiVersion.Current]`; anything outside the range is rejected with a logged message naming the range. Use `PluginApiVersion.IsSupported(int)` to test a value.
79
+
80
+
Because the contracts assembly keeps a **fixed `AssemblyVersion`**, an old plugin always binds to the host's current contracts copy at runtime — the range is the only thing that decides whether that copy will load it.
81
+
82
+
How the range moves:
83
+
84
+
-**Additive, binary-compatible changes** (a new default-interface member, a new optional capability interface, a new init-only property on a record) bump `Current` and leave `MinSupported` alone. Plugins built against any version still in the window keep loading — so you can build against an older API and keep running on newer hosts.
85
+
-**Breaking changes** raise `MinSupported`, intentionally locking out the now-incompatible older plugins. These should be rare; prefer the additive techniques above.
86
+
87
+
To run a single plugin binary across a span of hosts, build against the lowest API you need and feature-detect newer host capabilities at runtime via `IPluginContext.HostVersion`.
0 commit comments