IsOnline.NET 1.0.1

dotnet add package IsOnline.NET --version 1.0.1
                    
NuGet\Install-Package IsOnline.NET -Version 1.0.1
                    
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="IsOnline.NET" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="IsOnline.NET" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="IsOnline.NET" />
                    
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 IsOnline.NET --version 1.0.1
                    
#r "nuget: IsOnline.NET, 1.0.1"
                    
#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 IsOnline.NET@1.0.1
                    
#: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=IsOnline.NET&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=IsOnline.NET&version=1.0.1
                    
Install as a Cake Tool

IsOnline.NET

NuGet

Why?

NetworkInterface.GetIsNetworkAvailable() and Ping only tell you if there's a local connection — not whether the internet is actually reachable. Behind a captive portal (hotel, airport Wi-Fi), your device has an IP address but can't reach anything until you log in. IsOnline.NET detects this correctly.

Install

dotnet add package IsOnline.NET

Targets: netstandard2.1 · net8.0

Quick Start

using IsOnline;

Console.WriteLine(await IsOnlineChecker.CheckAsync());
// => true

Usage Examples

With timeout

bool online = await IsOnlineChecker.CheckAsync(new IsOnlineOptions
{
    Timeout = 10_000, // 10 seconds
});

With cancellation

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));

bool online = await IsOnlineChecker.CheckAsync(new IsOnlineOptions
{
    CancellationToken = cts.Token,
});
// => false (if cancelled before any check succeeds)

With fallback URLs

bool online = await IsOnlineChecker.CheckAsync(new IsOnlineOptions
{
    FallbackUrls = ["https://www.google.com", "https://www.github.com"],
});

With IPv6

bool online = await IsOnlineChecker.CheckAsync(new IsOnlineOptions
{
    IpVersion = 6,
});

All options combined

bool online = await IsOnlineChecker.CheckAsync(new IsOnlineOptions
{
    Timeout           = 8_000,
    IpVersion         = 4,
    CancellationToken = cts.Token,
    FallbackUrls      = ["https://your-api.example.com/health"],
});

API

IsOnlineChecker.CheckAsync(IsOnlineOptions? options = null)

Returns Task<bool>true if online, false otherwise.

  • Never throws on network failure (always returns false).
  • Throws ArgumentOutOfRangeException if IpVersion is not 4 or 6, or Timeout is ≤ 0.

IsOnlineOptions

Property Type Default Description
Timeout int (ms) 5000 Max wait time per check group
IpVersion int 4 4 or 6
CancellationToken CancellationToken default Cancels the check; resolves to false
FallbackUrls IReadOnlyList<string>? null Checked sequentially when all built-in checks fail

IsOnlineChecker.CheckFailed event

Subscribe to receive diagnostics when individual check URLs fail:

IsOnlineChecker.CheckFailed += (_, e) =>
{
    Console.WriteLine($"[{e.Timestamp:HH:mm:ss}] {e.Url} — {e.ErrorMessage}");
};

Each event provides:

  • Timestamp (DateTimeOffset) — when the failure occurred
  • Url (string) — the URL that failed
  • ErrorMessage (string) — human-readable error
  • Exception (Exception?) — the original exception

How It Works

Four checker groups run in parallel. The first success winsCheckAsync returns true immediately without waiting for the others.

🌐 Public IP Check

URL Success Condition
https://icanhazip.com Response body is a valid IP address
https://api.ipify.org (IPv4) / https://api6.ipify.org (IPv6) Response body is a valid IP address

🍎 Apple Captive Portal (iOS / macOS / iPadOS)

URL Success Condition
https://captive.apple.com/hotspot-detect.html Body contains "Success"
http://captive.apple.com/hotspot-detect.html Body contains "Success"
http://www.apple.com/library/test/success.html Body contains "Success"

User-Agent: CaptiveNetworkSupport/1.0 wispr

If behind a captive portal, these URLs are redirected to a login page → body won't contain "Success" → correctly returns false.

🤖 Google Connectivity Check (Android / ChromeOS)

URL Success Condition
http://connectivitycheck.gstatic.com/generate_204 HTTP 204 No Content
https://connectivitycheck.gstatic.com/generate_204 HTTP 204 No Content
http://clients3.google.com/generate_204 HTTP 204 No Content
https://clients3.google.com/generate_204 HTTP 204 No Content
http://www.gstatic.com/generate_204 HTTP 204 No Content

A redirect or any other status code → captive portal suspected → false.

🪟 Microsoft NCSI (Windows)

URL Success Condition
http://www.msftconnecttest.com/connecttest.txt Body = "Microsoft Connect Test"
http://www.msftncsi.com/ncsi.txt Body = "Microsoft NCSI"
http://www.msftconnecttest.com/redirect HTTP 200 OK

Fallback URLs

If all four checker groups fail and FallbackUrls is provided, those are checked sequentially:

  • HEAD request first (minimal data transfer)
  • Falls back to GET on HTTP 405 Method Not Allowed
  • Success = any 2xx or 3xx response

Architecture

IsOnlineChecker.CheckAsync()
     │
     ├── 1. All NICs internal? → false
     ├── 2. CancellationToken cancelled? → false
     │
     └── 3. Run in parallel (first true wins):
           ├── PublicIpChecker       (2 URLs)
           ├── ApplePortalChecker    (3 URLs)
           ├── GooglePortalChecker   (5 URLs)
           └── MicrosoftPortalChecker(3 URLs)
                     │
                     └── All failed? → try FallbackUrls sequentially
                               │
                               └── All failed? → false

Key design decisions:

  • Shared static HttpClient — avoids socket exhaustion
  • AllowAutoRedirect = false — detects captive portals via redirect
  • ConfigureAwait(false) — safe for ASP.NET, WPF, WinForms contexts
  • Diagnostics never throwCheckFailed event errors are swallowed

Proxy Support

To use through a proxy, configure HttpClient.DefaultProxy before calling CheckAsync:

HttpClient.DefaultProxy = new WebProxy("http://proxy.example.com:8080");

Requirements

  • .NET Standard 2.1+ or .NET 8.0+
  • No external NuGet dependencies

License

MIT — Created by Ishwar Datt Mishra.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

    • No dependencies.
  • net8.0

    • No dependencies.

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.1 108 3/2/2026
1.0.0 106 3/2/2026