Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 0 additions & 130 deletions src/NServiceBus.Core.Tests/API/TrimmabilityWarnings.cs

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,25 @@ public async Task When_mutator_uses_the_object_setter_should_use_the_object_over
}
}

[Test]
public async Task When_typed_replacement_is_followed_by_object_setter_should_use_the_object_overload()
{
var behavior = new MutateIncomingMessageBehavior([]);

var context = new InterceptUpdateMessageIncomingLogicalMessageContext();

context.Services.AddTransient<IMutateIncomingMessages>(sp => new MutatorWhichDeclaresAMessageType());
context.Services.AddTransient<IMutateIncomingMessages>(sp => new MutatorWhichMutatesTheBody());

await behavior.Invoke(context, ctx => Task.CompletedTask);

using (Assert.EnterMultipleScope())
{
Assert.That(context.UpdateMessageWithTypeCalled, Is.False);
Assert.That(context.UpdateMessageObjCalled, Is.True);
}
}

class InterceptUpdateMessageIncomingLogicalMessageContext : TestableIncomingLogicalMessageContext
{
public bool UpdateMessageCalled { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,25 @@ public async Task When_mutator_uses_the_object_setter_should_use_the_object_over
}
}

[Test]
public async Task When_typed_replacement_is_followed_by_object_setter_should_use_the_object_overload()
{
var behavior = new MutateOutgoingMessageBehavior([]);

var context = new InterceptUpdateMessageOutgoingLogicalMessageContext();

context.Services.AddTransient<IMutateOutgoingMessages>(sp => new MutatorWhichDeclaresAMessageType());
context.Services.AddTransient<IMutateOutgoingMessages>(sp => new MutatorWhichMutatesTheBody());

await behavior.Invoke(context, ctx => Task.CompletedTask);

using (Assert.EnterMultipleScope())
{
Assert.That(context.UpdateMessageWithTypeCalled, Is.False);
Assert.That(context.UpdateMessageObjCalled, Is.True);
}
}

class InterceptUpdateMessageOutgoingLogicalMessageContext : TestableOutgoingLogicalMessageContext
{
public bool UpdateMessageCalled { get; private set; }
Expand Down
4 changes: 2 additions & 2 deletions src/NServiceBus.Core.Tests/TrimmedEndpointTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public async Task Scanner_disabled_endpoint_publishes_trimmed_and_processes_a_me

// The AddMessageType and AddHandler calls in the sample are intercepted by source generators. If they
// were not intercepted, the RequiresUnreferencedCode fallback would surface as IL2026 trim warnings at
// the sample's own call sites. Trim warnings inside NServiceBus.Core itself are tracked separately by
// the TrimmabilityWarnings approval test.
// the sample's own call sites. Trim warnings inside NServiceBus.Core itself fail the Core build via
// EnableTrimAnalyzer.
var sampleTrimWarnings = publishResult.Output.Split(Environment.NewLine)
.Where(line => line.Contains("Program.cs") && line.Contains("IL2026"))
.ToArray();
Expand Down
5 changes: 3 additions & 2 deletions src/NServiceBus.Core/EndpointCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,14 @@ void Configure()

void ConfigureMessageTypes(IEnumerable<Type> messageTypesHandled)
{
var allowDynamicTypeLoading = settings.IsDynamicTypeLoadingEnabled();
var configuredDynamicTypeLoading = settings.IsDynamicTypeLoadingEnabled();
var strictMode = settings.Get<AssemblyScanningComponent.Configuration>().StrictRegisteredOnlyMode;
var messageMetadataRegistry = settings.GetOrCreate<MessageMetadataRegistry>();
// Strict mode is the stronger non-overridable policy: it must be in effect before Initialize so
// pre-initialization registrations are enforced against it, and it disables dynamic type loading.
var allowDynamicTypeLoading = configuredDynamicTypeLoading && !strictMode;
messageMetadataRegistry.StrictRegisteredOnlyMode = strictMode;
messageMetadataRegistry.Initialize(conventions.IsMessageType, allowDynamicTypeLoading && !strictMode);
messageMetadataRegistry.Initialize(conventions.IsMessageType, allowDynamicTypeLoading);

messageMetadataRegistry.RegisterMessageTypes(hostingConfiguration.AvailableTypes);
messageMetadataRegistry.RegisterMessageTypesBypassingChecks(messageTypesHandled);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public object Message
{
ArgumentNullException.ThrowIfNull(value);
MessageInstanceChanged = true;
// The setter declares no message type, so drop any type declared by an earlier replacement.
ReplacementMessageType = null;
message = value;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public object OutgoingMessage
{
ArgumentNullException.ThrowIfNull(value);
MessageInstanceChanged = true;
// The setter declares no message type, so drop any type declared by an earlier replacement.
ReplacementMessageType = null;
outgoingMessage = value;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/NServiceBus.Core/NServiceBus.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\NServiceBus.snk</AssemblyOriginatorKeyFile>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsTrimmable>true</IsTrimmable>
Comment thread
danielmarbach marked this conversation as resolved.
Outdated
</PropertyGroup>

<ItemGroup>
Expand Down
6 changes: 4 additions & 2 deletions src/NServiceBus.Core/Routing/AssemblyRouteSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ public AssemblyRouteSource(Assembly messageAssembly, UnicastRoute route)
this.route = route;
}

[RequiresUnreferencedCode(TrimmingMessage)]
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Scanning the configured assembly is intentional; this source can only be constructed through APIs annotated with RequiresUnreferencedCode.")]
static Type[] ScanAssemblyTypes(Assembly assembly) => assembly.GetTypes();

public IEnumerable<RouteTableEntry> GenerateRoutes(Conventions conventions)
{
var routes = messageAssembly.GetTypes()
var routes = ScanAssemblyTypes(messageAssembly)
.Where(t => conventions.IsMessageType(t))
.Select(t => new RouteTableEntry(t, route))
.ToArray();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ public AssemblyPublisherSource(Assembly messageAssembly, PublisherAddress addres
this.address = address;
}

[RequiresUnreferencedCode(TrimmingMessage)]
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Scanning the configured assembly is intentional; this source can only be constructed through APIs annotated with RequiresUnreferencedCode.")]
Comment thread
danielmarbach marked this conversation as resolved.
Outdated
static Type[] ScanAssemblyTypes(Assembly assembly) => assembly.GetTypes();

public IEnumerable<PublisherTableEntry> GenerateWithBestPracticeEnforcement(Conventions conventions)
{
var entries = messageAssembly.GetTypes()
var entries = ScanAssemblyTypes(messageAssembly)
.Where(conventions.IsEventType)
.Select(t => new PublisherTableEntry(t, address))
.ToArray();
Expand All @@ -35,10 +37,9 @@ public IEnumerable<PublisherTableEntry> GenerateWithBestPracticeEnforcement(Conv
return entries;
}

[RequiresUnreferencedCode(TrimmingMessage)]
public IEnumerable<PublisherTableEntry> GenerateWithoutBestPracticeEnforcement(Conventions conventions)
{
var entries = messageAssembly.GetTypes()
var entries = ScanAssemblyTypes(messageAssembly)
.Where(type => conventions.IsMessageType(type) && !conventions.IsCommandType(type))
.Select(t => new PublisherTableEntry(t, address))
.ToArray();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ class NamespacePublisherSource : IPublisherSource
readonly string messageNamespace;
readonly PublisherAddress address;

[RequiresUnreferencedCode(AssemblyPublisherSource.TrimmingMessage)]
public NamespacePublisherSource(Assembly messageAssembly, string messageNamespace, PublisherAddress address)
{
this.messageAssembly = messageAssembly;
this.address = address;
this.messageNamespace = messageNamespace;
}

[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "The public namespace publisher API is annotated with RequiresUnreferencedCode because this source intentionally scans the configured assembly.")]
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Scanning the configured assembly is intentional; this source can only be constructed through APIs annotated with RequiresUnreferencedCode.")]
static Type[] ScanAssemblyTypes(Assembly assembly) => assembly.GetTypes();

public IEnumerable<PublisherTableEntry> GenerateWithBestPracticeEnforcement(Conventions conventions)
{
var entries = messageAssembly.GetTypes()
var entries = ScanAssemblyTypes(messageAssembly)
.Where(t => conventions.IsEventType(t) && string.Equals(t.Namespace, messageNamespace, StringComparison.OrdinalIgnoreCase))
.Select(t => new PublisherTableEntry(t, address))
.ToArray();
Expand All @@ -36,10 +39,9 @@ public IEnumerable<PublisherTableEntry> GenerateWithBestPracticeEnforcement(Conv
return entries;
}

[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "The public namespace publisher API is annotated with RequiresUnreferencedCode because this source intentionally scans the configured assembly.")]
public IEnumerable<PublisherTableEntry> GenerateWithoutBestPracticeEnforcement(Conventions conventions)
{
var entries = messageAssembly.GetTypes()
var entries = ScanAssemblyTypes(messageAssembly)
.Where(t => conventions.IsMessageType(t) && !conventions.IsCommandType(t) && string.Equals(t.Namespace, messageNamespace, StringComparison.OrdinalIgnoreCase))
.Select(t => new PublisherTableEntry(t, address))
.ToArray();
Expand Down
6 changes: 4 additions & 2 deletions src/NServiceBus.Core/Routing/NamespaceRouteSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ public NamespaceRouteSource(Assembly messageAssembly, string messageNamespace, U
this.messageNamespace = messageNamespace;
}

[RequiresUnreferencedCode(AssemblyRouteSource.TrimmingMessage)]
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Scanning the configured assembly is intentional; this source can only be constructed through APIs annotated with RequiresUnreferencedCode.")]
static Type[] ScanAssemblyTypes(Assembly assembly) => assembly.GetTypes();

public IEnumerable<RouteTableEntry> GenerateRoutes(Conventions conventions)
{
var routes = messageAssembly.GetTypes()
var routes = ScanAssemblyTypes(messageAssembly)
.Where(t => conventions.IsMessageType(t) && string.Equals(t.Namespace, messageNamespace, StringComparison.OrdinalIgnoreCase))
.Select(t => new RouteTableEntry(t, route))
.ToArray();
Expand Down
Loading