diff --git a/AcceptanceTests/NServiceBus.AcceptanceTests/NServiceBus.AcceptanceTests.csproj b/AcceptanceTests/NServiceBus.AcceptanceTests/NServiceBus.AcceptanceTests.csproj
index c7d2d690432..6d2b87e5b8e 100644
--- a/AcceptanceTests/NServiceBus.AcceptanceTests/NServiceBus.AcceptanceTests.csproj
+++ b/AcceptanceTests/NServiceBus.AcceptanceTests/NServiceBus.AcceptanceTests.csproj
@@ -173,6 +173,7 @@
+
diff --git a/AcceptanceTests/NServiceBus.AcceptanceTests/Sagas/When_message_has_a_saga_id.cs b/AcceptanceTests/NServiceBus.AcceptanceTests/Sagas/When_message_has_a_saga_id.cs
new file mode 100644
index 00000000000..bc3ccb5a784
--- /dev/null
+++ b/AcceptanceTests/NServiceBus.AcceptanceTests/Sagas/When_message_has_a_saga_id.cs
@@ -0,0 +1,77 @@
+namespace NServiceBus.AcceptanceTests.Sagas
+{
+ using System;
+ using AcceptanceTesting;
+ using EndpointTemplates;
+ using Saga;
+ using NUnit.Framework;
+
+ public class When_message_has_a_saga_id : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_not_start_a_new_saga_if_not_found()
+ {
+ var context = Scenario.Define()
+ .WithEndpoint(b => b.Given(bus =>
+ {
+ var message = new MessageWithSagaId();
+
+ bus.SetMessageHeader(message, Headers.SagaId, Guid.NewGuid().ToString());
+ bus.SetMessageHeader(message, Headers.SagaType, typeof(MySaga).AssemblyQualifiedName);
+
+ bus.SendLocal(message);
+ }))
+ .Done(c => c.NotFoundHandlerCalled)
+ .Run(TimeSpan.FromSeconds(15));
+
+ Assert.True(context.NotFoundHandlerCalled);
+ Assert.False(context.MessageHandlerCalled);
+ Assert.False(context.TimeoutHandlerCalled);
+ }
+
+ class MySaga : Saga, IAmStartedByMessages,
+ IHandleTimeouts,
+ IHandleSagaNotFound
+ {
+ public Context Context { get; set; }
+
+ public class SagaData : ContainSagaData
+ {
+ }
+
+ public void Handle(MessageWithSagaId message)
+ {
+ Context.MessageHandlerCalled = true;
+ }
+
+ public void Handle(object message)
+ {
+ Context.NotFoundHandlerCalled = true;
+ }
+
+ public void Timeout(MessageWithSagaId state)
+ {
+ Context.TimeoutHandlerCalled = true;
+ }
+ }
+
+ class Context : ScenarioContext
+ {
+ public bool NotFoundHandlerCalled { get; set; }
+ public bool MessageHandlerCalled { get; set; }
+ public bool TimeoutHandlerCalled { get; set; }
+ }
+
+ public class SagaEndpoint : EndpointConfigurationBuilder
+ {
+ public SagaEndpoint()
+ {
+ EndpointSetup();
+ }
+ }
+
+ public class MessageWithSagaId : IMessage
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.Core/Sagas/SagaDispatcherFactory.cs b/src/NServiceBus.Core/Sagas/SagaDispatcherFactory.cs
index 02b8a7449d0..f73b2fd912a 100644
--- a/src/NServiceBus.Core/Sagas/SagaDispatcherFactory.cs
+++ b/src/NServiceBus.Core/Sagas/SagaDispatcherFactory.cs
@@ -44,6 +44,9 @@ public IEnumerable GetDispatcher(Type messageHandlerType, IBuilder build
if (sagaTypesHandled.Contains(sagaType))
continue; // don't create the same saga type twice for the same message
+ if (!IsAllowedToStartANewSaga(sagaType))
+ continue;
+
sagaEntity = CreateNewSagaEntity(sagaType);
sagaEntityIsPersistent = false;
@@ -128,6 +131,25 @@ public IEnumerable GetDispatcher(Type messageHandlerType, IBuilder build
};
}
+ bool IsAllowedToStartANewSaga(Type sagaInstanceType)
+ {
+ string sagaType;
+
+ if (Bus.CurrentMessageContext.Headers.ContainsKey(Headers.SagaId) &&
+ Bus.CurrentMessageContext.Headers.TryGetValue(Headers.SagaType, out sagaType))
+ {
+ //we want to move away from the assembly fully qualified name since that will break if you move sagas
+ // between assemblies. We use the fullname instead which is enough to identify the saga
+ if (sagaType.StartsWith(sagaInstanceType.FullName))
+ {
+ //so now we have a saga id for this saga and if we can't find it we shouldn't start a new one
+ return false;
+ }
+ }
+
+ return true;
+ }
+
IContainSagaData CreateNewSagaEntity(Type sagaType)
{
var sagaEntityType = Features.Sagas.GetSagaEntityTypeForSagaType(sagaType);