CheapHelpers.Avalonia.Bridge 1.2.0

dotnet add package CheapHelpers.Avalonia.Bridge --version 1.2.0
                    
NuGet\Install-Package CheapHelpers.Avalonia.Bridge -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CheapHelpers.Avalonia.Bridge" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CheapHelpers.Avalonia.Bridge" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="CheapHelpers.Avalonia.Bridge" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CheapHelpers.Avalonia.Bridge --version 1.2.0
                    
#r "nuget: CheapHelpers.Avalonia.Bridge, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CheapHelpers.Avalonia.Bridge@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CheapHelpers.Avalonia.Bridge&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=CheapHelpers.Avalonia.Bridge&version=1.2.0
                    
Install as a Cake Tool

CheapHelpers.Avalonia.Bridge

Bridge package for integrating CheapAvaloniaBlazor desktop OS notifications with the CheapHelpers unified notification system.

Purpose

This package provides an adapter that allows desktop applications built with CheapAvaloniaBlazor (using Photino, MAUI WebView, or other WebView technologies) to participate in the CheapHelpers multi-channel notification system.

Key Features:

  • Adds Desktop OS notifications as a 5th delivery channel (alongside InApp, Email, SMS, Push)
  • Zero coupling between main packages (CheapHelpers and CheapAvaloniaBlazor remain independent)
  • Clean adapter pattern following .NET ecosystem conventions
  • Minimal overhead (single channel implementation)

Why a Separate Package?

This bridge package exists to keep dependencies clean:

CheapAvaloniaBlazor          (independent - no CheapHelpers dependency)
CheapHelpers.Services        (independent - no Avalonia dependency)
CheapHelpers.Avalonia.Bridge (depends on both ↑)

Neither main package needs to know about the other. Only install this bridge if you're using both packages together.

Installation

dotnet add package CheapHelpers.Avalonia.Bridge

Prerequisites:

  • CheapHelpers (with notification system)
  • CheapAvaloniaBlazor (with desktop interop services)

Quick Start

1. Register Services (Correct Order)

// In your desktop app's Program.cs or Startup.cs
builder.Services
    .AddCheapAvaloniaBlazorServices()     // 1. Register CheapAvaloniaBlazor
    .AddCheapNotifications<MyUser>()      // 2. Register CheapHelpers notifications
    .AddDesktopNotificationBridge();      // 3. Register bridge

Important: Registration order matters. The bridge requires both underlying services to be registered first.

2. Send Notifications to Desktop

// Inject the notification dispatcher
public class MyService(NotificationDispatcher notificationDispatcher)
{
    public async Task NotifyUserAsync(string userId)
    {
        await notificationDispatcher.SendAsync(new UnifiedNotification
        {
            NotificationType = "OrderShipped",
            Title = "Your order has shipped!",
            Body = "Track your package at...",
            RecipientUserIds = [userId],
            Channels = NotificationChannelFlags.Desktop | NotificationChannelFlags.Email
        });
    }
}

3. Configure User Preferences

Desktop notifications respect the same subscription system as other channels:

// Users can enable/disable desktop notifications per notification type
var preference = new UserNotificationPreference
{
    UserId = userId,
    NotificationType = "OrderShipped",
    EnabledChannels = NotificationChannelFlags.Desktop | NotificationChannelFlags.InApp
};

context.UserNotificationPreferences.Add(preference);
await context.SaveChangesAsync();

How It Works

Architecture

┌─────────────────────────────────────────────┐
│        CheapHelpers Notification System     │
│                                             │
│  ┌─────────────────────────────────────┐   │
│  │   NotificationDispatcher             │   │
│  │   (orchestrates multi-channel send)  │   │
│  └──────────────┬──────────────────────┘   │
│                 │                           │
│                 │ resolves all              │
│                 │ INotificationChannel      │
│                 ▼                           │
│  ┌──────────────────────────────────────┐  │
│  │  InApp │ Email │ SMS │ Push │ Desktop│  │  <-- Desktop added by bridge
│  └──────────────────────────────────────┘  │
└─────────────────────────────────────────────┘
                                      │
                                      │ Desktop channel implemented by bridge
                                      ▼
                        ┌──────────────────────────────┐
                        │  DesktopNotificationChannel  │
                        │  (in bridge package)         │
                        └──────────────┬───────────────┘
                                       │ uses
                                       ▼
                        ┌──────────────────────────────┐
                        │  DesktopInteropService       │
                        │  (CheapAvaloniaBlazor)       │
                        └──────────────┬───────────────┘
                                       │ calls JavaScript
                                       ▼
                        ┌──────────────────────────────┐
                        │  WebView Notification API    │
                        │  (Browser/OS integration)    │
                        └──────────────────────────────┘

Channel Implementation

The DesktopNotificationChannel implements INotificationChannel and:

  1. Receives UnifiedNotification from the dispatcher
  2. Calls DesktopInteropService.ShowNotificationAsync() from CheapAvaloniaBlazor
  3. Returns delivery results to the dispatcher

Desktop notifications appear in:

  • Windows: Action Center
  • macOS: Notification Center
  • Linux: Desktop notification daemon (varies by DE)

Important Notes

Client-Side Nature

Desktop notifications are client-side - they show to whoever is currently using the desktop app, regardless of RecipientUserIds. This differs from server-side channels like Email/SMS which can target specific users remotely.

Notification Permissions

Desktop apps must request notification permission from the OS. CheapAvaloniaBlazor handles this via the browser Notification API:

// Handled automatically by CheapAvaloniaBlazor
Notification.requestPermission();

Subscription Provider Support

Desktop notifications work with custom subscription providers just like other channels:

public class ProjectNotificationProvider(CheapContext<MyUser> context)
    : INotificationSubscriptionProvider
{
    public int Priority => 10;
    public string Name => "ProjectNotifications";

    public bool CanHandle(ISubscriptionContext? subscriptionContext)
        => subscriptionContext is ProjectSubscriptionContext;

    public async Task<NotificationChannelFlags?> GetEnabledChannelsAsync(
        string userId,
        string notificationType,
        ISubscriptionContext? context,
        CancellationToken cancellationToken)
    {
        var projectContext = (ProjectSubscriptionContext)context!;

        // User might want desktop notifications for high-priority projects only
        if (projectContext.Project.Priority == Priority.High)
            return NotificationChannelFlags.Desktop | NotificationChannelFlags.Email;

        return NotificationChannelFlags.Email; // Lower priority projects: email only
    }
}

Future Extensibility

This bridge package can grow to include additional desktop integrations:

  • Desktop file pickers - OS file dialogs integration
  • System tray integration - Notification badges on system tray icons
  • Window management - Desktop window state helpers
  • Desktop-specific auth flows - OS credential storage integration

For now, it focuses solely on OS notifications, keeping the package lightweight.

Examples

Send Urgent Desktop Notification

await dispatcher.SendAsync(new UnifiedNotification
{
    NotificationType = "SecurityAlert",
    Title = "Unusual login detected",
    Body = "Someone logged into your account from a new device",
    RecipientUserIds = [userId],
    Priority = NotificationPriority.Urgent,
    Channels = NotificationChannelFlags.Desktop | NotificationChannelFlags.Email | NotificationChannelFlags.Sms
});

Desktop + InApp Only (Silent Server-Side)

await dispatcher.SendAsync(new UnifiedNotification
{
    NotificationType = "MessageReceived",
    Title = "New message from Alice",
    Body = "Hey, are you available?",
    RecipientUserIds = [userId],
    Channels = NotificationChannelFlags.Desktop | NotificationChannelFlags.InApp
    // No Email/SMS - keeps it quiet
});

Conditional Desktop Based on Time

// User preferences can include Do Not Disturb hours
var preference = new UserNotificationPreference
{
    UserId = userId,
    NotificationType = "MessageReceived",
    EnabledChannels = NotificationChannelFlags.Desktop | NotificationChannelFlags.InApp,
    DoNotDisturbStartHour = 22, // 10 PM
    DoNotDisturbEndHour = 8      // 8 AM
};

// Desktop notifications automatically respect DND hours
// Falls back to InApp only during quiet hours

Troubleshooting

Desktop notifications not showing?

  1. Check registration order - Bridge must be registered AFTER both main packages
  2. Verify OS permissions - User must grant notification permission to the app
  3. Check user preferences - Desktop channel must be enabled for the notification type
  4. Inspect logs - DesktopNotificationChannel logs errors at Error level

Bridge package not found?

Ensure you have the correct package references:

<PackageReference Include="CheapHelpers" Version="..." />
<PackageReference Include="CheapAvaloniaBlazor" Version="..." />
<PackageReference Include="CheapHelpers.Avalonia.Bridge" Version="..." />
  • CheapHelpers - Core helpers and unified notification system
  • CheapHelpers.Services - Service layer including notification services
  • CheapHelpers.Blazor - Blazor components including NotificationBell
  • CheapAvaloniaBlazor - Desktop Blazor hosting (Photino, MAUI WebView)

License

MIT License - See LICENSE

Contributing

Contributions welcome! See CONTRIBUTING.md

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.2.0 72 1/10/2026