diff --git a/.gitattributes b/.gitattributes
index bca64ed74..0b6aa0246 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -22,6 +22,8 @@
*.pptx -text -diff
*.xap -text -diff
*.ico -text -diff
+*.ttf -text -diff
+*.otf -text -diff
*.cs text diff=csharp
*.config text diff=csharp
@@ -53,9 +55,11 @@
*.fs text
*.fsx text
*.hs text
-
+*.targets text
*.psm1 text
*.ps1 text
+*.md text
+*.DotSettings text
*.txt text eol=crlf
*.bat text eol=crlf
diff --git a/.gitignore b/.gitignore
index 81e89fb6c..ef7a9f241 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,22 +1,13 @@
nugets
+deploy
build32
binaries
-obj
-bin
*.vshost.*
.nu
-_ReSharper.*
_UpgradeReport.*
-*.csproj.user
-*.resharper.user
-*.resharper
-*.suo
*.cache
*~
*.swp
-*.user
-TestResults
-TestResult.xml
results
CommonAssemblyInfo.cs
lib/sqlite/System.Data.SQLite.dll
@@ -35,4 +26,60 @@ _NCrunch_NServiceBus/*
logs
run-git.cmd
src/Chocolatey/Build/*
-App_Packages
+
+installer/[F|f]iles
+installer/[C|c]ustom[A|a]ctions
+installer/ServiceControl-cache
+
+# Created by https://www.gitignore.io
+
+### VisualStudio ###
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+.vs/
+
+# mac temp file ignore
+.DS_Store
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+build/
+bld/
+[Bb]in/
+[Oo]bj/
+
+# Roslyn cache directories
+*.ide/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+#NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+src/scaffolding.config
+
+# Approval tests temp file
+*.received.*
\ No newline at end of file
diff --git a/buildsupport/FubuCore.dll b/buildsupport/FubuCore.dll
deleted file mode 100644
index de611bc01..000000000
Binary files a/buildsupport/FubuCore.dll and /dev/null differ
diff --git a/buildsupport/GitVersionTask/Build/GitVersionTask.targets b/buildsupport/GitVersionTask/Build/GitVersionTask.targets
deleted file mode 100644
index d88232f59..000000000
--- a/buildsupport/GitVersionTask/Build/GitVersionTask.targets
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
- $(MSBuildProjectDirectory)..\
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/buildsupport/GitVersionTask/GitVersion.exe b/buildsupport/GitVersionTask/GitVersion.exe
deleted file mode 100644
index 8145ba7ed..000000000
Binary files a/buildsupport/GitVersionTask/GitVersion.exe and /dev/null differ
diff --git a/buildsupport/GitVersionTask/GitVersionTask.dll b/buildsupport/GitVersionTask/GitVersionTask.dll
deleted file mode 100644
index 035d8acd5..000000000
Binary files a/buildsupport/GitVersionTask/GitVersionTask.dll and /dev/null differ
diff --git a/buildsupport/GitVersionTask/LibGit2Sharp.dll b/buildsupport/GitVersionTask/LibGit2Sharp.dll
deleted file mode 100644
index a8e940c4b..000000000
Binary files a/buildsupport/GitVersionTask/LibGit2Sharp.dll and /dev/null differ
diff --git a/buildsupport/GitVersionTask/NativeBinaries/amd64/git2-65e9dc6.dll b/buildsupport/GitVersionTask/NativeBinaries/amd64/git2-65e9dc6.dll
deleted file mode 100644
index d548c861e..000000000
Binary files a/buildsupport/GitVersionTask/NativeBinaries/amd64/git2-65e9dc6.dll and /dev/null differ
diff --git a/buildsupport/GitVersionTask/NativeBinaries/x86/git2-65e9dc6.dll b/buildsupport/GitVersionTask/NativeBinaries/x86/git2-65e9dc6.dll
deleted file mode 100644
index 040f87c75..000000000
Binary files a/buildsupport/GitVersionTask/NativeBinaries/x86/git2-65e9dc6.dll and /dev/null differ
diff --git a/buildsupport/MSBuild.Community.Tasks.dll b/buildsupport/MSBuild.Community.Tasks.dll
deleted file mode 100644
index 6d43c0e5b..000000000
Binary files a/buildsupport/MSBuild.Community.Tasks.dll and /dev/null differ
diff --git a/buildsupport/Microsoft.Web.XmlTransform.dll b/buildsupport/Microsoft.Web.XmlTransform.dll
deleted file mode 100644
index 65769fa50..000000000
Binary files a/buildsupport/Microsoft.Web.XmlTransform.dll and /dev/null differ
diff --git a/buildsupport/NuGet.Core.dll b/buildsupport/NuGet.Core.dll
deleted file mode 100644
index a5787205f..000000000
Binary files a/buildsupport/NuGet.Core.dll and /dev/null differ
diff --git a/buildsupport/PepitaPackage.dll b/buildsupport/PepitaPackage.dll
deleted file mode 100644
index d1509d1b2..000000000
Binary files a/buildsupport/PepitaPackage.dll and /dev/null differ
diff --git a/buildsupport/RippleRestoreTask.dll b/buildsupport/RippleRestoreTask.dll
deleted file mode 100644
index e443473c5..000000000
Binary files a/buildsupport/RippleRestoreTask.dll and /dev/null differ
diff --git a/buildsupport/RippleRestoreTask.targets b/buildsupport/RippleRestoreTask.targets
deleted file mode 100644
index cb3f1b839..000000000
--- a/buildsupport/RippleRestoreTask.targets
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- $(MSBuildProjectDirectory)\..\
-
- RippleRestoreTarget;
- $(BuildDependsOn);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/buildsupport/ripple.exe b/buildsupport/ripple.exe
deleted file mode 100644
index 5ed129f4c..000000000
Binary files a/buildsupport/ripple.exe and /dev/null differ
diff --git a/packaging/nuget/NServiceBus.SqlServer.nuspec b/packaging/nuget/NServiceBus.SqlServer.nuspec
index 4eefe7a9e..71c8a30f4 100644
--- a/packaging/nuget/NServiceBus.SqlServer.nuspec
+++ b/packaging/nuget/NServiceBus.SqlServer.nuspec
@@ -3,22 +3,22 @@
NServiceBus.SqlServer
NServiceBus SqlServer
- 4.0.0-alpha0
- NServiceBus Ltd
- Udi Dahan, Andreas Ohlund, John Simons
- http://particular.net/LicenseAgreement
- http://particular.net/
- http://s3.amazonaws.com/nuget.images/NServiceBus_32.png
- true
+ $version$
+ $authors$
+ $owners$
+ $licenseUrl$
+ $projectUrl$
+ $iconUrl$
+ $requireLicenseAcceptance$
+ $copyright$
SQL transport support for NServicebus
- Copyright 2010-2013 NServiceBus. All rights reserved
nservicebus servicebus msmq cqrs publish subscribe
-
+
\ No newline at end of file
diff --git a/ripple.cmd b/ripple.cmd
deleted file mode 100644
index 74b6af73f..000000000
--- a/ripple.cmd
+++ /dev/null
@@ -1 +0,0 @@
-buildsupport\ripple.exe %*
\ No newline at end of file
diff --git a/ripple.config b/ripple.config
deleted file mode 100644
index 443ffb4f8..000000000
--- a/ripple.config
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
- NServiceBus.SqlServer
- packaging/nuget
- src
- rake
- rake compile
- CurrentMajor,NextMajor
- Current,NextMajor
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Audit/When_a_message_is_audited.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Audit/When_a_message_is_audited.cs
new file mode 100644
index 000000000..28ec5898b
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Audit/When_a_message_is_audited.cs
@@ -0,0 +1,130 @@
+namespace NServiceBus.AcceptanceTests.Audit
+{
+ using System;
+ using System.Linq;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using MessageMutator;
+ using NUnit.Framework;
+
+#pragma warning disable 612, 618
+
+ public class When_a_message_is_audited : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_preserve_the_original_body()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new MessageToBeAudited())))
+ .WithEndpoint()
+ .Done(c => c.AuditChecksum != default(byte))
+ .Run();
+
+ Assert.AreEqual(context.OriginalBodyChecksum, context.AuditChecksum, "The body of the message sent to audit should be the same as the original message coming off the queue");
+ }
+
+ [Test]
+ public void Should_add_the_license_diagnostic_headers()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new MessageToBeAudited())))
+ .WithEndpoint()
+ .Done(c => c.HasDiagnosticLicensingHeaders)
+ .Run();
+ Assert.IsTrue(context.HasDiagnosticLicensingHeaders);
+ }
+
+
+ public class Context : ScenarioContext
+ {
+ public byte OriginalBodyChecksum { get; set; }
+ public byte AuditChecksum { get; set; }
+ public bool HasDiagnosticLicensingHeaders { get; set; }
+ }
+
+ public class EndpointWithAuditOn : EndpointConfigurationBuilder
+ {
+ public EndpointWithAuditOn()
+ {
+ EndpointSetup()
+ .AuditTo();
+ }
+
+ class BodyMutator : IMutateIncomingTransportMessages, INeedInitialization
+ {
+ public Context Context { get; set; }
+
+ public void MutateIncoming(TransportMessage transportMessage)
+ {
+
+ var originalBody = transportMessage.Body;
+
+ Context.OriginalBodyChecksum = Checksum(originalBody);
+
+ // modifying the body by adding a line break
+ var modifiedBody = new byte[originalBody.Length + 1];
+
+ Buffer.BlockCopy(originalBody, 0, modifiedBody, 0, originalBody.Length);
+
+ modifiedBody[modifiedBody.Length - 1] = 13;
+
+ transportMessage.Body = modifiedBody;
+ }
+
+ public void Init()
+ {
+ Configure.Component(DependencyLifecycle.InstancePerCall);
+ }
+ }
+
+ public class MessageToBeAuditedHandler : IHandleMessages { public void Handle(MessageToBeAudited message) { } }
+ }
+
+ class AuditSpyEndpoint : EndpointConfigurationBuilder
+ {
+ public AuditSpyEndpoint()
+ {
+ EndpointSetup();
+ }
+
+ class BodySpy : IMutateIncomingTransportMessages, INeedInitialization
+ {
+ public Context Context { get; set; }
+
+ public void MutateIncoming(TransportMessage transportMessage)
+ {
+ Context.AuditChecksum = Checksum(transportMessage.Body);
+ string licenseExpired;
+ Context.HasDiagnosticLicensingHeaders = transportMessage.Headers.TryGetValue(Headers.HasLicenseExpired, out licenseExpired);
+ }
+
+ public void Init()
+ {
+ Configure.Component(DependencyLifecycle.InstancePerCall);
+ }
+ }
+
+ public class MessageToBeAuditedHandler : IHandleMessages { public void Handle(MessageToBeAudited message) { } }
+ }
+
+ public static byte Checksum(byte[] data)
+ {
+ var longSum = data.Sum(x => (long)x);
+ return unchecked((byte)longSum);
+ }
+
+ [Serializable]
+ public class MessageToBeAudited : IMessage
+ {
+ }
+
+
+ }
+
+#pragma warning restore 612, 618
+
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Audit/When_using_auditing_as_a_feature.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Audit/When_using_auditing_as_a_feature.cs
new file mode 100644
index 000000000..1df939607
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Audit/When_using_auditing_as_a_feature.cs
@@ -0,0 +1,111 @@
+
+namespace NServiceBus.AcceptanceTests.Audit
+{
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+
+ public class When_using_auditing_as_a_feature : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Message_should_not_be_forwarded_to_auditQueue_when_auditing_is_disabled()
+ {
+ var context = new Context();
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new MessageToBeAudited())))
+ .WithEndpoint()
+ .Done(c => c.IsMessageHandlingComplete)
+ .Run();
+
+ Assert.IsFalse(context.IsMessageHandledByTheAuditEndpoint);
+ }
+
+ [Test]
+ public void Message_should_be_forwarded_to_auditQueue_when_auditing_is_enabled()
+ {
+ var context = new Context();
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new MessageToBeAudited())))
+ .WithEndpoint()
+ .Done(c => c.IsMessageHandlingComplete)
+ .Run();
+
+ Assert.IsTrue(context.IsMessageHandledByTheAuditEndpoint);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool IsMessageHandlingComplete { get; set; }
+ public bool IsMessageHandledByTheAuditEndpoint { get; set; }
+ }
+
+ public class EndpointWithAuditOff : EndpointConfigurationBuilder
+ {
+
+ public EndpointWithAuditOff()
+ {
+ // Although the AuditTo seems strange here, this test tries to fake the scenario where
+ // even though the user has specified audit config, because auditing is explicitly turned
+ // off, no messages should be audited.
+ EndpointSetup(c => Configure.Features.Disable())
+ .AuditTo();
+
+ }
+
+ class MessageToBeAuditedHandler : IHandleMessages
+ {
+ public Context MyContext { get; set; }
+
+ public void Handle(MessageToBeAudited message)
+ {
+ MyContext.IsMessageHandlingComplete = true;
+ }
+ }
+ }
+
+ public class EndpointWithAuditOn : EndpointConfigurationBuilder
+ {
+
+ public EndpointWithAuditOn()
+ {
+ EndpointSetup()
+ .AuditTo();
+ }
+
+ class MessageToBeAuditedHandler : IHandleMessages
+ {
+ public Context MyContext { get; set; }
+
+ public void Handle(MessageToBeAudited message)
+ {
+ MyContext.IsMessageHandlingComplete = true;
+ }
+ }
+ }
+
+ public class EndpointThatHandlesAuditMessages : EndpointConfigurationBuilder
+ {
+
+ public EndpointThatHandlesAuditMessages()
+ {
+ EndpointSetup();
+ }
+
+ class AuditMessageHandler : IHandleMessages
+ {
+ public Context MyContext { get; set; }
+
+ public void Handle(MessageToBeAudited message)
+ {
+ MyContext.IsMessageHandledByTheAuditEndpoint = true;
+ }
+ }
+ }
+
+ [Serializable]
+ public class MessageToBeAudited : IMessage
+ {
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_Deferring_a_message.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_Deferring_a_message.cs
new file mode 100644
index 000000000..172e1bf16
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_Deferring_a_message.cs
@@ -0,0 +1,52 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+
+ public class When_Deferring_a_message : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Message_should_be_received()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given((bus, c) => bus.Defer(TimeSpan.FromSeconds(3), new MyMessage())))
+ .Done(c => c.WasCalled)
+ .Run();
+
+ Assert.IsTrue(context.WasCalled);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool WasCalled { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup();
+ }
+ public class MyMessageHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(MyMessage message)
+ {
+ Context.WasCalled = true;
+ }
+ }
+ }
+
+ [Serializable]
+ public class MyMessage : IMessage
+ {
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_aborting_the_behavior_chain.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_aborting_the_behavior_chain.cs
new file mode 100644
index 000000000..dcb50ea51
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_aborting_the_behavior_chain.cs
@@ -0,0 +1,73 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using AcceptanceTesting;
+ using EndpointTemplates;
+ using NUnit.Framework;
+
+ public class When_aborting_the_behavior_chain : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Subsequent_handlers_will_not_be_invoked()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.Send(Address.Local, new SomeMessage())))
+ .Done(c => c.FirstHandlerInvoked)
+ .Run();
+
+ Assert.That(context.FirstHandlerInvoked, Is.True);
+ Assert.That(context.SecondHandlerInvoked, Is.False);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool FirstHandlerInvoked { get; set; }
+ public bool SecondHandlerInvoked { get; set; }
+ }
+
+ [Serializable]
+ public class SomeMessage : IMessage { }
+
+ public class MyEndpoint : EndpointConfigurationBuilder
+ {
+ public MyEndpoint()
+ {
+ EndpointSetup();
+ }
+
+ class EnsureOrdering : ISpecifyMessageHandlerOrdering
+ {
+ public void SpecifyOrder(Order order)
+ {
+ order.Specify(First.Then());
+ }
+ }
+
+ class FirstHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(SomeMessage message)
+ {
+ Context.FirstHandlerInvoked = true;
+
+ Bus.DoNotContinueDispatchingCurrentMessageToHandlers();
+ }
+ }
+
+ class SecondHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public void Handle(SomeMessage message)
+ {
+ Context.SecondHandlerInvoked = true;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_handling_current_message_later.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_handling_current_message_later.cs
new file mode 100644
index 000000000..fcdf9301e
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_handling_current_message_later.cs
@@ -0,0 +1,157 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using System.Linq;
+ using AcceptanceTesting;
+ using EndpointTemplates;
+ using NUnit.Framework;
+
+ public class When_handling_current_message_later : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_commit_unit_of_work()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.Send(Address.Local, new SomeMessage())))
+ .Done(c => c.Done)
+ .Run();
+
+ Assert.That(context.AnotherMessageReceivedCount, Is.EqualTo(2),
+ "First handler sends a message to self, which should result in AnotherMessage being dispatched twice");
+ }
+
+ [Test, Description("NOTE the double negation - we should probably modify this behavior somehow")]
+ public void Should_not_not_execute_subsequent_handlers()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.Send(Address.Local, new SomeMessage())))
+ .Done(c => c.Done)
+ .Run();
+
+ Assert.That(context.ThirdHandlerInvocationCount, Is.EqualTo(2),
+ "Since calling HandleCurrentMessageLater does not discontinue message dispatch, the third handler should be called twice as well");
+ }
+
+ [Test]
+ public void Handlers_are_executed_in_the_right_order()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.Send(Address.Local, new SomeMessage())))
+ .Done(c => c.Done)
+ .Run();
+
+ var events = context.Events;
+ CollectionAssert
+ .AreEquivalent(new[]
+ {
+ "FirstHandler:Executed",
+ "SecondHandler:Sending message to the back of the queue",
+ "ThirdHandler:Executed",
+ "FirstHandler:Executed",
+ "SecondHandler:Handling the message this time",
+ "ThirdHandler:Executed"
+ },
+ events);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public string[] Events { get; set; }
+
+ public bool SomeMessageHasBeenRequeued { get; set; }
+
+ public bool Done
+ {
+ get { return ThirdHandlerInvocationCount >= 2 && AnotherMessageReceivedCount == 2; }
+ }
+
+ public int AnotherMessageReceivedCount { get; set; }
+
+ public int ThirdHandlerInvocationCount { get; set; }
+ }
+
+ [Serializable]
+ public class SomeMessage : IMessage { }
+
+ [Serializable]
+ public class AnotherMessage : IMessage { }
+
+ public class MyEndpoint : EndpointConfigurationBuilder
+ {
+ public MyEndpoint()
+ {
+ EndpointSetup();
+ }
+
+ class EnsureOrdering : ISpecifyMessageHandlerOrdering
+ {
+ public void SpecifyOrder(Order order)
+ {
+ order.Specify(First.Then().AndThen());
+ }
+ }
+
+ class FirstHandler : IHandleMessages, IHandleMessages
+ {
+ public Context Context { get; set; }
+ public IBus Bus { get; set; }
+
+ public void Handle(SomeMessage message)
+ {
+ Context.RegisterEvent("FirstHandler:Executed");
+ Bus.SendLocal(new AnotherMessage());
+ }
+
+ public void Handle(AnotherMessage message)
+ {
+ Context.AnotherMessageReceivedCount++;
+ }
+ }
+
+ class SecondHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+ public IBus Bus { get; set; }
+ public void Handle(SomeMessage message)
+ {
+ if (!Context.SomeMessageHasBeenRequeued)
+ {
+ Context.RegisterEvent("SecondHandler:Sending message to the back of the queue");
+ Bus.HandleCurrentMessageLater();
+ Context.SomeMessageHasBeenRequeued = true;
+ }
+ else
+ {
+ Context.RegisterEvent("SecondHandler:Handling the message this time");
+ }
+ }
+ }
+
+ class ThirdHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+ public void Handle(SomeMessage message)
+ {
+ Context.RegisterEvent("ThirdHandler:Executed");
+ Context.ThirdHandlerInvocationCount++;
+ }
+ }
+ }
+ }
+
+ static class ContextEx
+ {
+ public static void RegisterEvent(this When_handling_current_message_later.Context context, string description)
+ {
+ context.Events = context.Events
+ .Concat(new[] {description})
+ .ToArray();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_registering_a_callback_for_a_local_message.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_registering_a_callback_for_a_local_message.cs
new file mode 100644
index 000000000..d00d0102b
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_registering_a_callback_for_a_local_message.cs
@@ -0,0 +1,64 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+ using ScenarioDescriptors;
+
+ public class When_registering_a_callback_for_a_local_message : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_trigger_the_callback_when_the_response_comes_back()
+ {
+ Scenario.Define()
+ .WithEndpoint(b=>b.Given(
+ (bus,context)=>bus.SendLocal(new MyRequest()).Register(r =>
+ {
+ Assert.True(context.HandlerGotTheRequest);
+ context.CallbackFired = true;
+ })))
+ .Done(c => c.CallbackFired)
+ .Repeat(r =>r.For(Transports.Default))
+ .Should(c =>
+ {
+ Assert.True(c.CallbackFired);
+ Assert.True(c.HandlerGotTheRequest);
+ })
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool HandlerGotTheRequest { get; set; }
+
+ public bool CallbackFired { get; set; }
+ }
+
+ public class EndpointWithLocalCallback : EndpointConfigurationBuilder
+ {
+ public EndpointWithLocalCallback()
+ {
+ EndpointSetup();
+ }
+
+ public class MyRequestHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(MyRequest request)
+ {
+ Assert.False(Context.CallbackFired);
+ Context.HandlerGotTheRequest = true;
+
+ Bus.Return(1);
+ }
+ }
+ }
+
+ [Serializable]
+ public class MyRequest : IMessage{}
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_sending_a_message_that_is_registered_multiple_times_to_another_endpoint.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_sending_a_message_that_is_registered_multiple_times_to_another_endpoint.cs
new file mode 100644
index 000000000..a9c7bc06b
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_sending_a_message_that_is_registered_multiple_times_to_another_endpoint.cs
@@ -0,0 +1,100 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using System.Threading;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+
+ public class When_sending_a_message_that_is_registered_multiple_times_to_another_endpoint : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void First_registration_should_be_the_final_destination()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given((bus, c) => bus.Send(new MyCommand1())))
+ .WithEndpoint()
+ .WithEndpoint()
+ .Done(c => c.WasCalled1 || c.WasCalled2)
+ .Run();
+
+ Assert.IsTrue(context.WasCalled1);
+ Assert.IsFalse(context.WasCalled2);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool WasCalled1 { get; set; }
+ public bool WasCalled2 { get; set; }
+ }
+
+ public class Sender : EndpointConfigurationBuilder
+ {
+ public Sender()
+ {
+ EndpointSetup()
+ .AddMapping(typeof(Receiver1))
+ .AddMapping(typeof(Receiver2));
+ }
+ }
+
+ public class Receiver1 : EndpointConfigurationBuilder
+ {
+ public Receiver1()
+ {
+ EndpointSetup();
+ }
+
+ public class MyMessageHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(MyBaseCommand message)
+ {
+ Context.WasCalled1 = true;
+ Thread.Sleep(2000); // Just to be sure the other receiver is finished
+ }
+ }
+ }
+
+ public class Receiver2 : EndpointConfigurationBuilder
+ {
+ public Receiver2()
+ {
+ EndpointSetup();
+ }
+
+ public class MyMessageHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(MyBaseCommand message)
+ {
+ Context.WasCalled2 = true;
+ Thread.Sleep(2000); // Just to be sure the other receiver is finished
+ }
+ }
+ }
+
+ [Serializable]
+ public abstract class MyBaseCommand : ICommand
+ {
+ }
+
+ [Serializable]
+ public class MyCommand1 : MyBaseCommand
+ {
+ }
+
+ [Serializable]
+ public class MyCommand2 : MyBaseCommand
+ {
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_sending_a_message_to_another_endpoint.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_sending_a_message_to_another_endpoint.cs
new file mode 100644
index 000000000..b4eb71051
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_sending_a_message_to_another_endpoint.cs
@@ -0,0 +1,99 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using System.Collections.Generic;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+ using ScenarioDescriptors;
+
+ public class When_sending_a_message_to_another_endpoint : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_the_message()
+ {
+ Scenario.Define(() => new Context { Id = Guid.NewGuid() })
+ .WithEndpoint(b => b.Given((bus, context) =>
+ {
+ bus.OutgoingHeaders["MyStaticHeader"] = "StaticHeaderValue";
+ bus.Send(m=>
+ {
+ m.Id = context.Id;
+ m.SetHeader("MyHeader","MyHeaderValue");
+ });
+ }))
+ .WithEndpoint()
+ .Done(c => c.WasCalled)
+ .Repeat(r =>r.For(Serializers.Binary)
+ .For()
+ )
+ .Should(c =>
+ {
+ Assert.True(c.WasCalled, "The message handler should be called");
+ Assert.AreEqual(1, c.TimesCalled, "The message handler should only be invoked once");
+ Assert.True(c.ReceivedHeaders[Headers.OriginatingEndpoint].Contains("Sender"), "The sender should attach its endpoint name as a header");
+ Assert.True(c.ReceivedHeaders[Headers.ProcessingEndpoint].Contains("Receiver"), "The receiver should attach its endpoint name as a header");
+ Assert.AreEqual("StaticHeaderValue",c.ReceivedHeaders["MyStaticHeader"], "Static headers should be attached to outgoing messages");
+ Assert.AreEqual("MyHeaderValue", c.MyHeader, "Static headers should be attached to outgoing messages");
+ })
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool WasCalled { get; set; }
+
+ public int TimesCalled { get; set; }
+
+ public IDictionary ReceivedHeaders { get; set; }
+
+ public Guid Id { get; set; }
+
+ public string MyHeader { get; set; }
+ }
+
+ public class Sender : EndpointConfigurationBuilder
+ {
+ public Sender()
+ {
+ EndpointSetup()
+ .AddMapping(typeof(Receiver));
+ }
+ }
+
+ public class Receiver : EndpointConfigurationBuilder
+ {
+ public Receiver()
+ {
+ EndpointSetup();
+ }
+ }
+
+ [Serializable]
+ public class MyMessage : ICommand
+ {
+ public Guid Id { get; set; }
+ }
+
+ public class MyMessageHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(MyMessage message)
+ {
+ if (Context.Id != message.Id)
+ return;
+
+ Context.TimesCalled++;
+
+ Context.MyHeader = message.GetHeader("MyHeader");
+
+ Context.ReceivedHeaders = Bus.CurrentMessageContext.Headers;
+
+ Context.WasCalled = true;
+ }
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_sending_a_message_with_no_correlation_id.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_sending_a_message_with_no_correlation_id.cs
new file mode 100644
index 000000000..3918a7875
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_sending_a_message_with_no_correlation_id.cs
@@ -0,0 +1,73 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using MessageMutator;
+ using NUnit.Framework;
+
+ public class When_sending_a_message_with_no_correlation_id : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_use_the_message_id_as_the_correlation_id()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.Send(Address.Local, new MyRequest())))
+ .Done(c => c.GotRequest)
+ .Run();
+
+ Assert.AreEqual(context.MessageIdReceived, context.CorrelationIdReceived, "Correlation id should match MessageId");
+ }
+
+ public class Context : ScenarioContext
+ {
+ public string MessageIdReceived { get; set; }
+ public bool GotRequest { get; set; }
+ public string CorrelationIdReceived { get; set; }
+ }
+
+ public class CorrelationEndpoint : EndpointConfigurationBuilder
+ {
+ public CorrelationEndpoint()
+ {
+ EndpointSetup();
+ }
+
+ class GetValueOfIncomingCorrelationId:IMutateIncomingTransportMessages,INeedInitialization
+ {
+ public Context Context { get; set; }
+
+ public void MutateIncoming(TransportMessage transportMessage)
+ {
+ Context.CorrelationIdReceived = transportMessage.CorrelationId;
+ Context.MessageIdReceived = transportMessage.Id;
+ }
+
+ public void Init()
+ {
+ Configure.Component(DependencyLifecycle.InstancePerCall);
+ }
+ }
+
+ public class MyResponseHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(MyRequest response)
+ {
+ Context.GotRequest = true;
+ }
+ }
+ }
+
+
+ [Serializable]
+ public class MyRequest : IMessage
+ {
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_starting_a_send_only.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_starting_a_send_only.cs
new file mode 100644
index 000000000..f333cb565
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_starting_a_send_only.cs
@@ -0,0 +1,22 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using NUnit.Framework;
+
+ public class When_starting_a_send_only : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_not_need_audit_or_fault_forwarding_config_to_start()
+ {
+ using ((IDisposable)Configure.With(new Type[]
+ {
+ })
+ .DefaultBuilder()
+ .UnicastBus()
+ .SendOnly())
+ {
+ }
+
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_custom_correlation_id.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_custom_correlation_id.cs
new file mode 100644
index 000000000..f1221c4e1
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_custom_correlation_id.cs
@@ -0,0 +1,74 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using MessageMutator;
+ using NUnit.Framework;
+
+ public class When_using_a_custom_correlation_id : NServiceBusAcceptanceTest
+ {
+ static string CorrelationId = "my_custom_correlation_id";
+
+ [Test]
+ public void Should_use_the_given_id_as_the_transport_level_correlation_id()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.Send(Address.Local, CorrelationId, new MyRequest())))
+ .Done(c => c.GotRequest)
+ .Run();
+
+ Assert.AreEqual(CorrelationId, context.CorrelationIdReceived, "Correlation ids should match");
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool GotRequest { get; set; }
+
+ public string CorrelationIdReceived { get; set; }
+ }
+
+ public class CorrelationEndpoint : EndpointConfigurationBuilder
+ {
+ public CorrelationEndpoint()
+ {
+ EndpointSetup();
+ }
+
+ class GetValueOfIncomingCorrelationId:IMutateIncomingTransportMessages,INeedInitialization
+ {
+ public Context Context { get; set; }
+
+ public void MutateIncoming(TransportMessage transportMessage)
+ {
+ Context.CorrelationIdReceived = transportMessage.CorrelationId;
+ }
+
+ public void Init()
+ {
+ Configure.Component(DependencyLifecycle.InstancePerCall);
+ }
+ }
+
+ public class MyResponseHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(MyRequest response)
+ {
+ Context.GotRequest = true;
+ }
+ }
+ }
+
+
+ [Serializable]
+ public class MyRequest : IMessage
+ {
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_greedy_convention.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_greedy_convention.cs
new file mode 100644
index 000000000..c0320ddaf
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_greedy_convention.cs
@@ -0,0 +1,64 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+ using ScenarioDescriptors;
+
+ public class When_using_a_greedy_convention : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_the_message()
+ {
+ Scenario.Define(() => new Context { Id = Guid.NewGuid() })
+ .WithEndpoint(b => b.Given((bus, context) => bus.SendLocal(new MyMessage
+ {Id = context.Id})))
+ .Done(c => c.WasCalled)
+ .Repeat(r =>r
+ .For(Transports.Msmq)
+ )
+ .Should(c => Assert.True(c.WasCalled, "The message handler should be called"))
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool WasCalled { get; set; }
+
+ public Guid Id { get; set; }
+ }
+
+ public class EndPoint : EndpointConfigurationBuilder
+ {
+ public EndPoint()
+ {
+ EndpointSetup(c => c.DefiningMessagesAs(MessageConvention));
+ }
+
+ static bool MessageConvention(Type t)
+ {
+ return t.Namespace != null &&
+ (t.Namespace.EndsWith(".Messages") || (t == typeof(MyMessage)));
+ }
+ }
+
+ [Serializable]
+ public class MyMessage
+ {
+ public Guid Id { get; set; }
+ }
+
+ public class MyMessageHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+ public void Handle(MyMessage message)
+ {
+ if (Context.Id != message.Id)
+ return;
+
+ Context.WasCalled = true;
+ }
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_message_with_TimeToBeReceived_has_expired.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_message_with_TimeToBeReceived_has_expired.cs
new file mode 100644
index 000000000..f09474ebb
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_message_with_TimeToBeReceived_has_expired.cs
@@ -0,0 +1,49 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+
+ public class When_using_a_message_with_TimeToBeReceived_has_expired : NServiceBusAcceptanceTest
+ {
+ [Test, Ignore("The TTL will only be started at the moment the timeoutmanager sends the message back, still giving the test a second to receive it")]
+ public void Message_should_not_be_received()
+ {
+ var context = new Context();
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given((bus, c) => bus.Defer(TimeSpan.FromSeconds(5), new MyMessage())))
+ .Run(TimeSpan.FromSeconds(10));
+ Assert.IsFalse(context.WasCalled);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool WasCalled { get; set; }
+ }
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup();
+ }
+ public class MyMessageHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(MyMessage message)
+ {
+ Context.WasCalled = true;
+ }
+ }
+ }
+
+ [Serializable]
+ [TimeToBeReceived("00:00:01")]
+ public class MyMessage : IMessage
+ {
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_message_with_TimeToBeReceived_has_not_expired.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_message_with_TimeToBeReceived_has_not_expired.cs
new file mode 100644
index 000000000..a516e51da
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_a_message_with_TimeToBeReceived_has_not_expired.cs
@@ -0,0 +1,53 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+
+ public class When_using_a_message_with_TimeToBeReceived_has_not_expired : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Message_should_be_received()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given((bus, c) => bus.SendLocal(new MyMessage())))
+ .Done(c => c.WasCalled)
+ .Run();
+
+ Assert.IsTrue(context.WasCalled);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool WasCalled { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup();
+ }
+ public class MyMessageHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(MyMessage message)
+ {
+ Context.WasCalled = true;
+ }
+ }
+ }
+
+ [Serializable]
+ [TimeToBeReceived("00:00:10")]
+ public class MyMessage : IMessage
+ {
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_callbacks_in_a_scaleout_scenario.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_callbacks_in_a_scaleout_scenario.cs
new file mode 100644
index 000000000..db1df8120
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BasicMessaging/When_using_callbacks_in_a_scaleout_scenario.cs
@@ -0,0 +1,125 @@
+namespace NServiceBus.AcceptanceTests.BasicMessaging
+{
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+ using ScenarioDescriptors;
+ using Support;
+
+ public class When_using_callbacks_in_a_scaleout_scenario : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Each_client_should_have_a_unique_input_queue_to_avoid_processing_each_others_callbacks()
+ {
+ Scenario.Define(() => new Context{Id = Guid.NewGuid()})
+ .WithEndpoint(b => b.CustomConfig(c=>RuntimeEnvironment.MachineNameAction = () => "ClientA")
+ .Given((bus, context) => bus.Send(new MyRequest { Id = context.Id, Client = RuntimeEnvironment.MachineName })
+ .Register(r => context.CallbackAFired = true)))
+ .WithEndpoint(b => b.CustomConfig(c=>RuntimeEnvironment.MachineNameAction = () => "ClientB")
+ .Given((bus, context) => bus.Send(new MyRequest { Id = context.Id, Client = RuntimeEnvironment.MachineName })
+ .Register(r => context.CallbackBFired = true)))
+ .WithEndpoint()
+ .Done(c => c.ClientAGotResponse && c.ClientBGotResponse)
+ .Repeat(r =>r.For()
+ )
+ .Should(c =>
+ {
+ Assert.True(c.CallbackAFired, "Callback on ClientA should fire");
+ Assert.True(c.CallbackBFired, "Callback on ClientB should fire");
+ Assert.False(c.ResponseEndedUpAtTheWrongClient, "One of the responses ended up at the wrong client");
+ })
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ public Guid Id { get; set; }
+
+ public bool ClientAGotResponse { get; set; }
+
+ public bool ClientBGotResponse { get; set; }
+
+ public bool ResponseEndedUpAtTheWrongClient { get; set; }
+
+ public bool CallbackAFired { get; set; }
+
+ public bool CallbackBFired { get; set; }
+ }
+
+ public class Client : EndpointConfigurationBuilder
+ {
+ public Client()
+ {
+ EndpointSetup(c => Configure.ScaleOut(s => s.UseUniqueBrokerQueuePerMachine()))
+ .AddMapping(typeof(Server));
+ }
+
+ public class MyResponseHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(MyResponse response)
+ {
+ if (Context.Id != response.Id)
+ return;
+
+ if (RuntimeEnvironment.MachineName == "ClientA")
+ Context.ClientAGotResponse = true;
+ else
+ {
+ Context.ClientBGotResponse = true;
+ }
+
+ if (RuntimeEnvironment.MachineName != response.Client)
+ Context.ResponseEndedUpAtTheWrongClient = true;
+ }
+ }
+ }
+
+ public class Server : EndpointConfigurationBuilder
+ {
+ public Server()
+ {
+ EndpointSetup();
+ }
+
+ public class MyMessageHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public IBus Bus { get; set; }
+
+ public void Handle(MyRequest request)
+ {
+ if (Context.Id != request.Id)
+ return;
+
+
+ Bus.Reply(new MyResponse { Id = request.Id,Client = request.Client });
+ }
+ }
+ }
+
+ [Serializable]
+ public class MyRequest : IMessage
+ {
+ public Guid Id { get; set; }
+
+ public string Client { get; set; }
+ }
+
+ [Serializable]
+ public class MyResponse : IMessage
+ {
+ public Guid Id { get; set; }
+
+ public string Client { get; set; }
+ }
+
+
+
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BusStartStop/When_bus_start_and_stops_with_a_pending_message.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BusStartStop/When_bus_start_and_stops_with_a_pending_message.cs
new file mode 100644
index 000000000..8b252ea7e
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BusStartStop/When_bus_start_and_stops_with_a_pending_message.cs
@@ -0,0 +1,58 @@
+namespace NServiceBus.AcceptanceTests.BusStartStop
+{
+ using System;
+ using System.Threading;
+ using AcceptanceTesting.Support;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+
+ public class When_bus_start_and_stops_with_a_pending_message : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_not_throw()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => SendMessages(b))
+ .Run(TimeSpan.FromMilliseconds(100));
+
+ Thread.Sleep(100);
+ }
+
+
+ EndpointBehaviorBuilder SendMessages(EndpointBehaviorBuilder b)
+ {
+ return b.Given((bus, context) => bus.SendLocal(new Message()));
+ }
+
+ public class Context : ScenarioContext
+ {
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup();
+ }
+
+ class MessageHandler : IHandleMessages
+ {
+ public void Handle(Message message)
+ {
+ Thread.Sleep(100);
+ }
+ }
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/BusStartStop/When_bus_start_raises_an_inmemory_message.cs b/src/NServiceBus.SqlServer.AcceptanceTests/BusStartStop/When_bus_start_raises_an_inmemory_message.cs
new file mode 100644
index 000000000..4b2c17a4e
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/BusStartStop/When_bus_start_raises_an_inmemory_message.cs
@@ -0,0 +1,69 @@
+namespace NServiceBus.AcceptanceTests.BusStartStop
+{
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+ using ScenarioDescriptors;
+
+#pragma warning disable 612, 618
+ public class When_bus_start_raises_an_inmemory_message : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_not_throw()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint()
+ .Done(c => c.GotMessage)
+ .Repeat(r => r.For())
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool GotMessage;
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup();
+ }
+
+ class MessageHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public void Handle(Message message)
+ {
+ Context.GotMessage = true;
+ }
+ }
+ }
+
+ public class Foo : IWantToRunWhenBusStartsAndStops
+ {
+ public IBus Bus { get; set; }
+
+ public void Start()
+ {
+ Bus.InMemory.Raise(new Message());
+ }
+
+ public void Stop()
+ {
+ }
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+
+ }
+#pragma warning restore 612, 618
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Configuration/When_a_config_override_is_found.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Configuration/When_a_config_override_is_found.cs
new file mode 100644
index 000000000..3e130676c
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Configuration/When_a_config_override_is_found.cs
@@ -0,0 +1,65 @@
+namespace NServiceBus.AcceptanceTests.Configuration
+{
+ using Config;
+ using Config.ConfigurationSource;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using Faults.Forwarder;
+ using NUnit.Framework;
+ using Unicast;
+ using Unicast.Transport;
+
+ public class When_a_config_override_is_found : NServiceBusAcceptanceTest
+ {
+ static Address CustomErrorQ = Address.Parse("MyErrorQ");
+
+ [Test]
+ public void Should_be_used_instead_of_pulling_the_settings_from_appconfig()
+ {
+ var context = Scenario.Define()
+ .WithEndpoint(b => b.When(c => c.EndpointsStarted, (bus, cc) =>
+ {
+ var unicastBus = (UnicastBus)bus;
+ var transport = (TransportReceiver)unicastBus.Transport;
+ var fm = (FaultManager)transport.FailureManager;
+
+ cc.ErrorQueueUsedByTheEndpoint = fm.ErrorQueue;
+ cc.IsDone = true;
+ }))
+ .Done(c => c.IsDone)
+ .Run();
+
+ Assert.AreEqual(CustomErrorQ, context.ErrorQueueUsedByTheEndpoint, "The error queue should have been changed");
+
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool IsDone { get; set; }
+
+ public Address ErrorQueueUsedByTheEndpoint { get; set; }
+ }
+
+ public class ConfigOverrideEndpoint : EndpointConfigurationBuilder
+ {
+ public ConfigOverrideEndpoint()
+ {
+ EndpointSetup(c => c.MessageForwardingInCaseOfFault());
+ }
+
+ public class ConfigErrorQueue : IProvideConfiguration
+ {
+ public MessageForwardingInCaseOfFaultConfig GetConfiguration()
+ {
+
+ return new MessageForwardingInCaseOfFaultConfig
+ {
+ ErrorQueue = CustomErrorQ.ToString()
+ };
+ }
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/DataBus/When_sending_databus_properties.cs b/src/NServiceBus.SqlServer.AcceptanceTests/DataBus/When_sending_databus_properties.cs
new file mode 100644
index 000000000..db691ccc6
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/DataBus/When_sending_databus_properties.cs
@@ -0,0 +1,67 @@
+namespace NServiceBus.AcceptanceTests.DataBus
+{
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+ using ScenarioDescriptors;
+
+ public class When_sending_databus_properties:NServiceBusAcceptanceTest
+ {
+ static byte[] PayloadToSend = new byte[1024 * 1024 * 10];
+
+ [Test]
+ public void Should_receive_the_message_the_largeproperty_correctly()
+ {
+ Scenario.Define()
+ .WithEndpoint(b => b.Given(bus=> bus.Send(new MyMessageWithLargePayload
+ {
+ Payload = new DataBusProperty(PayloadToSend)
+ })))
+ .WithEndpoint()
+ .Done(context => context.ReceivedPayload != null)
+ .Repeat(r => r.For())
+ .Should(c => Assert.AreEqual(PayloadToSend, c.ReceivedPayload, "The large payload should be marshalled correctly using the databus"))
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ public byte[] ReceivedPayload { get; set; }
+ }
+
+
+ public class Sender : EndpointConfigurationBuilder
+ {
+ public Sender()
+ {
+ EndpointSetup(c => c.FileShareDataBus(@".\databus\sender"))
+ .AddMapping(typeof (Receiver));
+ }
+ }
+
+ public class Receiver : EndpointConfigurationBuilder
+ {
+ public Receiver()
+ {
+ EndpointSetup(c => c.FileShareDataBus(@".\databus\sender"));
+ }
+
+ public class MyMessageHandler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public void Handle(MyMessageWithLargePayload messageWithLargePayload)
+ {
+ Context.ReceivedPayload = messageWithLargePayload.Payload.Value;
+ }
+ }
+ }
+
+ [Serializable]
+ public class MyMessageWithLargePayload : ICommand
+ {
+ public DataBusProperty Payload { get; set; }
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Encryption/When_using_encryption.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Encryption/When_using_encryption.cs
new file mode 100644
index 000000000..6c982f323
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Encryption/When_using_encryption.cs
@@ -0,0 +1,117 @@
+namespace NServiceBus.AcceptanceTests.Encryption
+{
+ using System;
+ using System.Collections.Generic;
+ using Config;
+ using Config.ConfigurationSource;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+ using ScenarioDescriptors;
+
+ public class When_using_encryption : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_decrypted_message()
+ {
+ Scenario.Define()
+ .WithEndpoint(b => b.Given((bus, context) => bus.SendLocal(new MessageWithSecretData
+ {
+ Secret = "betcha can't guess my secret",
+ SubProperty = new MySecretSubProperty {Secret = "My sub secret"},
+ CreditCards = new List
+ {
+ new CreditCardDetails
+ {
+ ValidTo = DateTime.UtcNow.AddYears(1),
+ Number = "312312312312312"
+ },
+ new CreditCardDetails
+ {
+ ValidTo = DateTime.UtcNow.AddYears(2),
+ Number = "543645546546456"
+ }
+ }
+ })))
+ .Done(c => c.Done)
+ .Repeat(r => r.For())
+ .Should(c =>
+ {
+ Assert.AreEqual("betcha can't guess my secret", c.Secret);
+ Assert.AreEqual("My sub secret", c.SubPropertySecret);
+ CollectionAssert.AreEquivalent(new List { "312312312312312", "543645546546456" }, c.CreditCards);
+ })
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool Done { get; set; }
+
+ public string Secret { get; set; }
+
+ public string SubPropertySecret { get; set; }
+
+ public List CreditCards { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c => c.RijndaelEncryptionService());
+ }
+
+ public class Handler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public void Handle(MessageWithSecretData message)
+ {
+ Context.Secret = message.Secret.Value;
+
+ Context.SubPropertySecret = message.SubProperty.Secret.Value;
+
+ Context.CreditCards = new List
+ {
+ message.CreditCards[0].Number.Value,
+ message.CreditCards[1].Number.Value
+ };
+
+ Context.Done = true;
+ }
+ }
+ }
+
+ [Serializable]
+ public class MessageWithSecretData : IMessage
+ {
+ public WireEncryptedString Secret { get; set; }
+ public MySecretSubProperty SubProperty { get; set; }
+ public List CreditCards { get; set; }
+ }
+
+ [Serializable]
+ public class CreditCardDetails
+ {
+ public DateTime ValidTo { get; set; }
+ public WireEncryptedString Number { get; set; }
+ }
+
+ [Serializable]
+ public class MySecretSubProperty
+ {
+ public WireEncryptedString Secret { get; set; }
+ }
+
+ public class ConfigureEncryption: IProvideConfiguration
+ {
+ RijndaelEncryptionServiceConfig rijndaelEncryptionServiceConfig = new RijndaelEncryptionServiceConfig { Key = "gdDbqRpqdRbTs3mhdZh9qCaDaxJXl+e6" };
+
+ public RijndaelEncryptionServiceConfig GetConfiguration()
+ {
+ return rijndaelEncryptionServiceConfig;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Encryption/When_using_encryption_with_custom_service.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Encryption/When_using_encryption_with_custom_service.cs
new file mode 100644
index 000000000..136bbd5f1
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Encryption/When_using_encryption_with_custom_service.cs
@@ -0,0 +1,75 @@
+namespace NServiceBus.AcceptanceTests.Encryption
+{
+ using System.Linq;
+ using NServiceBus.Encryption;
+ using System;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+ using ScenarioDescriptors;
+
+ public class When_using_encryption_with_custom_service : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_decrypted_message()
+ {
+ Scenario.Define()
+ .WithEndpoint(b => b.Given((bus, context) => bus.SendLocal(new MessageWithSecretData
+ {
+ Secret = "betcha can't guess my secret"
+ })))
+ .Done(c => c.Done)
+ .Repeat(r => r.For())
+ .Should(c => Assert.AreEqual("betcha can't guess my secret", c.Secret))
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool Done { get; set; }
+ public string Secret { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c => c.Configurer.RegisterSingleton(new MyEncryptionService()));
+ }
+
+ public class Handler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public void Handle(MessageWithSecretData message)
+ {
+ Context.Secret = message.Secret.Value;
+ Context.Done = true;
+ }
+ }
+ }
+
+ [Serializable]
+ public class MessageWithSecretData : IMessage
+ {
+ public WireEncryptedString Secret { get; set; }
+ }
+
+
+ public class MyEncryptionService : IEncryptionService
+ {
+ public EncryptedValue Encrypt(string value)
+ {
+ return new EncryptedValue
+ {
+ EncryptedBase64Value = new string(value.Reverse().ToArray())
+ };
+ }
+
+ public string Decrypt(EncryptedValue encryptedValue)
+ {
+ return new string(encryptedValue.EncryptedBase64Value.Reverse().ToArray());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Encryption/When_using_encryption_with_multikey.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Encryption/When_using_encryption_with_multikey.cs
new file mode 100644
index 000000000..60dbf90ce
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Encryption/When_using_encryption_with_multikey.cs
@@ -0,0 +1,110 @@
+namespace NServiceBus.AcceptanceTests.Encryption
+{
+ using System;
+ using Config;
+ using Config.ConfigurationSource;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+ using ScenarioDescriptors;
+
+ public class When_using_encryption_with_multikey : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_decrypted_message()
+ {
+ Scenario.Define()
+ .WithEndpoint(b => b.Given((bus, context) => bus.Send(new MessageWithSecretData
+ {
+ Secret = "betcha can't guess my secret",
+ })))
+ .WithEndpoint()
+ .Done(c => c.Done)
+ .Repeat(r => r.For())
+ .Should(c => Assert.AreEqual("betcha can't guess my secret", c.Secret))
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool Done { get; set; }
+
+ public string Secret { get; set; }
+ }
+
+ public class Sender : EndpointConfigurationBuilder
+ {
+ public Sender()
+ {
+ EndpointSetup(c => c.RijndaelEncryptionService())
+ .AddMapping(typeof(Receiver));
+ }
+
+ public class Handler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public void Handle(MessageWithSecretData message)
+ {
+ Context.Secret = message.Secret.Value;
+ Context.Done = true;
+ }
+ }
+
+ public class ConfigureEncryption : IProvideConfiguration
+ {
+ public RijndaelEncryptionServiceConfig GetConfiguration()
+ {
+ return new RijndaelEncryptionServiceConfig
+ {
+ Key = "gdDbqRpqdRbTs3mhdZh9qCaDaxJXl+e6"
+ };
+ }
+ }
+ }
+
+ public class Receiver : EndpointConfigurationBuilder
+ {
+ public Receiver()
+ {
+ EndpointSetup(c => c.RijndaelEncryptionService());
+ }
+
+ public class Handler : IHandleMessages
+ {
+ public Context Context { get; set; }
+
+ public void Handle(MessageWithSecretData message)
+ {
+ Context.Secret = message.Secret.Value;
+ Context.Done = true;
+ }
+ }
+
+ public class ConfigureEncryption : IProvideConfiguration
+ {
+ public RijndaelEncryptionServiceConfig GetConfiguration()
+ {
+ return new RijndaelEncryptionServiceConfig
+ {
+ Key = "adDbqRpqdRbTs3mhdZh9qCaDaxJXl+e6",
+ ExpiredKeys = new RijndaelExpiredKeyCollection
+ {
+ new RijndaelExpiredKey
+ {
+ Key = "gdDbqRpqdRbTs3mhdZh9qCaDaxJXl+e6"
+ }
+ }
+ };
+ }
+ }
+ }
+
+ [Serializable]
+ public class MessageWithSecretData : IMessage
+ {
+ public WireEncryptedString Secret { get; set; }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/EndpointTemplates/ConfigureExtensions.cs b/src/NServiceBus.SqlServer.AcceptanceTests/EndpointTemplates/ConfigureExtensions.cs
new file mode 100644
index 000000000..3efb0fb63
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/EndpointTemplates/ConfigureExtensions.cs
@@ -0,0 +1,187 @@
+namespace NServiceBus.AcceptanceTests.EndpointTemplates
+{
+ using System;
+ using System.Collections.Generic;
+ using ObjectBuilder.Common;
+ using ObjectBuilder.Common.Config;
+ using Persistence.InMemory.SagaPersister;
+ using Persistence.InMemory.SubscriptionStorage;
+ using Persistence.InMemory.TimeoutPersister;
+ using Persistence.Msmq.SubscriptionStorage;
+ using Persistence.Raven.SagaPersister;
+ using Persistence.Raven.SubscriptionStorage;
+ using Persistence.Raven.TimeoutPersister;
+ using ScenarioDescriptors;
+ using Serializers.Binary;
+ using Serializers.Json;
+ using Serializers.XML;
+
+ public static class ConfigureExtensions
+ {
+ public static string GetOrNull(this IDictionary dictionary, string key)
+ {
+ if (!dictionary.ContainsKey(key))
+ {
+ return null;
+ }
+
+ return dictionary[key];
+ }
+
+ public static Configure DefineTransport(this Configure config, IDictionary settings)
+ {
+ if (!settings.ContainsKey("Transport"))
+ {
+ settings = Transports.Default.Settings;
+ }
+
+ var transportType = Type.GetType(settings["Transport"]);
+
+ return config.UseTransport(transportType, () => settings["Transport.ConnectionString"]);
+ }
+
+ public static Configure DefineSerializer(this Configure config, string serializer)
+ {
+ if (string.IsNullOrEmpty(serializer))
+ {
+ return config; //xml is the default
+ }
+
+ var type = Type.GetType(serializer);
+
+ if (type == typeof(XmlMessageSerializer))
+ {
+ Configure.Serialization.Xml();
+ return config;
+ }
+
+ if (type == typeof(JsonMessageSerializer))
+ {
+ Configure.Serialization.Json();
+ return config;
+ }
+
+ if (type == typeof(BsonMessageSerializer))
+ {
+ Configure.Serialization.Bson();
+ return config;
+ }
+
+ if (type == typeof(BinaryMessageSerializer))
+ {
+ Configure.Serialization.Binary();
+ return config;
+ }
+
+ throw new InvalidOperationException("Unknown serializer:" + serializer);
+ }
+
+ public static Configure DefineTimeoutPersister(this Configure config, string persister)
+ {
+ if (string.IsNullOrEmpty(persister))
+ {
+ persister = TimeoutPersisters.Default.Settings["TimeoutPersister"];
+ }
+
+ if (persister.Contains(typeof(InMemoryTimeoutPersistence).FullName))
+ {
+ return config.UseInMemoryTimeoutPersister();
+ }
+
+ if (persister.Contains(typeof(RavenTimeoutPersistence).FullName))
+ {
+ config.RavenPersistence(() => "url=http://localhost:8080");
+ return config.UseRavenTimeoutPersister();
+ }
+
+ CallConfigureForPersister(config, persister);
+
+ return config;
+ }
+
+ public static Configure DefineSagaPersister(this Configure config, string persister)
+ {
+ if (string.IsNullOrEmpty(persister))
+ {
+ persister = SagaPersisters.Default.Settings["SagaPersister"];
+ }
+
+ if (persister.Contains(typeof(InMemorySagaPersister).FullName))
+ {
+ return config.InMemorySagaPersister();
+ }
+
+ if (persister.Contains(typeof(RavenSagaPersister).FullName))
+ {
+ config.RavenPersistence(() => "url=http://localhost:8080");
+ return config.RavenSagaPersister();
+ }
+
+ CallConfigureForPersister(config, persister);
+
+ return config;
+ }
+
+ public static Configure DefineSubscriptionStorage(this Configure config, string persister)
+ {
+ if (string.IsNullOrEmpty(persister))
+ {
+ persister = SubscriptionPersisters.Default.Settings["SubscriptionStorage"];
+ }
+
+ if (persister.Contains(typeof(InMemorySubscriptionStorage).FullName))
+ {
+ return config.InMemorySubscriptionStorage();
+ }
+
+ if (persister.Contains(typeof(RavenSubscriptionStorage).FullName))
+ {
+ config.RavenPersistence(() => "url=http://localhost:8080");
+ return config.RavenSubscriptionStorage();
+ }
+
+ if (persister.Contains(typeof(MsmqSubscriptionStorage).FullName))
+ {
+ return config.MsmqSubscriptionStorage();
+ }
+
+ CallConfigureForPersister(config, persister);
+
+ return config;
+ }
+
+ static void CallConfigureForPersister(Configure config, string persister)
+ {
+ var type = Type.GetType(persister);
+
+ var typeName = "Configure" + type.Name;
+
+ var configurerType = Type.GetType(typeName, false);
+
+ if (configurerType == null)
+ {
+ return;
+ }
+
+ var configurer = Activator.CreateInstance(configurerType);
+
+ dynamic dc = configurer;
+
+ dc.Configure(config);
+ }
+
+ public static Configure DefineBuilder(this Configure config, string builder)
+ {
+ if (string.IsNullOrEmpty(builder))
+ {
+ return config.DefaultBuilder();
+ }
+
+ var container = (IContainer) Activator.CreateInstance(Type.GetType(builder));
+
+ ConfigureCommon.With(config, container);
+
+ return config;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/EndpointTemplates/ContextAppender.cs b/src/NServiceBus.SqlServer.AcceptanceTests/EndpointTemplates/ContextAppender.cs
new file mode 100644
index 000000000..08d576545
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/EndpointTemplates/ContextAppender.cs
@@ -0,0 +1,35 @@
+namespace NServiceBus.AcceptanceTests.EndpointTemplates
+{
+ using AcceptanceTesting;
+ using AcceptanceTesting.Support;
+ using log4net.Appender;
+ using log4net.Core;
+
+ public class ContextAppender : AppenderSkeleton
+ {
+ public ContextAppender(ScenarioContext context, EndpointConfiguration endpointConfiguration)
+ {
+ this.context = context;
+ this.endpointConfiguration = endpointConfiguration;
+ }
+
+ protected override void Append(LoggingEvent loggingEvent)
+ {
+ if (!endpointConfiguration.AllowExceptions && loggingEvent.ExceptionObject != null)
+ {
+ lock (context)
+ {
+ context.Exceptions += loggingEvent.ExceptionObject + "/n/r";
+ }
+ }
+ if (loggingEvent.Level >= Level.Warn)
+ {
+ context.RecordLog(endpointConfiguration.EndpointName, loggingEvent.Level.ToString(), loggingEvent.RenderedMessage);
+ }
+
+ }
+
+ ScenarioContext context;
+ readonly EndpointConfiguration endpointConfiguration;
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/EndpointTemplates/DefaultServer.cs b/src/NServiceBus.SqlServer.AcceptanceTests/EndpointTemplates/DefaultServer.cs
new file mode 100644
index 000000000..bd23f7021
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/EndpointTemplates/DefaultServer.cs
@@ -0,0 +1,84 @@
+namespace NServiceBus.AcceptanceTests.EndpointTemplates
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Reflection;
+ using AcceptanceTesting.Support;
+ using Config.ConfigurationSource;
+ using Hosting.Helpers;
+ using NServiceBus;
+ using Settings;
+
+ public class DefaultServer : IEndpointSetupTemplate
+ {
+ public Configure GetConfiguration(RunDescriptor runDescriptor, EndpointConfiguration endpointConfiguration, IConfigurationSource configSource)
+ {
+ var settings = runDescriptor.Settings;
+
+ SetLoggingLibrary.Log4Net(null, new ContextAppender(runDescriptor.ScenarioContext, endpointConfiguration));
+
+ var types = GetTypesToUse(endpointConfiguration);
+
+ var transportToUse = settings.GetOrNull("Transport");
+
+ Configure.Features.Enable();
+
+ SettingsHolder.SetDefault("ScaleOut.UseSingleBrokerQueue", true);
+
+ var config = Configure.With(types)
+ .DefineEndpointName(endpointConfiguration.EndpointName)
+ .CustomConfigurationSource(configSource)
+ .DefineBuilder(settings.GetOrNull("Builder"))
+ .DefineSerializer(settings.GetOrNull("Serializer"))
+ .DefineTransport(settings)
+ .DefineSagaPersister(settings.GetOrNull("SagaPersister"));
+
+ if (transportToUse == null ||
+ transportToUse.Contains("Msmq") ||
+ transportToUse.Contains("SqlServer") ||
+ transportToUse.Contains("RabbitMq"))
+ {
+ config.DefineTimeoutPersister(settings.GetOrNull("TimeoutPersister"));
+ }
+
+ if (transportToUse == null || transportToUse.Contains("Msmq") || transportToUse.Contains("SqlServer"))
+ {
+ config.DefineSubscriptionStorage(settings.GetOrNull("SubscriptionStorage"));
+ }
+
+ return config.UnicastBus();
+ }
+
+ static IEnumerable GetTypesToUse(EndpointConfiguration endpointConfiguration)
+ {
+ var assemblies = new AssemblyScanner().GetScannableAssemblies();
+
+ var types = assemblies.Assemblies
+ //exclude all test types by default
+ .Where(a => a != Assembly.GetExecutingAssembly())
+ .SelectMany(a => a.GetTypes());
+
+
+ types = types.Union(GetNestedTypeRecursive(endpointConfiguration.BuilderType.DeclaringType, endpointConfiguration.BuilderType));
+
+ types = types.Union(endpointConfiguration.TypesToInclude);
+
+ return types.Where(t => !endpointConfiguration.TypesToExclude.Contains(t)).ToList();
+ }
+
+ static IEnumerable GetNestedTypeRecursive(Type rootType, Type builderType)
+ {
+ yield return rootType;
+
+ if (typeof(IEndpointConfigurationFactory).IsAssignableFrom(rootType) && rootType != builderType)
+ yield break;
+
+ foreach (var nestedType in rootType.GetNestedTypes(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).SelectMany(t => GetNestedTypeRecursive(t, builderType)))
+ {
+ yield return nestedType;
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/SerializerCorrupter.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/SerializerCorrupter.cs
new file mode 100644
index 000000000..80ccecc78
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/SerializerCorrupter.cs
@@ -0,0 +1,17 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Reflection;
+
+ static class SerializerCorrupter
+ {
+
+ public static void Corrupt()
+ {
+ var msmqUtilitiesType = Type.GetType("NServiceBus.Transports.Msmq.MsmqUtilities, NServiceBus.Core");
+ var headerSerializerField = msmqUtilitiesType.GetField("headerSerializer", BindingFlags.Static | BindingFlags.NonPublic);
+ headerSerializerField.SetValue(null, null);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/When_cant_convert_to_TransportMessage.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/When_cant_convert_to_TransportMessage.cs
new file mode 100644
index 000000000..a5e0adddc
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/When_cant_convert_to_TransportMessage.cs
@@ -0,0 +1,56 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Linq;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.AcceptanceTests.EndpointTemplates;
+ using NUnit.Framework;
+
+ public class When_cant_convert_to_TransportMessage : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_send_message_to_error_queue()
+ {
+ Scenario.Define()
+ .WithEndpoint(b => b.Given(bus => bus.Send(new Message())))
+ .WithEndpoint()
+ .Done(c => c.GetAllLogs().Any(l => l.Level == "error"))
+ .Repeat(r => r.For(ScenarioDescriptors.Transports.Msmq))
+ .Should(c =>
+ {
+ var logs = c.GetAllLogs();
+ Assert.True(logs.Any(l => l.Message.Contains("is corrupt and will be moved to")));
+ })
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ }
+
+ public class Sender : EndpointConfigurationBuilder
+ {
+ public Sender()
+ {
+ EndpointSetup()
+ .AddMapping(typeof(Receiver));
+ }
+ }
+
+ public class Receiver : EndpointConfigurationBuilder
+ {
+ public Receiver()
+ {
+ SerializerCorrupter.Corrupt();
+ EndpointSetup()
+ .AllowExceptions();
+ }
+
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/When_cant_convert_to_TransportMessage_NoTransactions.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/When_cant_convert_to_TransportMessage_NoTransactions.cs
new file mode 100644
index 000000000..39936aff5
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/When_cant_convert_to_TransportMessage_NoTransactions.cs
@@ -0,0 +1,58 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Linq;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.AcceptanceTests.EndpointTemplates;
+ using NUnit.Framework;
+ using IMessage = NServiceBus.IMessage;
+
+ public class When_cant_convert_to_TransportMessage_NoTransactions : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_send_message_to_error_queue()
+ {
+ Scenario.Define()
+ .WithEndpoint(b => b.Given(bus => bus.Send(new Message())))
+ .WithEndpoint()
+ .Done(c => c.GetAllLogs().Any(l => l.Level == "error"))
+ .Repeat(r => r.For(ScenarioDescriptors.Transports.Msmq))
+ .Should(c =>
+ {
+ var logs = c.GetAllLogs();
+ Assert.True(logs.Any(l => l.Message.Contains("is corrupt and will be moved to")));
+ })
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ }
+
+ public class Sender : EndpointConfigurationBuilder
+ {
+ public Sender()
+ {
+ Configure.Transactions.Disable();
+ EndpointSetup()
+ .AddMapping(typeof(Receiver));
+ }
+ }
+
+ public class Receiver : EndpointConfigurationBuilder
+ {
+ public Receiver()
+ {
+ SerializerCorrupter.Corrupt();
+ Configure.Transactions.Disable();
+ EndpointSetup()
+ .AllowExceptions();
+ }
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/When_cant_convert_to_TransportMessage_SuppressedDTC.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/When_cant_convert_to_TransportMessage_SuppressedDTC.cs
new file mode 100644
index 000000000..77ba20bc7
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/Cant_convert_to_TransportMessage/When_cant_convert_to_TransportMessage_SuppressedDTC.cs
@@ -0,0 +1,57 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Linq;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.AcceptanceTests.EndpointTemplates;
+ using NUnit.Framework;
+
+ public class When_cant_convert_to_TransportMessage_SuppressedDTC : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_send_message_to_error_queue()
+ {
+ Scenario.Define()
+ .WithEndpoint(b => b.Given(bus => bus.Send(new Message())))
+ .WithEndpoint()
+ .Done(c => c.GetAllLogs().Any(l => l.Level == "error"))
+ .Repeat(r => r.For(ScenarioDescriptors.Transports.Msmq))
+ .Should(c =>
+ {
+ var logs = c.GetAllLogs();
+ Assert.True(logs.Any(l => l.Message.Contains("is corrupt and will be moved to")));
+ })
+ .Run();
+ }
+
+ public class Context : ScenarioContext
+ {
+ }
+
+ public class Sender : EndpointConfigurationBuilder
+ {
+ public Sender()
+ {
+ Configure.Transactions.Advanced(settings => settings.DisableDistributedTransactions());
+ EndpointSetup()
+ .AddMapping(typeof(Receiver));
+ }
+ }
+
+ public class Receiver : EndpointConfigurationBuilder
+ {
+ public Receiver()
+ {
+ SerializerCorrupter.Corrupt();
+ Configure.Transactions.Advanced(settings => settings.DisableDistributedTransactions());
+ EndpointSetup()
+ .AllowExceptions();
+ }
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/StackTraceAssert.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/StackTraceAssert.cs
new file mode 100644
index 000000000..a6293edae
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/StackTraceAssert.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ static class StackTraceAssert
+ {
+// ReSharper disable once UnusedParameter.Global
+ public static void StartsWith(string expected, string actual)
+ {
+ if (actual == null)
+ {
+ Assert.Fail();
+ }
+ else
+ {
+ var cleanStackTrace = CleanStackTrace(actual);
+ try
+ {
+ Assert.IsTrue(cleanStackTrace.Replace("\r\n", "\n").StartsWith(expected.Replace("\r\n", "\n")));
+ }
+ catch (Exception)
+ {
+ Trace.WriteLine(cleanStackTrace);
+ throw;
+ }
+ }
+ }
+ static string CleanStackTrace(string stackTrace)
+ {
+ if (stackTrace== null)
+ {
+ return string.Empty;
+ }
+ using (var stringReader = new StringReader(stackTrace))
+ {
+ var stringBuilder = new StringBuilder();
+ while (true)
+ {
+ var line = stringReader.ReadLine();
+ if (line == null)
+ {
+ break;
+ }
+
+ stringBuilder.AppendLine(line.Split(new[]
+ {
+ " in "
+ }, StringSplitOptions.RemoveEmptyEntries).First().Trim());
+ }
+ return stringBuilder.ToString().Trim();
+ }
+ }
+ }
+}
+
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_Begin_and_different_End_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_Begin_and_different_End_throws.cs
new file mode 100644
index 000000000..3bd98448b
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_Begin_and_different_End_throws.cs
@@ -0,0 +1,153 @@
+#pragma warning disable 0618
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using Faults;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NServiceBus.Config;
+ using NUnit.Framework;
+
+ public class When_Module_Begin_and_different_End_throws : NServiceBusAcceptanceTest
+ {
+ [Test]
+ [Explicit]
+ public void Should_receive_AggregateException_with_both_exceptions()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+
+ var exceptionType = context.ExceptionType;
+ Assert.AreEqual(typeof(AggregateException), exceptionType);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public Type ExceptionType { get; set; }
+ public string Log { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ Context.ExceptionType = e.GetType();
+ Context.StackTrace = e.StackTrace;
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+
+ }
+ }
+
+ class MessageModuleThatThrowsInBegin : IMessageModule
+ {
+ public Context Context { get; set; }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleBeginMessage()
+ {
+ Context.Log += "ThrowsInBegin Begin\r\n";
+ throw new BeginException();
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleEndMessage()
+ {
+ Context.Log += "ThrowsInBegin Begin\r\n";
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleError()
+ {
+ Context.Log += "ThrowsInBegin Begin\r\n";
+ }
+ }
+
+ class MessageModuleThatThrowsInEnd : IMessageModule
+ {
+ public Context Context { get; set; }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleBeginMessage()
+ {
+ Context.Log += "ThrowsInEnd Begin\r\n";
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleEndMessage()
+ {
+ Context.Log += "ThrowsInEnd End\r\n";
+ throw new EndException();
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleError()
+ {
+ Context.Log += "ThrowsInEnd Error\r\n";
+ }
+ }
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ }
+ }
+
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ public class BeginException : Exception
+ {
+ public BeginException()
+ : base("BeginException")
+ {
+
+ }
+ }
+ public class EndException : Exception
+ {
+ public EndException()
+ : base("EndException")
+ {
+
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_Begin_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_Begin_throws.cs
new file mode 100644
index 000000000..c8c81c09e
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_Begin_throws.cs
@@ -0,0 +1,121 @@
+#pragma warning disable 0618
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using Faults;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NServiceBus.Config;
+ using NUnit.Framework;
+
+ public class When_Module_Begin_throws : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_exception_from_begin()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+
+ Assert.AreEqual(typeof(BeginException), context.ExceptionType);
+//#if (!DEBUG)
+// StackTraceAssert.StartsWith(
+//@"at NServiceBus.AcceptanceTests.Exceptions.When_Module_Begin_throws.Endpoint.MessageModuleThatThrowsInBegin.HandleBeginMessage()
+//at System.Collections.Generic.List`1.ForEach(Action`1 action)
+//at NServiceBus.Unicast.UnicastBus.TransportStartedMessageProcessing(Object sender, StartedMessageProcessingEventArgs e)
+//at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message)
+//at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace);
+//#endif
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public Type ExceptionType { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ Context.ExceptionType = e.GetType();
+ Context.StackTrace = e.StackTrace;
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+
+ }
+ }
+
+ class MessageModuleThatThrowsInBegin:IMessageModule
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleBeginMessage()
+ {
+ throw new BeginException();
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleEndMessage()
+ {
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleError()
+ {
+ }
+ }
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ }
+ }
+
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ public class BeginException : Exception
+ {
+ public BeginException()
+ : base("BeginException")
+ {
+
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_End_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_End_throws.cs
new file mode 100644
index 000000000..a69f566ec
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_End_throws.cs
@@ -0,0 +1,121 @@
+#pragma warning disable 0618
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using Faults;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NServiceBus.Config;
+ using NUnit.Framework;
+
+ public class When_Module_End_throws : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_exception_from_end()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+
+ Assert.AreEqual(typeof(EndException), context.ExceptionType);
+//#if (!DEBUG)
+// StackTraceAssert.StartsWith(
+//@"at NServiceBus.AcceptanceTests.Exceptions.When_Module_End_throws.Endpoint.MessageModuleThatThrowsInEnd.HandleEndMessage()
+//at System.Collections.Generic.List`1.ForEach(Action`1 action)
+//at NServiceBus.Unicast.UnicastBus.TransportFinishedMessageProcessing(Object sender, FinishedMessageProcessingEventArgs e)
+//at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message)
+//at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace);
+//#endif
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public Type ExceptionType { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ Context.ExceptionType = e.GetType();
+ Context.StackTrace = e.StackTrace;
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+
+ }
+ }
+
+ class MessageModuleThatThrowsInEnd:IMessageModule
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleBeginMessage()
+ {
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleEndMessage()
+ {
+ throw new EndException();
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleError()
+ {
+ }
+ }
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ }
+ }
+
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ public class EndException : Exception
+ {
+ public EndException()
+ : base("EndException")
+ {
+
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_Error_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_Error_throws.cs
new file mode 100644
index 000000000..dda7ebe3c
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Module_Error_throws.cs
@@ -0,0 +1,122 @@
+#pragma warning disable 0618
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using Faults;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NServiceBus.Config;
+ using NUnit.Framework;
+
+ public class When_Module_Error_throws : NServiceBusAcceptanceTest
+ {
+ [Test]
+ [Explicit]
+ public void Should_receive_AggregateException_with_both_exceptions()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+ Assert.AreEqual(typeof(AggregateException), context.ExceptionType);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public Type ExceptionType { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ Context.ExceptionType = e.GetType();
+ Context.StackTrace = e.StackTrace;
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+
+ }
+ }
+
+ class MessageModuleThatThrowsInBegin:IMessageModule
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleBeginMessage()
+ {
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleEndMessage()
+ {
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleError()
+ {
+ throw new ErrorException();
+ }
+ }
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ throw new HandlerException();
+ }
+ }
+
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ public class ErrorException : Exception
+ {
+ public ErrorException()
+ : base("ErrorException")
+ {
+
+ }
+ }
+ public class HandlerException : Exception
+ {
+ public HandlerException()
+ : base("HandlerException")
+ {
+
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Uow_Begin_and_different_End_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Uow_Begin_and_different_End_throws.cs
new file mode 100644
index 000000000..01dd8c78c
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Uow_Begin_and_different_End_throws.cs
@@ -0,0 +1,194 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.AcceptanceTests.EndpointTemplates;
+ using NServiceBus.Config;
+ using NServiceBus.Faults;
+ using NServiceBus.UnitOfWork;
+ using NUnit.Framework;
+
+ public class When_Uow_Begin_and_different_End_throws : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_AggregateException_with_both_exceptions()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+
+ Assert.AreEqual(typeof(BeginException), context.InnerExceptionOneType);
+ Assert.AreEqual(typeof(EndException), context.InnerExceptionTwoType);
+
+
+//#if (!DEBUG)
+
+// StackTraceAssert.StartsWith(
+//@"at NServiceBus.UnitOfWork.UnitOfWorkBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ForwardBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Audit.AuditBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ImpersonateSenderBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.MessageHandlingLoggingBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ChildContainerBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message)
+//at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace);
+
+// var expected = string.Format(@"at NServiceBus.AcceptanceTests.Exceptions.When_Uow_Begin_and_different_End_throws.Endpoint.{0}.End(Exception ex)
+//at NServiceBus.UnitOfWork.UnitOfWorkBehavior.AppendEndExceptionsAndRethrow(Exception initialException)", context.TypeThatThrewInEnd);
+// StackTraceAssert.StartsWith(expected, context.InnerExceptionTwoStackTrace);
+
+//#endif
+
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public Type ExceptionType { get; set; }
+ public string InnerExceptionOneStackTrace { get; set; }
+ public string InnerExceptionTwoStackTrace { get; set; }
+ public Type InnerExceptionOneType { get; set; }
+ public Type InnerExceptionTwoType { get; set; }
+ public bool FirstOneExecuted { get; set; }
+ public string TypeThatThrewInEnd { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.Configurer.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork);
+ c.Configurer.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ var aggregateException = (AggregateException)e;
+ Context.StackTrace = aggregateException.StackTrace;
+ var innerExceptions = aggregateException.InnerExceptions;
+ Context.InnerExceptionOneStackTrace = innerExceptions[0].StackTrace;
+ Context.InnerExceptionTwoStackTrace = innerExceptions[1].StackTrace;
+ Context.InnerExceptionOneType = innerExceptions[0].GetType();
+ Context.InnerExceptionTwoType = innerExceptions[1].GetType();
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+
+ }
+ }
+
+ public class UnitOfWorkThatThrows1 : IManageUnitsOfWork
+ {
+ public Context Context { get; set; }
+
+ bool throwAtEnd;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Begin()
+ {
+ if (Context.FirstOneExecuted)
+ {
+ throw new BeginException();
+ }
+
+ Context.FirstOneExecuted = throwAtEnd = true;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void End(Exception ex = null)
+ {
+ if (throwAtEnd)
+ {
+ Context.TypeThatThrewInEnd = GetType().Name;
+
+ throw new EndException();
+ }
+ }
+ }
+ public class UnitOfWorkThatThrows2 : IManageUnitsOfWork
+ {
+ public Context Context { get; set; }
+
+ bool throwAtEnd;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Begin()
+ {
+ if (Context.FirstOneExecuted)
+ {
+ throw new BeginException();
+ }
+
+ Context.FirstOneExecuted = throwAtEnd = true;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void End(Exception ex = null)
+ {
+ if (throwAtEnd)
+ {
+ Context.TypeThatThrewInEnd = GetType().Name;
+
+ throw new EndException();
+ }
+ }
+ }
+
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ }
+ }
+
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ public class BeginException : Exception
+ {
+ public BeginException()
+ : base("BeginException")
+ {
+
+ }
+ }
+ public class EndException : Exception
+ {
+ public EndException()
+ : base("EndException")
+ {
+
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Uow_Begin_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Uow_Begin_throws.cs
new file mode 100644
index 000000000..1df9f6c6c
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Uow_Begin_throws.cs
@@ -0,0 +1,121 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.AcceptanceTests.EndpointTemplates;
+ using NServiceBus.Config;
+ using NServiceBus.Faults;
+ using NServiceBus.UnitOfWork;
+ using NUnit.Framework;
+
+ public class When_Uow_Begin_throws : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_exception_thrown_from_begin()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+
+ Assert.AreEqual(typeof(BeginException), context.ExceptionType);
+//#if (!DEBUG)
+// StackTraceAssert.StartsWith(
+//@"at NServiceBus.AcceptanceTests.Exceptions.When_Uow_Begin_throws.Endpoint.UnitOfWorkThatThrowsInBegin.Begin()
+//at NServiceBus.UnitOfWork.UnitOfWorkBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ForwardBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Audit.AuditBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ImpersonateSenderBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.MessageHandlingLoggingBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ChildContainerBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message)
+//at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace);
+//#endif
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public Type ExceptionType { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.Configurer.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ Context.ExceptionType = e.GetType();
+ Context.StackTrace = e.StackTrace;
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+
+ }
+ }
+
+ public class UnitOfWorkThatThrowsInBegin : IManageUnitsOfWork
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Begin()
+ {
+ throw new BeginException();
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void End(Exception ex = null)
+ {
+ }
+ }
+
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ }
+ }
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ public class BeginException : Exception
+ {
+ public BeginException()
+ : base("BeginException")
+ {
+
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Uow_End_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Uow_End_throws.cs
new file mode 100644
index 000000000..2e041809e
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_Uow_End_throws.cs
@@ -0,0 +1,120 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.AcceptanceTests.EndpointTemplates;
+ using NServiceBus.Config;
+ using NServiceBus.Faults;
+ using NServiceBus.UnitOfWork;
+ using NUnit.Framework;
+
+ public class When_Uow_End_throws : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_exception_thrown_from_end()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+
+ Assert.AreEqual(typeof(EndException), context.ExceptionType);
+//#if(!DEBUG)
+// StackTraceAssert.StartsWith(
+//@"at NServiceBus.AcceptanceTests.Exceptions.When_Uow_End_throws.Endpoint.UnitOfWorkThatThrowsInEnd.End(Exception ex)
+//at NServiceBus.UnitOfWork.UnitOfWorkBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ForwardBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Audit.AuditBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ImpersonateSenderBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.MessageHandlingLoggingBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ChildContainerBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message)
+//at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace);
+//#endif
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public Type ExceptionType { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.Configurer.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ Context.ExceptionType = e.GetType();
+ Context.StackTrace = e.StackTrace;
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+
+ }
+ }
+
+ class UnitOfWorkThatThrowsInEnd : IManageUnitsOfWork
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Begin()
+ {
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void End(Exception ex = null)
+ {
+ throw new EndException();
+ }
+ }
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ }
+ }
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ public class EndException : Exception
+ {
+ public EndException()
+ : base("EndException")
+ {
+
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_and_Module_End_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_and_Module_End_throws.cs
new file mode 100644
index 000000000..237e94062
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_and_Module_End_throws.cs
@@ -0,0 +1,133 @@
+#pragma warning disable 0618
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using Faults;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NServiceBus.Config;
+ using NUnit.Framework;
+
+ public class When_handler_and_Module_End_throws : NServiceBusAcceptanceTest
+ {
+ [Test]
+ [Explicit]
+ public void Should_receive_AggregateException_with_both_exceptions()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+
+ var exceptionType = context.ExceptionType;
+ Assert.AreEqual(typeof(AggregateException), exceptionType);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public Type ExceptionType { get; set; }
+ public string InnerExceptionOneStackTrace { get; set; }
+ public string InnerExceptionTwoStackTrace { get; set; }
+ public Type InnerExceptionOneType { get; set; }
+ public Type InnerExceptionTwoType { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ var aggregateException = (AggregateException)e;
+ Context.StackTrace = aggregateException.StackTrace;
+ var exceptions = aggregateException.InnerExceptions;
+ Context.InnerExceptionOneStackTrace = exceptions[0].StackTrace;
+ Context.InnerExceptionTwoStackTrace = exceptions[1].StackTrace;
+ Context.InnerExceptionOneType = exceptions[0].GetType();
+ Context.InnerExceptionTwoType = exceptions[1].GetType();
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+
+ }
+ }
+
+ class MessageModuleThatThrowsInBegin:IMessageModule
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleBeginMessage()
+ {
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleEndMessage()
+ {
+ throw new EndException();
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void HandleError()
+ {
+ }
+ }
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ throw new HandlerException();
+ }
+ }
+
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ public class EndException : Exception
+ {
+ public EndException()
+ : base("EndException")
+ {
+
+ }
+ }
+ public class HandlerException : Exception
+ {
+ public HandlerException()
+ : base("HandlerException")
+ {
+
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_and_Uow_End_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_and_Uow_End_throws.cs
new file mode 100644
index 000000000..7093b10e0
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_and_Uow_End_throws.cs
@@ -0,0 +1,211 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.AcceptanceTests.EndpointTemplates;
+ using NServiceBus.Config;
+ using NServiceBus.Faults;
+ using NServiceBus.UnitOfWork;
+ using NUnit.Framework;
+
+ public class When_handler_and_Uow_End_throws : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_AggregateException_with_both_exceptions()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+
+ Assert.AreEqual(typeof(HandlerException), context.InnerExceptionOneType);
+ Assert.AreEqual(typeof(EndException), context.InnerExceptionTwoType);
+
+//#if (!DEBUG)
+// StackTraceAssert.StartsWith(
+//@"at NServiceBus.UnitOfWork.UnitOfWorkBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ForwardBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Audit.AuditBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ImpersonateSenderBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.MessageHandlingLoggingBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ChildContainerBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message)
+//at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace);
+
+// StackTraceAssert.StartsWith(
+//@"at NServiceBus.AcceptanceTests.Exceptions.When_handler_and_Uow_End_throws.Endpoint.Handler.Handle(Message message)
+//at NServiceBus.Unicast.HandlerInvocationCache.Invoke(Object handler, Object message, Dictionary`2 dictionary)
+//at NServiceBus.Unicast.Behaviors.InvokeHandlersBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Sagas.SagaPersistenceBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Sagas.AuditInvokedSagaBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.SetCurrentMessageBeingHandledBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context)
+//at NServiceBus.Unicast.Behaviors.LoadHandlersBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.DataBus.DataBusReceiveBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.Pipeline.MessageMutator.ApplyIncomingMessageMutatorsBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context)
+//at NServiceBus.Unicast.Messages.ExecuteLogicalMessagesBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.CallbackInvocationBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Messages.ExtractLogicalMessagesBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Sagas.RemoveIncomingHeadersBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.MessageMutator.ApplyIncomingTransportMessageMutatorsBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.UnitOfWork.UnitOfWorkBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)", context.InnerExceptionOneStackTrace);
+
+// StackTraceAssert.StartsWith(
+//string.Format(@"at NServiceBus.AcceptanceTests.Exceptions.When_handler_and_Uow_End_throws.Endpoint.UnitOfWorkThatThrows1.End(Exception ex)
+//at NServiceBus.UnitOfWork.UnitOfWorkBehavior.AppendEndExceptionsAndRethrow(Exception initialException)", context.TypeName), context.InnerExceptionTwoStackTrace);
+
+//#endif
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public string InnerExceptionOneStackTrace { get; set; }
+ public string InnerExceptionTwoStackTrace { get; set; }
+ public Type InnerExceptionOneType { get; set; }
+ public Type InnerExceptionTwoType { get; set; }
+ public bool FirstOneExecuted { get; set; }
+ public string TypeName { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.Configurer.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork);
+ c.Configurer.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ var aggregateException = (AggregateException)e;
+ Context.StackTrace = aggregateException.StackTrace;
+ var exceptions = aggregateException.InnerExceptions;
+ Context.InnerExceptionOneStackTrace = exceptions[0].StackTrace;
+ Context.InnerExceptionTwoStackTrace = exceptions[1].StackTrace;
+ Context.InnerExceptionOneType = exceptions[0].GetType();
+ Context.InnerExceptionTwoType = exceptions[1].GetType();
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+
+ }
+ }
+
+ public class UnitOfWorkThatThrows1 : IManageUnitsOfWork
+ {
+ public Context Context { get; set; }
+
+ bool executedInSecondPlace;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Begin()
+ {
+ if (Context.FirstOneExecuted)
+ {
+ executedInSecondPlace = true;
+ }
+
+ Context.FirstOneExecuted = true;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void End(Exception ex = null)
+ {
+ if (executedInSecondPlace)
+ {
+ Context.TypeName = GetType().Name;
+
+ throw new EndException();
+ }
+ }
+ }
+
+ public class UnitOfWorkThatThrows2 : IManageUnitsOfWork
+ {
+ public Context Context { get; set; }
+
+ bool executedInSecondPlace;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Begin()
+ {
+ if (Context.FirstOneExecuted)
+ {
+ executedInSecondPlace = true;
+ }
+
+ Context.FirstOneExecuted = true;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void End(Exception ex = null)
+ {
+ if (executedInSecondPlace)
+ {
+ Context.TypeName = GetType().Name;
+
+ throw new EndException();
+ }
+ }
+ }
+
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ throw new HandlerException();
+ }
+ }
+
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ public class HandlerException : Exception
+ {
+ public HandlerException()
+ : base("HandlerException")
+ {
+
+ }
+ }
+ public class EndException : Exception
+ {
+ public EndException()
+ : base("EndException")
+ {
+
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_throws.cs
new file mode 100644
index 000000000..58473cd5b
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_throws.cs
@@ -0,0 +1,119 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.AcceptanceTests.EndpointTemplates;
+ using NServiceBus.Config;
+ using NServiceBus.Faults;
+ using NUnit.Framework;
+
+ public class When_handler_throws : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_exception_from_handler()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+ Assert.AreEqual(typeof(HandlerException), context.ExceptionType);
+//#if (!DEBUG)
+// StackTraceAssert.StartsWith(
+//@"at NServiceBus.AcceptanceTests.Exceptions.When_handler_throws.Endpoint.Handler.Handle(Message message)
+//at NServiceBus.Unicast.HandlerInvocationCache.Invoke(Object handler, Object message, Dictionary`2 dictionary)
+//at NServiceBus.Unicast.Behaviors.InvokeHandlersBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Sagas.SagaPersistenceBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Sagas.AuditInvokedSagaBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.SetCurrentMessageBeingHandledBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context)
+//at NServiceBus.Unicast.Behaviors.LoadHandlersBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.DataBus.DataBusReceiveBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.Pipeline.MessageMutator.ApplyIncomingMessageMutatorsBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context)
+//at NServiceBus.Unicast.Messages.ExecuteLogicalMessagesBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.CallbackInvocationBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Messages.ExtractLogicalMessagesBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Sagas.RemoveIncomingHeadersBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.MessageMutator.ApplyIncomingTransportMessageMutatorsBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.UnitOfWork.UnitOfWorkBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ForwardBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Audit.AuditBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ImpersonateSenderBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.MessageHandlingLoggingBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ChildContainerBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message)
+//at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace);
+//#endif
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public Type ExceptionType { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ Context.ExceptionType = e.GetType();
+ Context.StackTrace = e.StackTrace;
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+ }
+ }
+
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ throw new HandlerException();
+ }
+ }
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ public class HandlerException : Exception
+ {
+ public HandlerException()
+ : base("HandlerException")
+ {
+
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_throws_AggregateException.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_throws_AggregateException.cs
new file mode 100644
index 000000000..911f29855
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_throws_AggregateException.cs
@@ -0,0 +1,142 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.AcceptanceTests.EndpointTemplates;
+ using NServiceBus.Config;
+ using NServiceBus.Faults;
+ using NUnit.Framework;
+
+ public class When_handler_throws_AggregateException : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_exact_AggregateException_exception_from_handler()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+ Assert.AreEqual(typeof(AggregateException), context.ExceptionType);
+ Assert.AreEqual(typeof(Exception), context.InnerExceptionType);
+ Assert.AreEqual("My Exception", context.ExceptionMessage);
+ Assert.AreEqual("My Inner Exception", context.InnerExceptionMessage);
+
+//#if (!DEBUG)
+// StackTraceAssert.StartsWith(
+// @"at NServiceBus.AcceptanceTests.Exceptions.When_handler_throws_AggregateException.Endpoint.Handler.Handle(Message message)
+//at NServiceBus.Unicast.HandlerInvocationCache.Invoke(Object handler, Object message, Dictionary`2 dictionary)
+//at NServiceBus.Unicast.Behaviors.InvokeHandlersBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Sagas.SagaPersistenceBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Sagas.AuditInvokedSagaBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.SetCurrentMessageBeingHandledBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context)
+//at NServiceBus.Unicast.Behaviors.LoadHandlersBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.DataBus.DataBusReceiveBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.Pipeline.MessageMutator.ApplyIncomingMessageMutatorsBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context)
+//at NServiceBus.Unicast.Messages.ExecuteLogicalMessagesBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.CallbackInvocationBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Messages.ExtractLogicalMessagesBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Sagas.RemoveIncomingHeadersBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.MessageMutator.ApplyIncomingTransportMessageMutatorsBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.UnitOfWork.UnitOfWorkBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ForwardBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Audit.AuditBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ImpersonateSenderBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.MessageHandlingLoggingBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ChildContainerBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message)
+//at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace);
+
+// StackTraceAssert.StartsWith(
+// @"at NServiceBus.AcceptanceTests.Exceptions.When_handler_throws_AggregateException.Endpoint.Handler.MethodThatThrows()
+//at NServiceBus.AcceptanceTests.Exceptions.When_handler_throws_AggregateException.Endpoint.Handler.Handle(Message message)", context.InnerStackTrace);
+//#endif
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public string InnerStackTrace { get; set; }
+ public Type InnerExceptionType { get; set; }
+ public string ExceptionMessage { get; set; }
+ public string InnerExceptionMessage { get; set; }
+ public Type ExceptionType { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ Context.ExceptionMessage = e.Message;
+ Context.StackTrace = e.StackTrace;
+ Context.ExceptionType = e.GetType();
+ if (e.InnerException != null)
+ {
+ Context.InnerExceptionMessage = e.InnerException.Message;
+ Context.InnerExceptionType = e.InnerException.GetType();
+ Context.InnerStackTrace = e.InnerException.StackTrace;
+ }
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+ }
+ }
+
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ try
+ {
+ MethodThatThrows();
+ }
+ catch (Exception exception)
+ {
+ throw new AggregateException("My Exception", exception);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ void MethodThatThrows()
+ {
+ throw new Exception("My Inner Exception");
+ }
+ }
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_throws_with_Dispatcher.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_throws_with_Dispatcher.cs
new file mode 100644
index 000000000..2f7db74ac
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_handler_throws_with_Dispatcher.cs
@@ -0,0 +1,139 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Runtime.CompilerServices;
+ using Faults;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NServiceBus.Config;
+ using NServiceBus.ObjectBuilder;
+ using NServiceBus.Unicast;
+ using NUnit.Framework;
+
+ public class When_handler_throws_with_Dispatcher : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_exception_from_handler()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+ Assert.AreEqual(typeof(HandlerException), context.ExceptionType);
+//#if (!DEBUG)
+// StackTraceAssert.StartsWith(
+//@"at NServiceBus.AcceptanceTests.Exceptions.When_handler_throws_with_Dispatcher.Endpoint.Handler.Handle(Message message)
+//at NServiceBus.Unicast.Behaviors.InvokeHandlersBehavior.<>c__DisplayClass2.b__0(Action dispatch)
+//at System.Collections.Generic.List`1.ForEach(Action`1 action)
+//at NServiceBus.Unicast.Behaviors.InvokeHandlersBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Sagas.SagaPersistenceBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Sagas.AuditInvokedSagaBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.SetCurrentMessageBeingHandledBehavior.Invoke(HandlerInvocationContext context, Action next)
+//at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context)
+//at NServiceBus.Unicast.Behaviors.LoadHandlersBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.DataBus.DataBusReceiveBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.Pipeline.MessageMutator.ApplyIncomingMessageMutatorsBehavior.Invoke(ReceiveLogicalMessageContext context, Action next)
+//at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context)
+//at NServiceBus.Unicast.Messages.ExecuteLogicalMessagesBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.CallbackInvocationBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Messages.ExtractLogicalMessagesBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Sagas.RemoveIncomingHeadersBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.MessageMutator.ApplyIncomingTransportMessageMutatorsBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.UnitOfWork.UnitOfWorkBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ForwardBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Audit.AuditBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ImpersonateSenderBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.MessageHandlingLoggingBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Behaviors.ChildContainerBehavior.Invoke(ReceivePhysicalMessageContext context, Action next)
+//at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message)
+//at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message)", context.StackTrace);
+//#endif
+
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public Type ExceptionType { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ Context.ExceptionType = e.GetType();
+ Context.StackTrace = e.StackTrace;
+ Context.ExceptionReceived = true;
+ }
+
+ public void Init(Address address)
+ {
+ }
+ }
+
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ throw new HandlerException();
+ }
+ }
+
+ class MyDispatcher : IMessageDispatcherFactory
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public IEnumerable GetDispatcher(Type messageHandlerType, IBuilder builder, object toHandle)
+ {
+ yield return () => new Handler().Handle((Message) toHandle);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public bool CanDispatch(Type handler)
+ {
+ return handler == typeof(Handler);
+ }
+ }
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+
+ public class HandlerException : Exception
+ {
+ public HandlerException()
+ : base("HandlerException")
+ {
+
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_processing_a_message_without_an_id.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_processing_a_message_without_an_id.cs
new file mode 100644
index 000000000..4fd3fa690
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_processing_a_message_without_an_id.cs
@@ -0,0 +1,100 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.AcceptanceTests.EndpointTemplates;
+ using NServiceBus.Config;
+ using NServiceBus.MessageMutator;
+ using NServiceBus.Unicast;
+ using NServiceBus.Unicast.Transport;
+ using NUnit.Framework;
+
+ public class When_processing_a_message_without_an_id : NServiceBusAcceptanceTest
+ {
+ [Test]
+ [Explicit( "In light of https://github.com/Particular/NServiceBus.SqlServer/issues/82 this will always fail." )]
+ public void Should_invoke_start_message_processing_listeners()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.StartMessageProcessingCalled)
+ .Run();
+
+ Assert.IsTrue(context.StartMessageProcessingCalled);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool StartMessageProcessingCalled { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.InstancePerCall);
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class StartProcessingListener : IWantToRunWhenBusStartsAndStops
+ {
+ Context context;
+
+ public StartProcessingListener(UnicastBus bus, Context context)
+ {
+ this.context = context;
+ bus.Transport.StartedMessageProcessing += transport_StartedMessageProcessing;
+ }
+
+ void transport_StartedMessageProcessing(object sender, StartedMessageProcessingEventArgs e)
+ {
+ context.StartMessageProcessingCalled = true;
+ }
+
+ public void Start()
+ {
+ }
+
+ public void Stop()
+ {
+ }
+ }
+
+ class CorruptionMutator : IMutateTransportMessages
+ {
+ public void MutateIncoming(TransportMessage transportMessage)
+ {
+ }
+
+ public void MutateOutgoing(object[] messages, TransportMessage transportMessage)
+ {
+ transportMessage.Headers[Headers.MessageId] = "";
+ }
+ }
+
+ class Handler : IHandleMessages
+ {
+ public void Handle(Message message)
+ {
+ }
+ }
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_serialization_throws.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_serialization_throws.cs
new file mode 100644
index 000000000..3593d51fc
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Exceptions/When_serialization_throws.cs
@@ -0,0 +1,108 @@
+namespace NServiceBus.AcceptanceTests.Exceptions
+{
+ using System;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.Serialization;
+ using NServiceBus.AcceptanceTesting;
+ using NServiceBus.AcceptanceTests.EndpointTemplates;
+ using NServiceBus.Config;
+ using NServiceBus.Faults;
+ using NServiceBus.MessageMutator;
+ using NUnit.Framework;
+
+ public class When_serialization_throws : NServiceBusAcceptanceTest
+ {
+ [Test]
+ public void Should_receive_SerializationException()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(b => b.Given(bus => bus.SendLocal(new Message())))
+ .Done(c => c.ExceptionReceived)
+ .Run();
+
+ Assert.AreEqual(typeof(SerializationException), context.ExceptionType);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool ExceptionReceived { get; set; }
+ public string StackTrace { get; set; }
+ public Type ExceptionType { get; set; }
+ public string InnerExceptionStackTrace { get; set; }
+ public Type InnerExceptionType { get; set; }
+ }
+
+ public class Endpoint : EndpointConfigurationBuilder
+ {
+ public Endpoint()
+ {
+ EndpointSetup(c =>
+ {
+ c.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance);
+ c.Configurer.ConfigureComponent(DependencyLifecycle.InstancePerCall);
+ c.DisableTimeoutManager();
+ })
+ .WithConfig(c =>
+ {
+ c.MaxRetries = 0;
+ })
+ .AllowExceptions();
+ }
+
+ class CustomFaultManager : IManageMessageFailures
+ {
+ public Context Context { get; set; }
+
+ public void SerializationFailedForMessage(TransportMessage message, Exception e)
+ {
+ Context.ExceptionType = e.GetType();
+ Context.StackTrace = e.StackTrace;
+ if (e.InnerException != null)
+ {
+ Context.InnerExceptionType = e.InnerException.GetType();
+ Context.InnerExceptionStackTrace = e.InnerException.StackTrace;
+ }
+ Context.ExceptionReceived = true;
+ }
+
+ public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
+ {
+ }
+
+ public void Init(Address address)
+ {
+ }
+ }
+
+ class CorruptionMutator : IMutateTransportMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void MutateIncoming(TransportMessage transportMessage)
+ {
+ transportMessage.Body[1]++;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void MutateOutgoing(object[] messages, TransportMessage transportMessage)
+ {
+ }
+ }
+
+ class Handler : IHandleMessages
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void Handle(Message message)
+ {
+ }
+ }
+ }
+
+ [Serializable]
+ public class Message : IMessage
+ {
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Gateway/When_doing_request_response_between_sites.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Gateway/When_doing_request_response_between_sites.cs
new file mode 100644
index 000000000..284c15535
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Gateway/When_doing_request_response_between_sites.cs
@@ -0,0 +1,105 @@
+namespace NServiceBus.AcceptanceTests.Gateway
+{
+ using System;
+ using Config;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+
+ public class When_doing_request_response_between_sites : NServiceBusAcceptanceTest
+ {
+ [Test, Explicit( "This tests requires URLS ACL to be set on the Agent" )]
+ public void Callback_should_be_fired()
+ {
+ var context = new Context();
+
+ Scenario.Define(context)
+ .WithEndpoint(
+ b => b.Given((bus, c) =>
+ bus.SendToSites(new[] { "SiteB" }, new MyRequest())
+ .Register(result => c.GotCallback = true)))
+ .WithEndpoint()
+ .Done(c => c.GotCallback)
+ .Run(TimeSpan.FromSeconds(2000));
+
+ Assert.IsTrue(context.GotCallback);
+ }
+
+ public class Context : ScenarioContext
+ {
+ public bool GotCallback { get; set; }
+ }
+
+ public class SiteA : EndpointConfigurationBuilder
+ {
+ public SiteA()
+ {
+ EndpointSetup(c => c.RunGateway()
+ .UseInMemoryGatewayPersister())
+ .AllowExceptions()
+ .WithConfig(c =>
+ {
+ c.Sites = new SiteCollection
+ {
+ new SiteConfig
+ {
+ Key = "SiteB",
+ Address = "http://localhost:25799/SiteB/",
+ ChannelType = "http"
+ }
+ };
+
+ c.Channels = new ChannelCollection
+ {
+ new ChannelConfig
+ {
+ Address = "http://localhost:25799/SiteA/",
+ ChannelType = "http",
+ Default = true
+ }
+ };
+ });
+ }
+ }
+
+ public class SiteB : EndpointConfigurationBuilder
+ {
+ public SiteB()
+ {
+ EndpointSetup(c => c.RunGateway().UseInMemoryGatewayPersister())
+ .AllowExceptions()
+ .WithConfig(c =>
+ {
+ c.Channels = new ChannelCollection
+ {
+ new ChannelConfig
+ {
+ Address = "http://localhost:25799/SiteB/",
+ ChannelType = "http",
+ Default = true
+ }
+ };
+ });
+
+ }
+
+ public class MyRequestHandler : IHandleMessages
+ {
+ public IBus Bus { get; set; }
+ public void Handle(MyRequest request)
+ {
+ Bus.Reply(new MyResponse());
+ }
+ }
+ }
+
+ [Serializable]
+ public class MyRequest : ICommand
+ {
+ }
+ [Serializable]
+ public class MyResponse : IMessage
+ {
+ }
+ }
+}
diff --git a/src/NServiceBus.SqlServer.AcceptanceTests/Gateway/When_doing_request_response_with_databus_between_sites.cs b/src/NServiceBus.SqlServer.AcceptanceTests/Gateway/When_doing_request_response_with_databus_between_sites.cs
new file mode 100644
index 000000000..8bdbae38d
--- /dev/null
+++ b/src/NServiceBus.SqlServer.AcceptanceTests/Gateway/When_doing_request_response_with_databus_between_sites.cs
@@ -0,0 +1,143 @@
+namespace NServiceBus.AcceptanceTests.Gateway
+{
+ using System;
+ using Config;
+ using EndpointTemplates;
+ using AcceptanceTesting;
+ using NUnit.Framework;
+ using ScenarioDescriptors;
+
+ public class When_doing_request_response_with_databus_between_sites : NServiceBusAcceptanceTest
+ {
+ static readonly byte[] PayloadToSend = new byte[1024 * 1024 * 10];
+
+ [Test, Explicit("This tests requires URLS ACL to be set on the Agent")]
+ public void Should_be_able_to_reply_to_the_message_using_databus()
+ {
+ Scenario.Define