diff --git a/pi-session-2026-09-03T07-32-04-213Z_01a0662e-95f5-7570-adde-5ca565b482e5.html b/pi-session-2026-09-03T07-32-04-213Z_01a0662e-95f5-7570-adde-5ca565b482e5.html
new file mode 100644
index 00000000000..3851f4dcb13
--- /dev/null
+++ b/pi-session-2026-09-03T07-32-04-213Z_01a0662e-95f5-7570-adde-5ca565b482e5.html
@@ -0,0 +1,4332 @@
+
+
+
+
+
+ Session Export
+
+
+
+
+
+
+
+
+
+
+
+
+
+
![]()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/NServiceBus.AcceptanceTests/Core/Mutators/When_incoming_mutator_changes_message_type.cs b/src/NServiceBus.AcceptanceTests/Core/Mutators/When_incoming_mutator_changes_message_type.cs
index 0fcec518f63..ba140f0f21d 100644
--- a/src/NServiceBus.AcceptanceTests/Core/Mutators/When_incoming_mutator_changes_message_type.cs
+++ b/src/NServiceBus.AcceptanceTests/Core/Mutators/When_incoming_mutator_changes_message_type.cs
@@ -45,7 +45,9 @@ public class MessageMutator : IMutateIncomingMessages
public Task MutateIncoming(MutateIncomingMessageContext context)
{
var original = (OriginalMessage)context.Message;
+#pragma warning disable CS0618 // Deliberate coverage of the legacy runtime-type-routing setter until its removal
context.Message = new NewMessage { SomeId = original.SomeId };
+#pragma warning restore CS0618
return Task.CompletedTask;
}
}
diff --git a/src/NServiceBus.AcceptanceTests/Core/Mutators/When_outgoing_mutator_replaces_instance.cs b/src/NServiceBus.AcceptanceTests/Core/Mutators/When_outgoing_mutator_replaces_instance.cs
index 53c8c2cdcfb..5f91a6c299d 100644
--- a/src/NServiceBus.AcceptanceTests/Core/Mutators/When_outgoing_mutator_replaces_instance.cs
+++ b/src/NServiceBus.AcceptanceTests/Core/Mutators/When_outgoing_mutator_replaces_instance.cs
@@ -38,7 +38,9 @@ public Task MutateOutgoing(MutateOutgoingMessageContext context)
{
if (context.OutgoingMessage is V1Message)
{
+#pragma warning disable CS0618 // Deliberate coverage of the legacy runtime-type-routing setter until its removal
context.OutgoingMessage = new V2Message();
+#pragma warning restore CS0618
}
return Task.CompletedTask;
}
diff --git a/src/NServiceBus.Core.Analyzer.Fixes/MessagingMigrationFixer.cs b/src/NServiceBus.Core.Analyzer.Fixes/MessagingMigrationFixer.cs
index e3808dca7de..f7edb0f1931 100644
--- a/src/NServiceBus.Core.Analyzer.Fixes/MessagingMigrationFixer.cs
+++ b/src/NServiceBus.Core.Analyzer.Fixes/MessagingMigrationFixer.cs
@@ -68,6 +68,24 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
continue;
}
+ if (node is AssignmentExpressionSyntax assignment &&
+ TryGetMutatorReplacementMethod(semanticModel, assignment, out var replacementMethodName))
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ "Use the strongly typed message overload",
+ cancellationToken => ReplaceAssignmentWithTypedCall(
+ context.Document,
+ root,
+ assignment,
+ replacementMethodName,
+ messageType!,
+ cancellationToken),
+ EquivalenceKey),
+ diagnostic);
+ continue;
+ }
+
if (node.FirstAncestorOrSelf() is not { } invocation ||
!CanAddTypeArgument(invocation.Expression))
{
@@ -209,6 +227,73 @@ static Task AddTypeArgumentToMethodReference(
return Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode(methodReference, updatedMethodReference)));
}
+ static bool TryGetMutatorReplacementMethod(
+ SemanticModel? semanticModel,
+ AssignmentExpressionSyntax assignment,
+ out string methodName)
+ {
+ methodName = null!;
+ if (semanticModel is null || assignment.Left is not MemberAccessExpressionSyntax memberAccess)
+ {
+ return false;
+ }
+
+ var propertySymbol = semanticModel.GetSymbolInfo(memberAccess).Symbol;
+ if (propertySymbol is not IPropertySymbol
+ {
+ ContainingType: { } containingType
+ })
+ {
+ return false;
+ }
+
+ var containingTypeName = containingType.ToDisplayString();
+ if (propertySymbol.Name == "Message" &&
+ containingTypeName == "NServiceBus.MessageMutator.MutateIncomingMessageContext")
+ {
+ methodName = "UpdateMessageInstance";
+ return true;
+ }
+
+ if (propertySymbol.Name == "OutgoingMessage" &&
+ containingTypeName == "NServiceBus.MessageMutator.MutateOutgoingMessageContext")
+ {
+ methodName = "UpdateMessage";
+ return true;
+ }
+
+ return false;
+ }
+
+ static Task ReplaceAssignmentWithTypedCall(
+ Document document,
+ SyntaxNode root,
+ AssignmentExpressionSyntax assignment,
+ string methodName,
+ string messageType,
+ CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var memberAccess = (MemberAccessExpressionSyntax)assignment.Left;
+ var typeArgument = SyntaxFactory.ParseTypeName(messageType)
+ .WithAdditionalAnnotations(Simplifier.Annotation);
+ var typeArguments = SyntaxFactory.TypeArgumentList(
+ SyntaxFactory.SingletonSeparatedList(typeArgument));
+
+ var invocation = SyntaxFactory.InvocationExpression(
+ SyntaxFactory.MemberAccessExpression(
+ SyntaxKind.SimpleMemberAccessExpression,
+ memberAccess.Expression,
+ SyntaxFactory.GenericName(SyntaxFactory.Identifier(methodName), typeArguments)
+ .WithTriviaFrom(memberAccess.Name)),
+ SyntaxFactory.ArgumentList(
+ SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(assignment.Right))))
+ .WithAdditionalAnnotations(Formatter.Annotation);
+
+ return Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode(assignment, invocation)));
+ }
+
static ExpressionSyntax AddTypeArgumentToExpression(ExpressionSyntax expression, string messageType)
{
var typeArgument = SyntaxFactory.ParseTypeName(messageType)
diff --git a/src/NServiceBus.Core.Analyzer.Tests.Roslyn5/MessagingMigrationAnalyzerTests.cs b/src/NServiceBus.Core.Analyzer.Tests.Roslyn5/MessagingMigrationAnalyzerTests.cs
index 560cea107f4..ffc172e5b85 100644
--- a/src/NServiceBus.Core.Analyzer.Tests.Roslyn5/MessagingMigrationAnalyzerTests.cs
+++ b/src/NServiceBus.Core.Analyzer.Tests.Roslyn5/MessagingMigrationAnalyzerTests.cs
@@ -1010,6 +1010,198 @@ async Task Bar(IMessageSession session)
return Assert(source, DiagnosticIds.RuntimeTypeMayDiffer);
}
+ // ===== Mutator context setters =====
+
+ [Test]
+ public Task NSB0039_MutatorIncomingContext_DirectObjectCreation()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.MessageMutator;
+
+ class Foo
+ {
+ void Bar(MutateIncomingMessageContext context)
+ {
+ [|context.Message = new MyMessage()|];
+ }
+ }
+
+ class MyMessage : IMessage { }
+ """;
+ return Assert(source, DiagnosticIds.UseGenericMessageType);
+ }
+
+ [Test]
+ public Task NSB0039_MutatorOutgoingContext_DirectObjectCreation()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.MessageMutator;
+
+ class Foo
+ {
+ void Bar(MutateOutgoingMessageContext context)
+ {
+ [|context.OutgoingMessage = new MyEvent()|];
+ }
+ }
+
+ class MyEvent : IEvent { }
+ """;
+ return Assert(source, DiagnosticIds.UseGenericMessageType);
+ }
+
+ [Test]
+ public Task NSB0039_MutatorIncomingContext_ValueType()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.MessageMutator;
+
+ class Foo
+ {
+ void Bar(MutateIncomingMessageContext context, MyValue message)
+ {
+ [|context.Message = message|];
+ }
+ }
+
+ struct MyValue : IMessage { }
+ """;
+ return Assert(source, DiagnosticIds.UseGenericMessageType);
+ }
+
+ [Test]
+ public Task NSB0040_MutatorIncomingContext_VarObjectCreation()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.MessageMutator;
+
+ class Foo
+ {
+ void Bar(MutateIncomingMessageContext context)
+ {
+ var message = new MyMessage();
+ [|context.Message = message|];
+ }
+ }
+
+ class MyMessage : IMessage { }
+ """;
+ return Assert(source, DiagnosticIds.RuntimeTypeMayDiffer);
+ }
+
+ [Test]
+ public Task NSB0040_MutatorOutgoingContext_VarObjectCreation()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.MessageMutator;
+
+ class Foo
+ {
+ void Bar(MutateOutgoingMessageContext context)
+ {
+ var message = new MyEvent();
+ [|context.OutgoingMessage = message|];
+ }
+ }
+
+ class MyEvent : IEvent { }
+ """;
+ return Assert(source, DiagnosticIds.RuntimeTypeMayDiffer);
+ }
+
+ [Test]
+ public Task NSB0040_MutatorIncomingContext_SealedVariable()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.MessageMutator;
+
+ class Foo
+ {
+ void Bar(MutateIncomingMessageContext context, MyMessage message)
+ {
+ [|context.Message = message|];
+ }
+ }
+
+ sealed class MyMessage : IMessage { }
+ """;
+ return Assert(source, DiagnosticIds.RuntimeTypeMayDiffer);
+ }
+
+ [Test]
+ public Task NSB0040_MutatorOutgoingContext_CreatedByMessageCreator()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.MessageMutator;
+
+ class Foo
+ {
+ void Bar(MutateOutgoingMessageContext context, IMessageCreator creator)
+ {
+ [|context.OutgoingMessage = creator.CreateInstance()|];
+ }
+ }
+
+ class MyEvent : IEvent { }
+ """;
+ return Assert(source, DiagnosticIds.RuntimeTypeMayDiffer);
+ }
+
+ [Test]
+ public Task NoDiagnostic_MutatorContext_ObjectType()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.MessageMutator;
+
+ class Foo
+ {
+ void Bar(MutateIncomingMessageContext context)
+ {
+ context.Message = new object();
+ }
+ }
+ """;
+ return Assert(source);
+ }
+
+ [Test]
+ public Task NoDiagnostic_MutatorContext_UnrelatedMessageProperty()
+ {
+ var source =
+ """
+ using NServiceBus;
+
+ class Foo
+ {
+ public object Message { get; set; }
+
+ void Bar(Foo foo)
+ {
+ foo.Message = new MyMessage();
+ }
+ }
+
+ class MyMessage : IMessage { }
+ """;
+ return Assert(source);
+ }
+
// ===== NSB0041: Generic T == object =====
[Test]
@@ -1154,6 +1346,158 @@ void Bar(IOutgoingLogicalMessageContext context, object message)
return Assert(source, DiagnosticIds.GenericMessageTypeIsObject);
}
+ // ===== UpdateMessageInstance on IIncomingLogicalMessageContext =====
+
+ [Test]
+ public Task NSB0039_UpdateMessageInstanceDirectObjectCreation()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.Pipeline;
+ using System.Threading.Tasks;
+
+ class Foo
+ {
+ void Bar(IIncomingLogicalMessageContext context)
+ {
+ [|context.UpdateMessageInstance(new MyMessage())|];
+ }
+ }
+
+ class MyMessage : IMessage { }
+ """;
+ return Assert(source, DiagnosticIds.UseGenericMessageType);
+ }
+
+ [Test]
+ public Task NSB0040_UpdateMessageInstanceVarObjectCreation()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.Pipeline;
+
+ class MyMessage : IMessage { }
+
+ class Foo
+ {
+ void Bar(IIncomingLogicalMessageContext context)
+ {
+ var message = new MyMessage();
+ [|context.UpdateMessageInstance(message)|];
+ }
+ }
+ """;
+ return Assert(source, DiagnosticIds.RuntimeTypeMayDiffer);
+ }
+
+ [Test]
+ public Task NSB0040_UpdateMessageInstanceCreatedByMessageCreator()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.Pipeline;
+
+ class Foo
+ {
+ void Bar(IIncomingLogicalMessageContext context, IMessageCreator creator)
+ {
+ [|context.UpdateMessageInstance(creator.CreateInstance())|];
+ }
+ }
+
+ public interface IMyMessage { }
+ """;
+ return Assert(source, DiagnosticIds.RuntimeTypeMayDiffer);
+ }
+
+ [Test]
+ public Task NSB0040_UpdateMessageInstanceSealedVariable()
+ {
+ var source =
+ """
+ using NServiceBus;
+ using NServiceBus.Pipeline;
+
+ class Foo
+ {
+ void Bar(IIncomingLogicalMessageContext context, MyMessage message)
+ {
+ [|context.UpdateMessageInstance(message)|];
+ }
+ }
+
+ public sealed class MyMessage : IMessage { }
+ """;
+ return Assert(source, DiagnosticIds.RuntimeTypeMayDiffer);
+ }
+
+ [Test]
+ public Task NSB0041_GenericTIsObject_UpdateMessageInstance()
+ {
+ var source =
+ """
+ using NServiceBus.Pipeline;
+
+ class Foo
+ {
+ void Bar(IIncomingLogicalMessageContext context, object message)
+ {
+ [|context.UpdateMessageInstance