Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,57 @@
|:-|---|---|
| System.Net | [![Build Status](https://dev.azure.com/nanoframework/System.Net/_apis/build/status/System.Net?repoName=nanoframework%2FSystem.Net&branchName=main)](https://dev.azure.com/nanoframework/System.Net/_build/latest?definitionId=20&repoName=nanoframework%2FSystem.Net&branchName=main) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.System.Net.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.System.Net/) |

## NetworkHelper usage

`NetworkHelper` provides two patterns for establishing a network connection: a blocking token-based approach for simple use-cases, and an event-based approach for background connection management.

### Token-based (retryable)

Call `SetupAndConnectNetwork` with a `CancellationToken` timeout. This method can be called repeatedly — if the first attempt times out, call it again:

```csharp
bool connected = false;
while (!connected)
{
CancellationTokenSource cs = new(30000);
connected = NetworkHelper.SetupAndConnectNetwork(requiresDateTime: true, token: cs.Token);
if (!connected)
{
Debug.WriteLine($"Network not ready, status: {NetworkHelper.Status}");
// wait before retrying
Thread.Sleep(5000);
}
}
```

### Event-based

Call `SetupNetworkHelper` once at startup. The helper connects in the background. Wait on `NetworkReady`:

```csharp
NetworkHelper.SetupNetworkHelper(requiresDateTime: true);

if (!NetworkHelper.NetworkReady.WaitOne(30000, true))
{
Debug.WriteLine($"Failed to connect: {NetworkHelper.Status}");
}
```

> **Note:** `NetworkReady` is reset when the connection is lost and re-signaled when it is restored, accurately reflecting live network state. Code that previously assumed `NetworkReady` would remain set after first connect should be updated to handle transient disconnects.

### Reset and reconfigure

Call `Reset()` to fully reset the helper so it can be called again with different settings, or to restart after an error:

```csharp
NetworkHelper.Reset();

// Now call SetupNetworkHelper or SetupAndConnectNetwork again
NetworkHelper.SetupNetworkHelper(requiresDateTime: true);
```

`SetupNetworkHelper` throws `InvalidOperationException` if called a second time without a prior `Reset()`. Token-based methods (`SetupAndConnectNetwork`) do not have this restriction and are always retryable.

## Feedback and documentation

For documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home).
Expand Down
56 changes: 47 additions & 9 deletions Tests/NetworkHelperTests/ConnectToEthernetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ public void TestFixedIPAddress_01()

Assert.IsTrue(success);

// need to reset this internal flag to allow calling the NetworkHelper again
NetworkHelper.ResetInstance();
NetworkHelper.Reset();
}

[TestMethod]
Expand All @@ -47,8 +46,7 @@ public void TestFixedIPAddress_02()
// wait 10 seconds to connect to the network
Assert.IsTrue(NetworkHelper.NetworkReady.WaitOne(10000, true));

// need to reset this internal flag to allow calling the NetworkHelper again
NetworkHelper.ResetInstance();
NetworkHelper.Reset();
}

[TestMethod]
Expand All @@ -64,8 +62,7 @@ public void TestDhcp_01()

Assert.IsTrue(success);

// need to reset this internal flag to allow calling the NetworkHelper again
NetworkHelper.ResetInstance();
NetworkHelper.Reset();
}

[TestMethod]
Expand All @@ -76,8 +73,7 @@ public void TestDhcp_02()
// wait 10 seconds to connect to the network and get an IP address
Assert.IsTrue(NetworkHelper.NetworkReady.WaitOne(10000, true));

// need to reset this internal flag to allow calling the NetworkHelper again
NetworkHelper.ResetInstance();
NetworkHelper.Reset();
}

[TestMethod]
Expand All @@ -88,9 +84,51 @@ public void TestSingleUsage()
// call once, it's OK
NetworkHelper.SetupNetworkHelper();

// call twice, it's a NO NO and should throw an exception
// call twice without Reset — must throw
NetworkHelper.SetupNetworkHelper();
});

NetworkHelper.Reset();
}

[TestMethod]
public void TestRetryAfterTimeout()
{
// First attempt: very short timeout so it expires
CancellationTokenSource cs1 = new(1000);
var firstResult = NetworkHelper.SetupAndConnectNetwork(token: cs1.Token);

Assert.IsFalse(firstResult, "First call should have timed out");
Assert.IsTrue(NetworkHelper.Status == NetworkHelperStatus.TokenExpiredWaitingIPAddress);

// Second attempt: longer timeout — must not throw InvalidOperationException
CancellationTokenSource cs2 = new(10000);
var secondResult = NetworkHelper.SetupAndConnectNetwork(token: cs2.Token);

// If there is a network, second attempt should succeed;
// if not, it will time out again — either way, it must NOT throw
Assert.IsTrue(
NetworkHelper.Status == NetworkHelperStatus.NetworkIsReady ||
NetworkHelper.Status == NetworkHelperStatus.TokenExpiredWaitingIPAddress ||
NetworkHelper.Status == NetworkHelperStatus.TokenExpiredWaitingDateTime,
"Expected a terminal status after the second attempt");

NetworkHelper.Reset();
}

[TestMethod]
public void TestResetAllowsSetupNetworkHelperRestart()
{
NetworkHelper.SetupNetworkHelper();

// Reset and call again — must not throw
NetworkHelper.Reset();
NetworkHelper.SetupNetworkHelper();

// wait briefly
NetworkHelper.NetworkReady.WaitOne(5000, true);

NetworkHelper.Reset();
}

public void DisplayLastError(bool success)
Expand Down
Loading
Loading