Skip to content

Commit 8eec086

Browse files
New Forwarder demo in C# (#283)
1 parent 4df0a6d commit 8eec086

File tree

11 files changed

+284
-0
lines changed

11 files changed

+284
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<Project Sdk="Microsoft.NET.Sdk">
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<OutputType>Exe</OutputType>
6+
<Nullable>enable</Nullable>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<!-- Copy the PDBs from the NuGet packages to get file names and line numbers in stack traces. -->
9+
<CopyDebugSymbolFilesFromPackages>true</CopyDebugSymbolFilesFromPackages>
10+
</PropertyGroup>
11+
<ItemGroup>
12+
<SliceCompile Include="../slice/Greeter.ice" />
13+
<PackageReference Include="zeroc.ice.net" Version="3.8.0-alpha0" />
14+
<PackageReference Include="zeroc.icebuilder.msbuild" Version="5.0.9" />
15+
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
16+
<PrivateAssets>all</PrivateAssets>
17+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
18+
</PackageReference>
19+
</ItemGroup>
20+
</Project>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) ZeroC, Inc.
2+
3+
// Slice module VisitorCenter in Greeter.ice maps to C# namespace VisitorCenter.
4+
using VisitorCenter;
5+
6+
// Create an Ice communicator to initialize the Ice runtime. The communicator is disposed before the program exits.
7+
using Ice.Communicator communicator = Ice.Util.initialize(ref args);
8+
9+
// We create a Greeter proxy for a Greeter object in the Forwarder server (port 10000).
10+
GreeterPrx greeter = GreeterPrxHelper.createProxy(communicator, "greeter:tcp -h localhost -p 10000");
11+
12+
// Send a request to the remote object and get the response.
13+
string greeting = await greeter.GreetAsync(Environment.UserName);
14+
15+
Console.WriteLine(greeting);

csharp/Ice/Forwarder/Forwarder.sln

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.4.33122.133
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{BBF1199A-46A4-4AE9-AFFE-4D8DD59EB874}"
7+
EndProject
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{527EEA4D-77B9-4252-A2CD-C641A25CAD53}"
9+
EndProject
10+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FBDAF448-665A-4595-98D3-4538C56A666D}"
11+
ProjectSection(SolutionItems) = preProject
12+
README.md = README.md
13+
EndProjectSection
14+
EndProject
15+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ForwardingServer", "ForwardingServer\ForwardingServer.csproj", "{1A6E0164-8AED-45B8-B07A-C1DD1CF5160E}"
16+
EndProject
17+
Global
18+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
19+
Debug|Any CPU = Debug|Any CPU
20+
Release|Any CPU = Release|Any CPU
21+
EndGlobalSection
22+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
23+
{BBF1199A-46A4-4AE9-AFFE-4D8DD59EB874}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24+
{BBF1199A-46A4-4AE9-AFFE-4D8DD59EB874}.Debug|Any CPU.Build.0 = Debug|Any CPU
25+
{BBF1199A-46A4-4AE9-AFFE-4D8DD59EB874}.Release|Any CPU.ActiveCfg = Release|Any CPU
26+
{BBF1199A-46A4-4AE9-AFFE-4D8DD59EB874}.Release|Any CPU.Build.0 = Release|Any CPU
27+
{527EEA4D-77B9-4252-A2CD-C641A25CAD53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28+
{527EEA4D-77B9-4252-A2CD-C641A25CAD53}.Debug|Any CPU.Build.0 = Debug|Any CPU
29+
{527EEA4D-77B9-4252-A2CD-C641A25CAD53}.Release|Any CPU.ActiveCfg = Release|Any CPU
30+
{527EEA4D-77B9-4252-A2CD-C641A25CAD53}.Release|Any CPU.Build.0 = Release|Any CPU
31+
{1A6E0164-8AED-45B8-B07A-C1DD1CF5160E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32+
{1A6E0164-8AED-45B8-B07A-C1DD1CF5160E}.Debug|Any CPU.Build.0 = Debug|Any CPU
33+
{1A6E0164-8AED-45B8-B07A-C1DD1CF5160E}.Release|Any CPU.ActiveCfg = Release|Any CPU
34+
{1A6E0164-8AED-45B8-B07A-C1DD1CF5160E}.Release|Any CPU.Build.0 = Release|Any CPU
35+
EndGlobalSection
36+
GlobalSection(SolutionProperties) = preSolution
37+
HideSolutionNode = FALSE
38+
EndGlobalSection
39+
GlobalSection(ExtensibilityGlobals) = postSolution
40+
SolutionGuid = {0B36F1E1-0592-4A15-9981-67BC4A653EC4}
41+
EndGlobalSection
42+
EndGlobal
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) ZeroC, Inc.
2+
3+
using Ice;
4+
5+
namespace ForwardingServer;
6+
7+
/// <summary>Forwarder is an Ice servant that implements Ice.Object by forwarding all requests it receives to a remote
8+
/// Ice object.</summary>
9+
internal class Forwarder : Ice.Object
10+
{
11+
// A template for the target proxy.
12+
private readonly Ice.ObjectPrx _targetTemplate;
13+
14+
// Implements abstract method dispatchAsync defined on Ice.Object.
15+
public async ValueTask<OutgoingResponse> dispatchAsync(IncomingRequest request)
16+
{
17+
// Change the identity and facet of _target to match the identity and facet in the incoming request.
18+
Ice.ObjectPrx target = _targetTemplate.ice_identity(request.current.id).ice_facet(request.current.facet);
19+
20+
if (request.current.requestId == 0)
21+
{
22+
// The incoming request is one-way, so we reconfigure target to be one-way.
23+
target = target.ice_oneway();
24+
}
25+
26+
// Make the invocation asynchronously. If `ice_invokeAsync` throws an Ice.LocalException that cannot be
27+
// marshaled (such as Ice.ConnectionRefusedException), the object adapter that calls `dispatchAsync` converts it
28+
// into an Ice.UnknownLocalException.
29+
(bool ok, byte[] encapsulation) = await target.ice_invokeAsync(
30+
request.current.operation,
31+
request.current.mode,
32+
request.inputStream.readEncapsulation(out EncodingVersion _), // the in-parameters encapsulation
33+
request.current.ctx);
34+
35+
// Create and return the OutgoingResponse.
36+
return request.current.createOutgoingResponse(ok, encapsulation);
37+
}
38+
39+
/// <summary>Constructs a forwarder.</summary>
40+
/// <param name="targetTemplate">A template for the target proxy.</param>
41+
internal Forwarder(Ice.ObjectPrx targetTemplate) => _targetTemplate = targetTemplate.ice_twoway();
42+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<Project Sdk="Microsoft.NET.Sdk">
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<OutputType>Exe</OutputType>
6+
<Nullable>enable</Nullable>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<!-- Copy the PDBs from the NuGet packages to get file names and line numbers in stack traces. -->
9+
<CopyDebugSymbolFilesFromPackages>true</CopyDebugSymbolFilesFromPackages>
10+
</PropertyGroup>
11+
<ItemGroup>
12+
<PackageReference Include="zeroc.ice.net" Version="3.8.0-alpha0" />
13+
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
14+
<PrivateAssets>all</PrivateAssets>
15+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
16+
</PackageReference>
17+
<Compile Include="../../../Common/Program.CancelKeyPressed.cs" Link="Program.CancelKeyPressed.cs" />
18+
</ItemGroup>
19+
</Project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) ZeroC, Inc.
2+
3+
using ForwardingServer;
4+
5+
// Create an Ice communicator to initialize the Ice runtime. The communicator is disposed before the program exits.
6+
using Ice.Communicator communicator = Ice.Util.initialize(ref args);
7+
8+
// Create an object adapter that listens for incoming requests and dispatches them to servants.
9+
Ice.ObjectAdapter adapter = communicator.createObjectAdapterWithEndpoints("ForwarderAdapter", "tcp -p 10000");
10+
11+
// Create a target proxy template, with a dummy identity.
12+
Ice.ObjectPrx targetTemplate = Ice.ObjectPrxHelper.createProxy(communicator, "dummy:tcp -h localhost -p 4061");
13+
14+
// Register the Forwarder servant as default servant with the object adapter. The empty category means this default
15+
// servant receives requests to all Ice objects.
16+
adapter.addDefaultServant(new Forwarder(targetTemplate), category: "");
17+
18+
// Start dispatching requests.
19+
adapter.activate();
20+
Console.WriteLine("Listening on port 10000...");
21+
22+
// Wait until the user presses Ctrl+C.
23+
await CancelKeyPressed;
24+
Console.WriteLine("Caught Ctrl+C, exiting...");

csharp/Ice/Forwarder/README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Forwarder
2+
3+
The Forwarder demo shows how to write a servant that forwards all requests it receives to another remote Ice object,
4+
as-is.
5+
6+
The core of this demo is the generic Forwarding server. This server listens on tcp port 10000 and forwards all
7+
requests to tcp port 4061 on the same host.
8+
9+
The demo also includes a Greeter client and server; these are the usual Greeter client and server, except the client
10+
is configured to use port 10000:
11+
12+
```mermaid
13+
flowchart LR
14+
c[Greeter Client] --> f[Forwarding Server:10000] --> s[Greeter Server:4061]
15+
```
16+
17+
The Forwarding server is generic can be inserted between any client and server. In particular, the Forwarding server
18+
does not use any Slice generated code.
19+
20+
You can build the demo with:
21+
22+
``` shell
23+
dotnet build
24+
```
25+
26+
Then, start the Forwarding server and Greeter server in separate terminals:
27+
28+
```shell
29+
cd Server
30+
dotnet run --Ice.Trace.Dispatch
31+
```
32+
33+
```shell
34+
cd ForwardingServer
35+
dotnet run --Ice.Trace.Dispatch
36+
```
37+
38+
In a third terminal, start the Client program:
39+
40+
```shell
41+
cd Client
42+
dotnet run --Ice.Trace.Network
43+
```
44+
45+
> [!NOTE]
46+
> The `--Ice.Trace` command-line options are optional: they turn-on tracing (logging) for request dispatches
47+
> (`--Ice.Trace.Dispatch`) and connection establishment/closure (`--Ice.Trace.Network`) and help you follow the call
48+
> flow.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) ZeroC, Inc.
2+
3+
using VisitorCenter;
4+
5+
namespace Server;
6+
7+
/// <summary>Chatbot is an Ice servant that implements Slice interface Greeter.</summary>
8+
internal class Chatbot : GreeterDisp_
9+
{
10+
// Implements the abstract method Greet from the GreeterDisp_ class generated by the Slice compiler.
11+
// This variant is the synchronous implementation.
12+
public override string Greet(string name, Ice.Current current)
13+
{
14+
Console.WriteLine($"Dispatching greet request {{ name = '{name}' }}");
15+
return $"Hello, {name}!";
16+
}
17+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) ZeroC, Inc.
2+
3+
using Server;
4+
5+
// Create an Ice communicator to initialize the Ice runtime. The communicator is disposed before the program exits.
6+
using Ice.Communicator communicator = Ice.Util.initialize(ref args);
7+
8+
// Create an object adapter that listens for incoming requests and dispatches them to servants.
9+
Ice.ObjectAdapter adapter = communicator.createObjectAdapterWithEndpoints("GreeterAdapter", "tcp -p 4061");
10+
11+
// Register the Chatbot servant with the adapter.
12+
adapter.add(new Chatbot(), Ice.Util.stringToIdentity("greeter"));
13+
14+
// Start dispatching requests.
15+
adapter.activate();
16+
Console.WriteLine("Listening on port 4061...");
17+
18+
// Wait until the user presses Ctrl+C.
19+
await CancelKeyPressed;
20+
Console.WriteLine("Caught Ctrl+C, exiting...");
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<Project Sdk="Microsoft.NET.Sdk">
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<OutputType>Exe</OutputType>
6+
<Nullable>enable</Nullable>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<!-- Copy the PDBs from the NuGet packages to get file names and line numbers in stack traces. -->
9+
<CopyDebugSymbolFilesFromPackages>true</CopyDebugSymbolFilesFromPackages>
10+
</PropertyGroup>
11+
<ItemGroup>
12+
<SliceCompile Include="../slice/Greeter.ice" />
13+
<PackageReference Include="zeroc.ice.net" Version="3.8.0-alpha0" />
14+
<PackageReference Include="zeroc.icebuilder.msbuild" Version="5.0.9" />
15+
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
16+
<PrivateAssets>all</PrivateAssets>
17+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
18+
</PackageReference>
19+
<Compile Include="../../../Common/Program.CancelKeyPressed.cs" Link="Program.CancelKeyPressed.cs" />
20+
</ItemGroup>
21+
</Project>

0 commit comments

Comments
 (0)