Skip to content

Commit b71b0e6

Browse files
author
GitHub Copilot
committed
Update multi-tenant RavenDB samples to support RavenDB upgrade
1 parent 17d79c5 commit b71b0e6

20 files changed

+361
-11
lines changed

samples/multi-tenant/ravendb/Core_10/Receiver/Receiver.csproj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFramework>net10.0</TargetFramework>
3+
<TargetFrameworks>net9.0;net8.0</TargetFrameworks>
44
<OutputType>Exe</OutputType>
5-
<LangVersion>preview</LangVersion>
5+
<LangVersion>12.0</LangVersion>
66
<ImplicitUsings>enable</ImplicitUsings>
77
</PropertyGroup>
88
<ItemGroup>
9-
<PackageReference Include="NServiceBus.Extensions.Hosting" Version="4.0.0-alpha.1" />
10-
<PackageReference Include="NServiceBus.RavenDB" Version="10.0.0-alpha.1" />
11-
<PackageReference Include="RavenDB.Client" Version="5.*" />
9+
<PackageReference Include="NServiceBus.Extensions.Hosting" Version="3.0.1" />
10+
<PackageReference Include="NServiceBus.RavenDB" Version="10.0.0" />
11+
<PackageReference Include="RavenDB.Client" Version="6.*" />
1212
</ItemGroup>
1313
<ItemGroup>
1414
<ProjectReference Include="..\Shared\Shared.csproj" />

samples/multi-tenant/ravendb/Core_10/Sender/Sender.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFramework>net10.0</TargetFramework>
3+
<TargetFrameworks>net9.0;net8.0</TargetFrameworks>
44
<OutputType>Exe</OutputType>
5-
<LangVersion>preview</LangVersion>
5+
<LangVersion>12.0</LangVersion>
66
<ImplicitUsings>enable</ImplicitUsings>
77
</PropertyGroup>
88
<ItemGroup>
9-
<PackageReference Include="NServiceBus.Extensions.Hosting" Version="4.0.0-alpha.1" />
9+
<PackageReference Include="NServiceBus.Extensions.Hosting" Version="3.0.1" />
1010
</ItemGroup>
1111
<ItemGroup>
1212
<ProjectReference Include="..\Shared\Shared.csproj" />
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFramework>net10.0</TargetFramework>
4-
<LangVersion>preview</LangVersion>
3+
<TargetFrameworks>net9.0;net8.0</TargetFrameworks>
4+
<LangVersion>12.0</LangVersion>
55
<ImplicitUsings>enable</ImplicitUsings>
66
</PropertyGroup>
77
<ItemGroup>
8-
<PackageReference Include="NServiceBus" Version="10.0.0-alpha.1" />
8+
<PackageReference Include="NServiceBus" Version="9.*" />
99
</ItemGroup>
1010
</Project>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.29728.190
5+
MinimumVisualStudioVersion = 15.0.26730.12
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sender", "Sender\Sender.csproj", "{B58159EB-9EFD-443F-A80E-8C90B0AF1907}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Receiver", "Receiver\Receiver.csproj", "{1EEC6A8C-DB3C-4F20-93CE-5004BF16AD7F}"
9+
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{BF92D39E-42F6-44E9-8F7F-819993235621}"
11+
EndProject
12+
Global
13+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
14+
Debug|Any CPU = Debug|Any CPU
15+
EndGlobalSection
16+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
17+
{B58159EB-9EFD-443F-A80E-8C90B0AF1907}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18+
{B58159EB-9EFD-443F-A80E-8C90B0AF1907}.Debug|Any CPU.Build.0 = Debug|Any CPU
19+
{1EEC6A8C-DB3C-4F20-93CE-5004BF16AD7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20+
{1EEC6A8C-DB3C-4F20-93CE-5004BF16AD7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
21+
{BF92D39E-42F6-44E9-8F7F-819993235621}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22+
{BF92D39E-42F6-44E9-8F7F-819993235621}.Debug|Any CPU.Build.0 = Debug|Any CPU
23+
EndGlobalSection
24+
GlobalSection(SolutionProperties) = preSolution
25+
HideSolutionNode = FALSE
26+
EndGlobalSection
27+
EndGlobal
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public class Order
2+
{
3+
public string Id { get; set; }
4+
public decimal Value { get; set; }
5+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Microsoft.Extensions.Logging;
2+
3+
public class OrderLifecycleSaga(ILogger<OrderLifecycleSaga> logger) :
4+
Saga<OrderLifecycleSagaData>,
5+
IAmStartedByMessages<OrderSubmitted>,
6+
IHandleTimeouts<OrderTimeout>
7+
{
8+
9+
public async Task Handle(OrderSubmitted message, IMessageHandlerContext context)
10+
{
11+
Data.OrderId = message.OrderId;
12+
13+
await RequestTimeout<OrderTimeout>(context, TimeSpan.FromSeconds(5));
14+
}
15+
16+
public Task Timeout(OrderTimeout state, IMessageHandlerContext context)
17+
{
18+
logger.LogInformation("Order {OrderId} has timed out", Data.OrderId);
19+
return Task.CompletedTask;
20+
}
21+
22+
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<OrderLifecycleSagaData> mapper)
23+
{
24+
mapper.MapSaga(saga => saga.OrderId)
25+
.ToMessage<OrderSubmitted>(m => m.OrderId);
26+
}
27+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public class OrderLifecycleSagaData :
2+
ContainSagaData
3+
{
4+
public string OrderId { get; set; }
5+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using Microsoft.Extensions.Logging;
2+
3+
public class OrderSubmittedHandler(ILogger<OrderSubmittedHandler> logger) :
4+
IHandleMessages<OrderSubmitted>
5+
{
6+
public async Task Handle(OrderSubmitted message, IMessageHandlerContext context)
7+
{
8+
logger.LogInformation("Order {OrderId} worth {Value} submitted", message.OrderId, message.Value);
9+
10+
var order = new Order
11+
{
12+
Id = message.OrderId,
13+
Value = message.Value
14+
};
15+
var session = context.SynchronizedStorageSession.RavenSession();
16+
17+
await session.StoreAsync(order, context.CancellationToken);
18+
19+
var orderAccepted = new OrderAccepted
20+
{
21+
OrderId = message.OrderId,
22+
};
23+
await context.Reply(orderAccepted);
24+
}
25+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public class OrderTimeout
2+
{
3+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using Microsoft.Extensions.Hosting;
2+
using Raven.Client.Documents;
3+
using Raven.Client.Documents.Operations;
4+
using Raven.Client.Exceptions;
5+
using Raven.Client.Exceptions.Database;
6+
using Raven.Client.ServerWide;
7+
using Raven.Client.ServerWide.Operations;
8+
9+
Console.Title = "Receiver";
10+
var builder = Host.CreateApplicationBuilder(args);
11+
12+
var endpointConfiguration = new EndpointConfiguration("Samples.MultiTenant.Receiver");
13+
14+
using var documentStore = new DocumentStore
15+
{
16+
Urls = new[] { "http://localhost:8080" },
17+
Database = "MultiTenantSamples",
18+
};
19+
20+
documentStore.Initialize();
21+
await CreateDatabase(documentStore);
22+
await CreateTenantDatabase(documentStore, "A");
23+
await CreateTenantDatabase(documentStore, "B");
24+
25+
var persistence = endpointConfiguration.UsePersistence<RavenDBPersistence>();
26+
persistence.SetDefaultDocumentStore(documentStore);
27+
28+
var transport = new LearningTransport
29+
{
30+
TransportTransactionMode = TransportTransactionMode.ReceiveOnly
31+
};
32+
endpointConfiguration.UseTransport(transport);
33+
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
34+
35+
var outbox = endpointConfiguration.EnableOutbox();
36+
37+
#region DetermineDatabase
38+
39+
persistence.SetMessageToDatabaseMappingConvention(headers =>
40+
{
41+
return headers.TryGetValue("tenant_id", out var tenantId)
42+
? $"MultiTenantSamples-{tenantId}"
43+
: "MultiTenantSamples";
44+
});
45+
46+
#endregion
47+
48+
var pipeline = endpointConfiguration.Pipeline;
49+
50+
pipeline.Register(new StoreTenantIdBehavior(), "Stores tenant ID in the session");
51+
pipeline.Register(new PropagateTenantIdBehavior(), "Propagates tenant ID to outgoing messages");
52+
53+
builder.UseNServiceBus(endpointConfiguration);
54+
await builder.Build().RunAsync();
55+
56+
static async Task CreateDatabase(IDocumentStore documentStore)
57+
{
58+
try
59+
{
60+
await documentStore.Maintenance.ForDatabase(documentStore.Database).SendAsync(new GetStatisticsOperation());
61+
}
62+
catch (DatabaseDoesNotExistException)
63+
{
64+
try
65+
{
66+
await documentStore.Maintenance.Server.SendAsync(new CreateDatabaseOperation(new DatabaseRecord(documentStore.Database)));
67+
}
68+
catch (ConcurrencyException)
69+
{
70+
// This exception is thrown if the database already exists.
71+
// We can safely ignore it, as our goal is simply to ensure it exists.
72+
}
73+
}
74+
}
75+
76+
static async Task CreateTenantDatabase(DocumentStore documentStore, string tenant)
77+
{
78+
#region CreateDatabase
79+
80+
var id = $"MultiTenantSamples-{tenant}";
81+
try
82+
{
83+
await documentStore.Maintenance.ForDatabase(id).SendAsync(new GetStatisticsOperation());
84+
}
85+
catch (DatabaseDoesNotExistException)
86+
{
87+
try
88+
{
89+
await documentStore.Maintenance.Server.SendAsync(new CreateDatabaseOperation(new DatabaseRecord(id)));
90+
}
91+
catch (ConcurrencyException)
92+
{
93+
// This exception is thrown if the database already exists.
94+
// We can safely ignore it, as our goal is simply to ensure it exists.
95+
}
96+
}
97+
98+
#endregion
99+
}

0 commit comments

Comments
 (0)