Skip to content

Commit

Permalink
New Bidir demo for C# (#291)
Browse files Browse the repository at this point in the history
  • Loading branch information
bernardnormier authored Feb 12, 2025
1 parent 8a65ec9 commit a37cfbe
Show file tree
Hide file tree
Showing 21 changed files with 276 additions and 410 deletions.
33 changes: 0 additions & 33 deletions csharp/C# NET demos.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "client", "Ice\session\msbui
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "server", "Ice\session\msbuild\server\server.csproj", "{F0BEAEC8-0D12-4196-A20D-2681EBDA15E0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bidir", "bidir", "{A1DE7220-B866-4216-A6A1-DA2B0D136A76}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "client", "Ice\bidir\msbuild\client\client.csproj", "{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "server", "Ice\bidir\msbuild\server\server.csproj", "{46E5DF0C-DBEE-4874-A778-776A3640C0F3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "context", "context", "{D04FD855-69A8-43E5-8F94-FB16B3D8BCA8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "client", "Ice\context\msbuild\client\client.csproj", "{1A96996B-B60D-473E-98F4-53F1EC589D68}"
Expand Down Expand Up @@ -132,30 +126,6 @@ Global
{F0BEAEC8-0D12-4196-A20D-2681EBDA15E0}.Release|x64.Build.0 = Release|Any CPU
{F0BEAEC8-0D12-4196-A20D-2681EBDA15E0}.Release|x86.ActiveCfg = Release|Any CPU
{F0BEAEC8-0D12-4196-A20D-2681EBDA15E0}.Release|x86.Build.0 = Release|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Debug|x64.ActiveCfg = Debug|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Debug|x64.Build.0 = Debug|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Debug|x86.ActiveCfg = Debug|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Debug|x86.Build.0 = Debug|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Release|Any CPU.Build.0 = Release|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Release|x64.ActiveCfg = Release|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Release|x64.Build.0 = Release|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Release|x86.ActiveCfg = Release|Any CPU
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0}.Release|x86.Build.0 = Release|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Debug|x64.ActiveCfg = Debug|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Debug|x64.Build.0 = Debug|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Debug|x86.ActiveCfg = Debug|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Debug|x86.Build.0 = Debug|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Release|Any CPU.Build.0 = Release|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Release|x64.ActiveCfg = Release|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Release|x64.Build.0 = Release|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Release|x86.ActiveCfg = Release|Any CPU
{46E5DF0C-DBEE-4874-A778-776A3640C0F3}.Release|x86.Build.0 = Release|Any CPU
{1A96996B-B60D-473E-98F4-53F1EC589D68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A96996B-B60D-473E-98F4-53F1EC589D68}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A96996B-B60D-473E-98F4-53F1EC589D68}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -452,9 +422,6 @@ Global
{86DCC48B-624F-441C-A78E-88BB224CF554} = {0B69E55F-3828-41DC-B50D-22A9E7BEE80B}
{E1D29995-B491-4FF2-ADB3-8C6DA3CBA15C} = {86DCC48B-624F-441C-A78E-88BB224CF554}
{F0BEAEC8-0D12-4196-A20D-2681EBDA15E0} = {86DCC48B-624F-441C-A78E-88BB224CF554}
{A1DE7220-B866-4216-A6A1-DA2B0D136A76} = {0B69E55F-3828-41DC-B50D-22A9E7BEE80B}
{ED0B9C9F-D2CF-4EEF-8A4D-5D8D5FC230E0} = {A1DE7220-B866-4216-A6A1-DA2B0D136A76}
{46E5DF0C-DBEE-4874-A778-776A3640C0F3} = {A1DE7220-B866-4216-A6A1-DA2B0D136A76}
{D04FD855-69A8-43E5-8F94-FB16B3D8BCA8} = {0B69E55F-3828-41DC-B50D-22A9E7BEE80B}
{1A96996B-B60D-473E-98F4-53F1EC589D68} = {D04FD855-69A8-43E5-8F94-FB16B3D8BCA8}
{E189473B-221E-41E2-AD04-01A2AA282FC5} = {D04FD855-69A8-43E5-8F94-FB16B3D8BCA8}
Expand Down
35 changes: 35 additions & 0 deletions csharp/Ice/Bidir/Bidir.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33122.133
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{BBF1199A-46A4-4AE9-AFFE-4D8DD59EB874}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{527EEA4D-77B9-4252-A2CD-C641A25CAD53}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FBDAF448-665A-4595-98D3-4538C56A666D}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BBF1199A-46A4-4AE9-AFFE-4D8DD59EB874}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BBF1199A-46A4-4AE9-AFFE-4D8DD59EB874}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BBF1199A-46A4-4AE9-AFFE-4D8DD59EB874}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BBF1199A-46A4-4AE9-AFFE-4D8DD59EB874}.Release|Any CPU.Build.0 = Release|Any CPU
{527EEA4D-77B9-4252-A2CD-C641A25CAD53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{527EEA4D-77B9-4252-A2CD-C641A25CAD53}.Debug|Any CPU.Build.0 = Debug|Any CPU
{527EEA4D-77B9-4252-A2CD-C641A25CAD53}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0B36F1E1-0592-4A15-9981-67BC4A653EC4}
EndGlobalSection
EndGlobal
20 changes: 20 additions & 0 deletions csharp/Ice/Bidir/Client/Client.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Copy the PDBs from the NuGet packages to get file names and line numbers in stack traces. -->
<CopyDebugSymbolFilesFromPackages>true</CopyDebugSymbolFilesFromPackages>
</PropertyGroup>
<ItemGroup>
<SliceCompile Include="../slice/AlarmClock.ice" />
<PackageReference Include="zeroc.ice.net" Version="3.8.0-alpha0" />
<PackageReference Include="zeroc.icebuilder.msbuild" Version="5.0.9" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
37 changes: 37 additions & 0 deletions csharp/Ice/Bidir/Client/MockAlarmClock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) ZeroC, Inc.

using EarlyRiser;

namespace Client;

/// <summary>MockAlarmClock is an Ice servant that implements Slice interface AlarmClock.</summary>
internal class MockAlarmClock : AlarmClockDisp_
{
/// <summary>Gets a task that completes when we return <see cref="ButtonPressed.Stop" /> from <see cref="Ring" />.
/// </summary>
public Task StopPressed => _tcs.Task;

// RunContinuationsAsynchronously because we don't want to continue Main in an Ice thread pool thread.
private readonly TaskCompletionSource _tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);

private bool _needMoreTime = true;

/// <inheritdoc/>
// Implements the abstract method Ring from the AlarmClockDisp_ class generated by the Slice compiler.
public override ButtonPressed Ring(string message, Ice.Current current)
{
Console.WriteLine($"Dispatching ring request {{ message = '{message}' }}");
if (_needMoreTime)
{
Console.WriteLine($"Returning {ButtonPressed.Snooze} to request more time.");
_needMoreTime = false; // we only snooze one time
return ButtonPressed.Snooze;
}
else
{
_tcs.TrySetResult();
Console.WriteLine($"Returning {ButtonPressed.Stop} to stop the alarm.");
return ButtonPressed.Stop;
}
}
}
31 changes: 31 additions & 0 deletions csharp/Ice/Bidir/Client/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) ZeroC, Inc.

// Slice module EarlyRiser in AlarmClock.ice maps to C# namespace EarlyRiser.
using EarlyRiser;

// Create an Ice communicator to initialize the Ice runtime.
using Ice.Communicator communicator = Ice.Util.initialize(ref args);

// Create an object adapter with no name and no configuration. This object adapter does not need to be activated.
Ice.ObjectAdapter adapter = communicator.createObjectAdapter("");

// Sets this object adapter as the default object adapter on the communicator.
communicator.setDefaultObjectAdapter(adapter);

// Register the MockAlarmClock servant with the adapter. The wake up service knows we use identity "alarmClock".
var mockAlarmClock = new Client.MockAlarmClock();
adapter.add(mockAlarmClock, Ice.Util.stringToIdentity("alarmClock"));

// Create a proxy to the wake-up service.
WakeUpServicePrx wakeUpService = WakeUpServicePrxHelper.createProxy(
communicator,
"wakeUpService:tcp -h localhost -p 4061");

// Schedule a wake-up call in 5 seconds. This call establishes the connection to the server; incoming requests over this
// connection are handled by the communicator's default object adapter.
await wakeUpService.WakeMeUpAsync(DateTime.Now.AddSeconds(5).ToUniversalTime().Ticks);
Console.WriteLine("Wake-up call scheduled, falling asleep...");

// Wait until the "stop" button is pressed on the mock alarm clock.
await mockAlarmClock.StopPressed;
Console.WriteLine("Stop button pressed, exiting...");
34 changes: 34 additions & 0 deletions csharp/Ice/Bidir/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Bidir

The Bidir demo illustrates how to send requests "the other way around", from a server to a client, by reusing the
connection established by the client to the server.

This demo is very similar to the [../Callback] demo: with the Callback demo, the server opens a connection to the
client, while with this demo, there is only one connection, from the client to the server:

```mermaid
flowchart LR
c[Client<br>hosts AlarmClock] --bidir connection--> s[Server:4061<br>hosts WakeUpService]
```

This is particularly useful when the client application is behind a firewall that does not allow incoming connections.

You can build the client and server applications with:

``` shell
dotnet build
```

First start the Server program:

```shell
cd Server
dotnet run
```

In a separate terminal, start the Client program:

```shell
cd Client
dotnet run
```
50 changes: 50 additions & 0 deletions csharp/Ice/Bidir/Server/BidirWakeUpService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) ZeroC, Inc.

using EarlyRiser;

namespace Server;

/// <summary>BidirWakeUpService is an Ice servant that implements Slice interface WakeUpService.</summary>
internal class BidirWakeUpService : WakeUpServiceDisp_
{
/// <inheritdoc/>
// Implements the abstract method WakeMeUp from the WakeUpServiceDisp_ class generated by the Slice compiler.
public override void WakeMeUp(long timeStamp, Ice.Current current)
{
var timeStampDateTime = new DateTime(timeStamp, DateTimeKind.Utc);
Console.WriteLine($"Dispatching wakeMeUp request {{ timeStamp = '{timeStampDateTime.ToLocalTime()}' }}");

Ice.Connection? connection = current.con; // The connection from the client to the server.
if (connection is null)
{
// Should never happen, but in case it does, the Ice runtime transmits this exception as an
// Ice.UnknownException.
throw new NotImplementedException("BidirWakeUpService does not support collocated calls");
}

// Create a proxy to the client's alarm clock. This connection-bound proxy is called a "fixed proxy".
AlarmClockPrx alarmClock = AlarmClockPrxHelper.uncheckedCast(
connection.createProxy(Ice.Util.stringToIdentity("alarmClock")));

// Start a background task to ring the alarm clock.
_ = Task.Run(async () =>
{
// Wait until the specified time.
TimeSpan delay = timeStampDateTime - DateTime.UtcNow;
if (delay > TimeSpan.Zero)
{
await Task.Delay(delay);
}

// First ring. This invocation reuses the connection established by the client.
ButtonPressed buttonPressed = await alarmClock.RingAsync("It's time to wake up!");

// Keep ringing every 10 seconds until the user presses the stop button.
while (buttonPressed is ButtonPressed.Snooze)
{
await Task.Delay(TimeSpan.FromSeconds(10));
buttonPressed = await alarmClock.RingAsync("No more snoozing!");
}
});
}
}
18 changes: 18 additions & 0 deletions csharp/Ice/Bidir/Server/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) ZeroC, Inc.

// Create an Ice communicator to initialize the Ice runtime.
using Ice.Communicator communicator = Ice.Util.initialize(ref args);

// Create an object adapter that listens for incoming requests and dispatches them to servants.
Ice.ObjectAdapter adapter = communicator.createObjectAdapterWithEndpoints("WakeUpAdapter", "tcp -p 4061");

// Register the BidirWakeUpService servant with the adapter.
adapter.add(new Server.BidirWakeUpService(), Ice.Util.stringToIdentity("wakeUpService"));

// Start dispatching requests.
adapter.activate();
Console.WriteLine("Listening on port 4061...");

// Wait until the user presses Ctrl+C.
await CancelKeyPressed;
Console.WriteLine("Caught Ctrl+C, exiting...");
21 changes: 21 additions & 0 deletions csharp/Ice/Bidir/Server/Server.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Copy the PDBs from the NuGet packages to get file names and line numbers in stack traces. -->
<CopyDebugSymbolFilesFromPackages>true</CopyDebugSymbolFilesFromPackages>
</PropertyGroup>
<ItemGroup>
<SliceCompile Include="../slice/AlarmClock.ice" />
<PackageReference Include="zeroc.ice.net" Version="3.8.0-alpha0" />
<PackageReference Include="zeroc.icebuilder.msbuild" Version="5.0.9" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<Compile Include="../../../Common/Program.CancelKeyPressed.cs" Link="Program.CancelKeyPressed.cs" />
</ItemGroup>
</Project>
29 changes: 29 additions & 0 deletions csharp/Ice/Bidir/slice/AlarmClock.ice
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) ZeroC, Inc.

#pragma once

module EarlyRiser
{
/// Indicates the button pressed when the alarm rang.
enum ButtonPressed { Snooze, Stop }

/// Represents a simple alarm clock. It's the "callback" in this demo, and it's implemented by the client.
interface AlarmClock
{
/// Rings the alarm clock.
/// @param message The message to display.
/// @return The button pressed by the user.
["cs:identifier:Ring"] // We prefer PascalCase for C# methods.
ButtonPressed ring(string message);
}

/// Represents the wake up service provided by the server.
interface WakeUpService
{
/// Schedules a call to the caller's {@link AlarmClock::ring} at the specified time.
/// @param timeStamp The time to ring the alarm clock. It's encoded as the number of ticks (100 nanoseconds)
/// since January 1, 0001 00:00:00 UTC in the Gregorian calendar.
["cs:identifier:WakeMeUp"] // We prefer PascalCase for C# methods.
void wakeMeUp(long timeStamp);
}
}
6 changes: 1 addition & 5 deletions csharp/Ice/Callback/slice/AlarmClock.ice
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@
module EarlyRiser
{
/// Indicates the button pressed when the alarm rang.
enum ButtonPressed
{
Snooze,
Stop
}
enum ButtonPressed { Snooze, Stop }

/// Represents a simple alarm clock. It's the "callback" in this demo, and it's implemented by the client.
interface AlarmClock
Expand Down
16 changes: 0 additions & 16 deletions csharp/Ice/bidir/Callback.ice

This file was deleted.

11 changes: 0 additions & 11 deletions csharp/Ice/bidir/CallbackReceiverI.cs

This file was deleted.

Loading

0 comments on commit a37cfbe

Please sign in to comment.