Skip to content

Commit 1a6b49a

Browse files
committed
Upgrade Orleans Chirper sample to dotnet 9
1 parent 0a82190 commit 1a6b49a

12 files changed

+73
-71
lines changed

orleans/Chirper/Chirper.Client/Chirper.Client.csproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net8.0</TargetFramework>
5+
<TargetFramework>net9.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
88
</PropertyGroup>
@@ -16,8 +16,8 @@
1616
</ItemGroup>
1717

1818
<ItemGroup>
19-
<PackageReference Include="Spectre.Console" Version="0.48.0" />
20-
<PackageReference Include="Spectre.Console.ImageSharp" Version="0.48.0" />
19+
<PackageReference Include="Spectre.Console" Version="0.49.1" />
20+
<PackageReference Include="Spectre.Console.ImageSharp" Version="0.49.1" />
2121
</ItemGroup>
2222

2323
<ItemGroup>

orleans/Chirper/Chirper.Client/ShellHostedService.cs

+4-13
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,12 @@
77

88
namespace Chirper.Client;
99

10-
public sealed partial class ShellHostedService : BackgroundService
10+
public sealed partial class ShellHostedService(IClusterClient client, IHostApplicationLifetime applicationLifetime) : BackgroundService
1111
{
12-
private readonly IClusterClient _client;
13-
private readonly IHostApplicationLifetime _applicationLifetime;
14-
1512
private ChirperConsoleViewer? _viewer;
1613
private IChirperViewer? _viewerRef;
1714
private IChirperAccount? _account;
1815

19-
public ShellHostedService(IClusterClient client, IHostApplicationLifetime applicationLifetime)
20-
{
21-
_client = client;
22-
_applicationLifetime = applicationLifetime;
23-
}
24-
2516
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
2617
{
2718
ShowHelp(true);
@@ -35,7 +26,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
3526
}
3627
else if (command is null or "/quit")
3728
{
38-
_applicationLifetime.StopApplication();
29+
applicationLifetime.StopApplication();
3930
return;
4031
}
4132
else if (command.StartsWith("/user "))
@@ -44,7 +35,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
4435
{
4536
await Unobserve();
4637
var username = match.Groups["username"].Value;
47-
_account = _client.GetGrain<IChirperAccount>(username);
38+
_account = client.GetGrain<IChirperAccount>(username);
4839

4940
AnsiConsole.MarkupLine("[bold grey][[[/][bold lime]✓[/][bold grey]]][/] The current user is now [navy]{0}[/]", username);
5041
}
@@ -121,7 +112,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
121112
if (_viewerRef is null)
122113
{
123114
_viewer = new ChirperConsoleViewer(_account.GetPrimaryKeyString());
124-
_viewerRef = _client.CreateObjectReference<IChirperViewer>(_viewer);
115+
_viewerRef = client.CreateObjectReference<IChirperViewer>(_viewer);
125116
}
126117

127118
await _account.SubscribeAsync(_viewerRef);
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFramework>net9.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.Orleans.Sdk" Version="8.0.0" />
10+
<PackageReference Include="Microsoft.Orleans.Sdk" Version="9.0.1" />
1111
</ItemGroup>
1212

1313
</Project>

orleans/Chirper/Chirper.Grains.Interfaces/EnumerableExtensions.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
namespace System.Collections.Generic;
1+
namespace System.Collections.Generic;
22

33
/// <summary>
4-
/// Helper extensions for enumerables.
4+
/// Helper extensions for <see cref="IEnumerable{T}">.
55
/// </summary>
66
public static class EnumerableExtensions
77
{

orleans/Chirper/Chirper.Grains.Interfaces/Models/ChirperMessage.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
namespace Chirper.Grains.Models;
1+
namespace Chirper.Grains.Models;
22

33
/// <summary>
44
/// Data object representing one Chirp message entry
55
/// </summary>
6-
[GenerateSerializer]
6+
[GenerateSerializer, Immutable]
77
public record class ChirperMessage(
88
/// <summary>
99
/// The message content for this chirp message entry.

orleans/Chirper/Chirper.Grains/Chirper.Grains.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFramework>net9.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.Orleans.Runtime" Version="8.0.0" />
10+
<PackageReference Include="Microsoft.Orleans.Runtime" Version="9.0.1" />
1111
</ItemGroup>
1212

1313
<ItemGroup>

orleans/Chirper/Chirper.Grains/ChirperAccount.cs

+35-42
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Collections.Immutable;
1+
using System.Collections.Immutable;
22
using Chirper.Grains.Models;
33
using Microsoft.Extensions.Logging;
44
using Orleans.Concurrency;
@@ -7,8 +7,12 @@
77
namespace Chirper.Grains;
88

99
[Reentrant]
10-
public sealed class ChirperAccount : Grain, IChirperAccount
10+
public sealed class ChirperAccount(
11+
[PersistentState(stateName: "account", storageName: "AccountState")] IPersistentState<ChirperAccountState> state,
12+
ILogger<ChirperAccount> logger) : Grain, IChirperAccount
1113
{
14+
private static string GrainType => nameof(ChirperAccount);
15+
1216
/// <summary>
1317
/// Size for the recently received message cache.
1418
/// </summary>
@@ -29,28 +33,17 @@ public sealed class ChirperAccount : Grain, IChirperAccount
2933
/// This list is not part of state and will not survive grain deactivation.
3034
/// </summary>
3135
private readonly HashSet<IChirperViewer> _viewers = new();
32-
private readonly ILogger<ChirperAccount> _logger;
33-
private readonly IPersistentState<ChirperAccountState> _state;
3436

3537
/// <summary>
3638
/// Allows state writing to happen in the background.
3739
/// </summary>
3840
private Task? _outstandingWriteStateOperation;
3941

40-
public ChirperAccount(
41-
[PersistentState(stateName: "account", storageName: "AccountState")] IPersistentState<ChirperAccountState> state,
42-
ILogger<ChirperAccount> logger)
43-
{
44-
_state = state;
45-
_logger = logger;
46-
}
47-
48-
private static string GrainType => nameof(ChirperAccount);
4942
private string GrainKey => this.GetPrimaryKeyString();
5043

5144
public override Task OnActivateAsync(CancellationToken _)
5245
{
53-
_logger.LogInformation("{GrainType} {GrainKey} activated.", GrainType, GrainKey);
46+
logger.LogInformation("{GrainType} {GrainKey} activated.", GrainType, GrainKey);
5447

5548
return Task.CompletedTask;
5649
}
@@ -59,49 +52,49 @@ public async ValueTask PublishMessageAsync(string message)
5952
{
6053
var chirp = CreateNewChirpMessage(message);
6154

62-
_logger.LogInformation("{GrainType} {GrainKey} publishing new chirp message '{Chirp}'.",
55+
logger.LogInformation("{GrainType} {GrainKey} publishing new chirp message '{Chirp}'.",
6356
GrainType, GrainKey, chirp);
6457

65-
_state.State.MyPublishedMessages.Enqueue(chirp);
58+
state.State.MyPublishedMessages.Enqueue(chirp);
6659

67-
while (_state.State.MyPublishedMessages.Count > PublishedMessagesCacheSize)
60+
while (state.State.MyPublishedMessages.Count > PublishedMessagesCacheSize)
6861
{
69-
_state.State.MyPublishedMessages.Dequeue();
62+
state.State.MyPublishedMessages.Dequeue();
7063
}
7164

7265
await WriteStateAsync();
7366

7467
// notify viewers of new message
75-
_logger.LogInformation("{GrainType} {GrainKey} sending new chirp message to {ViewerCount} viewers.",
68+
logger.LogInformation("{GrainType} {GrainKey} sending new chirp message to {ViewerCount} viewers.",
7669
GrainType, GrainKey, _viewers.Count);
7770

7871
_viewers.ForEach(_ => _.NewChirp(chirp));
7972

8073
// notify followers of a new message
81-
_logger.LogInformation("{GrainType} {GrainKey} sending new chirp message to {FollowerCount} followers.",
82-
GrainType, GrainKey, _state.State.Followers.Count);
74+
logger.LogInformation("{GrainType} {GrainKey} sending new chirp message to {FollowerCount} followers.",
75+
GrainType, GrainKey, state.State.Followers.Count);
8376

84-
await Task.WhenAll(_state.State.Followers.Values.Select(_ => _.NewChirpAsync(chirp)).ToArray());
77+
await Task.WhenAll(state.State.Followers.Values.Select(_ => _.NewChirpAsync(chirp)).ToArray());
8578
}
8679

8780
public ValueTask<ImmutableList<ChirperMessage>> GetReceivedMessagesAsync(int number, int start)
8881
{
8982
if (start < 0) start = 0;
90-
if (start + number > _state.State.RecentReceivedMessages.Count)
83+
if (start + number > state.State.RecentReceivedMessages.Count)
9184
{
92-
number = _state.State.RecentReceivedMessages.Count - start;
85+
number = state.State.RecentReceivedMessages.Count - start;
9386
}
9487

9588
return ValueTask.FromResult(
96-
_state.State.RecentReceivedMessages
89+
state.State.RecentReceivedMessages
9790
.Skip(start)
9891
.Take(number)
9992
.ToImmutableList());
10093
}
10194

10295
public async ValueTask FollowUserIdAsync(string username)
10396
{
104-
_logger.LogInformation(
97+
logger.LogInformation(
10598
"{GrainType} {UserName} > FollowUserName({TargetUserName}).",
10699
GrainType,
107100
GrainKey,
@@ -111,7 +104,7 @@ public async ValueTask FollowUserIdAsync(string username)
111104

112105
await userToFollow.AddFollowerAsync(GrainKey, this.AsReference<IChirperSubscriber>());
113106

114-
_state.State.Subscriptions[username] = userToFollow;
107+
state.State.Subscriptions[username] = userToFollow;
115108

116109
await WriteStateAsync();
117110

@@ -121,7 +114,7 @@ public async ValueTask FollowUserIdAsync(string username)
121114

122115
public async ValueTask UnfollowUserIdAsync(string username)
123116
{
124-
_logger.LogInformation(
117+
logger.LogInformation(
125118
"{GrainType} {GrainKey} > UnfollowUserName({TargetUserName}).",
126119
GrainType,
127120
GrainKey,
@@ -132,7 +125,7 @@ await GrainFactory.GetGrain<IChirperPublisher>(username)
132125
.RemoveFollowerAsync(GrainKey);
133126

134127
// remove this publisher from the subscriptions list
135-
_state.State.Subscriptions.Remove(username);
128+
state.State.Subscriptions.Remove(username);
136129

137130
// save now
138131
await WriteStateAsync();
@@ -142,10 +135,10 @@ await GrainFactory.GetGrain<IChirperPublisher>(username)
142135
}
143136

144137
public ValueTask<ImmutableList<string>> GetFollowingListAsync() =>
145-
ValueTask.FromResult(_state.State.Subscriptions.Keys.ToImmutableList());
138+
ValueTask.FromResult(state.State.Subscriptions.Keys.ToImmutableList());
146139

147140
public ValueTask<ImmutableList<string>> GetFollowersListAsync() =>
148-
ValueTask.FromResult(_state.State.Followers.Keys.ToImmutableList());
141+
ValueTask.FromResult(state.State.Followers.Keys.ToImmutableList());
149142

150143
public ValueTask SubscribeAsync(IChirperViewer viewer)
151144
{
@@ -162,50 +155,50 @@ public ValueTask UnsubscribeAsync(IChirperViewer viewer)
162155
public ValueTask<ImmutableList<ChirperMessage>> GetPublishedMessagesAsync(int number, int start)
163156
{
164157
if (start < 0) start = 0;
165-
if (start + number > _state.State.MyPublishedMessages.Count)
158+
if (start + number > state.State.MyPublishedMessages.Count)
166159
{
167-
number = _state.State.MyPublishedMessages.Count - start;
160+
number = state.State.MyPublishedMessages.Count - start;
168161
}
169162
return ValueTask.FromResult(
170-
_state.State.MyPublishedMessages
163+
state.State.MyPublishedMessages
171164
.Skip(start)
172165
.Take(number)
173166
.ToImmutableList());
174167
}
175168

176169
public async ValueTask AddFollowerAsync(string username, IChirperSubscriber follower)
177170
{
178-
_state.State.Followers[username] = follower;
171+
state.State.Followers[username] = follower;
179172
await WriteStateAsync();
180173
_viewers.ForEach(cv => cv.NewFollower(username));
181174
}
182175

183176
public ValueTask RemoveFollowerAsync(string username)
184177
{
185-
_state.State.Followers.Remove(username);
178+
state.State.Followers.Remove(username);
186179
return WriteStateAsync();
187180
}
188181

189182
public async Task NewChirpAsync(ChirperMessage chirp)
190183
{
191-
_logger.LogInformation(
184+
logger.LogInformation(
192185
"{GrainType} {GrainKey} received chirp message = {Chirp}",
193186
GrainType,
194187
GrainKey,
195188
chirp);
196189

197-
_state.State.RecentReceivedMessages.Enqueue(chirp);
190+
state.State.RecentReceivedMessages.Enqueue(chirp);
198191

199192
// only relevant when not using fixed queue
200-
while (_state.State.RecentReceivedMessages.Count > ReceivedMessagesCacheSize) // to keep not more than the max number of messages
193+
while (state.State.RecentReceivedMessages.Count > ReceivedMessagesCacheSize) // to keep not more than the max number of messages
201194
{
202-
_state.State.RecentReceivedMessages.Dequeue();
195+
state.State.RecentReceivedMessages.Dequeue();
203196
}
204197

205198
await WriteStateAsync();
206199

207200
// notify any viewers that a new chirp has been received
208-
_logger.LogInformation(
201+
logger.LogInformation(
209202
"{GrainType} {GrainKey} sending received chirp message to {ViewerCount} viewers",
210203
GrainType,
211204
GrainKey,
@@ -246,7 +239,7 @@ private async ValueTask WriteStateAsync()
246239
if (_outstandingWriteStateOperation is null)
247240
{
248241
// If after the initial write is completed, no other request initiated a new write operation, do it now.
249-
currentWriteStateOperation = _state.WriteStateAsync();
242+
currentWriteStateOperation = state.WriteStateAsync();
250243
_outstandingWriteStateOperation = currentWriteStateOperation;
251244
}
252245
else

orleans/Chirper/Chirper.Grains/ChirperAccountState.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Chirper.Grains.Models;
1+
using Chirper.Grains.Models;
22

33
namespace Chirper.Grains;
44

orleans/Chirper/Chirper.Server/Chirper.Server.csproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net8.0</TargetFramework>
5+
<TargetFramework>net9.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Microsoft.Orleans.Server" Version="8.0.0" />
12-
<PackageReference Include="OrleansDashboard" Version="8.0.0" />
11+
<PackageReference Include="Microsoft.Orleans.Server" Version="9.0.1" />
12+
<PackageReference Include="OrleansDashboard" Version="8.2.0" />
1313
</ItemGroup>
1414

1515
<ItemGroup>

orleans/Chirper/Chirper.sln

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ EndProject
99
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chirper.Server", "Chirper.Server\Chirper.Server.csproj", "{2C967379-D025-4EBB-96C0-1A4C6CBE4B4B}"
1010
EndProject
1111
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chirper.Client", "Chirper.Client\Chirper.Client.csproj", "{3BE53D35-938D-47D8-B135-501786B145DC}"
12+
ProjectSection(ProjectDependencies) = postProject
13+
{2C967379-D025-4EBB-96C0-1A4C6CBE4B4B} = {2C967379-D025-4EBB-96C0-1A4C6CBE4B4B}
14+
EndProjectSection
1215
EndProject
1316
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1223A865-0D72-4BF7-8FCD-016A48F3EC68}"
1417
ProjectSection(SolutionItems) = preProject

orleans/Chirper/Chirper.slnLaunch

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[
2+
{
3+
"Name": "Server + Client",
4+
"Projects": [
5+
{
6+
"Path": "Chirper.Client\\Chirper.Client.csproj",
7+
"Action": "Start"
8+
},
9+
{
10+
"Path": "Chirper.Server\\Chirper.Server.csproj",
11+
"Action": "Start"
12+
}
13+
]
14+
}
15+
]

0 commit comments

Comments
 (0)