Skip to content

Commit c6085d8

Browse files
Fix ref struct scan for sagas (#7187) (#7193)
* Prevent saga conventions from throwing on ref struct * Better test * Tweaks --------- Co-authored-by: Mike Minutillo <[email protected]>
1 parent 4ab258c commit c6085d8

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
namespace NServiceBus.AcceptanceTests.Core.Conventions;
2+
3+
using System;
4+
using System.Threading.Tasks;
5+
using AcceptanceTesting;
6+
using EndpointTemplates;
7+
using NServiceBus.AcceptanceTesting.Customization;
8+
using NUnit.Framework;
9+
10+
public class When_scanning_an_assembly_containing_a_ref_struct_and_sagas_enabled : NServiceBusAcceptanceTest
11+
{
12+
[Test]
13+
public void It_should_not_throw_an_exception()
14+
=> Assert.DoesNotThrowAsync(
15+
() => Scenario.Define<ScenarioContext>()
16+
.WithEndpoint<EndpointWithASaga>()
17+
.Run()
18+
);
19+
20+
// HINT: This will get picked up by the AssemblyRouteSource created by the routing call below
21+
// Even though it is not a message type, it is still checked by passing it to conventions.
22+
// The conventions added by Sagas were throwing an exception when passed a ref struct.
23+
// See https://github.com/Particular/NServiceBus/issues/7179 for details.
24+
ref struct RefStruct { }
25+
26+
class EndpointWithASaga : EndpointConfigurationBuilder
27+
{
28+
public EndpointWithASaga() => EndpointSetup<DefaultServer>(cfg => cfg
29+
.ConfigureRouting()
30+
.RouteToEndpoint(
31+
typeof(RefStruct).Assembly,
32+
Conventions.EndpointNamingConvention(typeof(EndpointWithASaga))
33+
)
34+
);
35+
36+
class RealSagaToSetUpConventions : Saga<RealSagaToSetUpConventions.RealSagaToSetUpConventionsSagaData>, IAmStartedByMessages<SomeMessage>
37+
{
38+
public Task Handle(SomeMessage message, IMessageHandlerContext context) => Task.CompletedTask;
39+
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<RealSagaToSetUpConventionsSagaData> mapper)
40+
=> mapper.MapSaga(saga => saga.BusinessId).ToMessage<SomeMessage>(msg => msg.BusinessId);
41+
42+
public class RealSagaToSetUpConventionsSagaData : ContainSagaData
43+
{
44+
public virtual Guid BusinessId { get; set; }
45+
}
46+
}
47+
}
48+
49+
public class SomeMessage : IMessage
50+
{
51+
public Guid BusinessId { get; set; }
52+
}
53+
}

src/NServiceBus.Core/Sagas/Sagas.cs

+7
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ static bool IsCompatible(Type t, Type source)
104104

105105
static bool IsTypeATimeoutHandledByAnySaga(Type type, IEnumerable<Type> sagas)
106106
{
107+
// MakeGenericType() throws an exception if passed a ref struct type
108+
// Messages cannot be ref struct types
109+
if (type.IsByRefLike)
110+
{
111+
return false;
112+
}
113+
107114
var timeoutHandler = typeof(IHandleTimeouts<>).MakeGenericType(type);
108115
var messageHandler = typeof(IHandleMessages<>).MakeGenericType(type);
109116

0 commit comments

Comments
 (0)