diff --git a/.gitattributes b/.gitattributes index 76f32717ea..0b6aa02467 100644 --- a/.gitattributes +++ b/.gitattributes @@ -55,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 @@ -71,6 +73,3 @@ *.snk -text -diff *.cub -text -diff *.wixlib -text -diff - - -*.approved.* binary diff --git a/.gitignore b/.gitignore index a9137e1d1d..ef7a9f241f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,22 +2,12 @@ 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 @@ -36,3 +26,60 @@ _NCrunch_NServiceBus/* logs run-git.cmd src/Chocolatey/Build/* + +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/src/NServiceBus.AcceptanceTests/NServiceBus.AcceptanceTests.csproj b/src/NServiceBus.AcceptanceTests/NServiceBus.AcceptanceTests.csproj index 137e8f770a..273071d18e 100644 --- a/src/NServiceBus.AcceptanceTests/NServiceBus.AcceptanceTests.csproj +++ b/src/NServiceBus.AcceptanceTests/NServiceBus.AcceptanceTests.csproj @@ -193,6 +193,18 @@ + + + + + + + + + + + + diff --git a/src/NServiceBus.AcceptanceTests/Timeouts/OutdatedTimeoutPersister.cs b/src/NServiceBus.AcceptanceTests/Timeouts/OutdatedTimeoutPersister.cs new file mode 100644 index 0000000000..2877dfffe5 --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/OutdatedTimeoutPersister.cs @@ -0,0 +1,30 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using System; + using System.Collections.Generic; + using System.Linq; + using NServiceBus.Timeout.Core; + + class OutdatedTimeoutPersister : IPersistTimeouts + { + public List> GetNextChunk(DateTime startSlice, out DateTime nextTimeToRunQuery) + { + nextTimeToRunQuery = DateTime.Now.AddYears(42); + return Enumerable.Empty>().ToList(); + } + + public void Add(TimeoutData timeout) + { + } + + public bool TryRemove(string timeoutId, out TimeoutData timeoutData) + { + timeoutData = null; + return false; + } + + public void RemoveTimeoutBy(Guid sagaId) + { + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.AcceptanceTests/Timeouts/UpdatedTimeoutPersister.cs b/src/NServiceBus.AcceptanceTests/Timeouts/UpdatedTimeoutPersister.cs new file mode 100644 index 0000000000..79993ee078 --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/UpdatedTimeoutPersister.cs @@ -0,0 +1,40 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using System; + using System.Collections.Generic; + using System.Linq; + using NServiceBus.Timeout.Core; + + class UpdatedTimeoutPersister : IPersistTimeouts, IPersistTimeoutsV2 + { + public List> GetNextChunk(DateTime startSlice, out DateTime nextTimeToRunQuery) + { + nextTimeToRunQuery = DateTime.Now.AddYears(42); + return Enumerable.Empty>().ToList(); + } + + public void Add(TimeoutData timeout) + { + } + + public bool TryRemove(string timeoutId, out TimeoutData timeoutData) + { + timeoutData = null; + return false; + } + + public void RemoveTimeoutBy(Guid sagaId) + { + } + + public TimeoutData Peek(string timeoutId) + { + return null; + } + + public bool TryRemove(string timeoutId) + { + return true; + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.AcceptanceTests/Timeouts/When_dispatched_timeout_already_removed_from_timeout_storage.cs b/src/NServiceBus.AcceptanceTests/Timeouts/When_dispatched_timeout_already_removed_from_timeout_storage.cs new file mode 100644 index 0000000000..ac2ece64f8 --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/When_dispatched_timeout_already_removed_from_timeout_storage.cs @@ -0,0 +1,182 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using System; + using System.Collections.Generic; + using System.Transactions; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Config; + using NServiceBus.Timeout.Core; + using NUnit.Framework; + + public class When_dispatched_timeout_already_removed_from_timeout_storage + { + [Test] + public void Should_rollback_and_not_deliver_timeout_when_using_dtc() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b + .CustomConfig(configure => Configure.Transactions.Advanced(s => s.EnableDistributedTransactions())) + .Given(bus => + { + bus.Defer(TimeSpan.FromSeconds(5), new MyMessage()); + })) + .Done(c => c.AttemptedToRemoveTimeout || c.MessageReceived) + .Run(); + + Assert.IsFalse(context.MessageReceived, "Message should not be delivered using dtc"); + Assert.AreEqual(2, context.NumberOfProcessingAttempts, "The rollback should cause a retry"); + Assert.IsTrue(context.AttemptedToRemoveTimeout); + } + + [Test] + public void Should_rollback_and_deliver_timeout_anyway_when_using_native_tx() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b + .CustomConfig(configure => Configure.Transactions.Advanced(s => s.DisableDistributedTransactions())) + .Given(bus => + { + bus.Defer(TimeSpan.FromSeconds(5), new MyMessage()); + })) + .Done(c => c.AttemptedToRemoveTimeout && c.MessageReceived) + .Run(); + + Assert.IsTrue(context.MessageReceived, "Message should only be delivered although transaction has been aborted"); + Assert.AreEqual(2, context.NumberOfProcessingAttempts, "The rollback should cause a retry"); + Assert.IsTrue(context.AttemptedToRemoveTimeout); + } + + [Test] + public void Should_deliver_timeout_anyway_when_using_no_tx() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b + .CustomConfig(configure => Configure.Transactions.Disable()) + .Given(bus => + { + bus.Defer(TimeSpan.FromSeconds(5), new MyMessage()); + })) + .Done(c => c.AttemptedToRemoveTimeout && c.MessageReceived) + .Run(); + + Assert.IsTrue(context.MessageReceived, "Message should be delivered although timeout processing fails"); + Assert.AreEqual(1, context.NumberOfProcessingAttempts, "Should not retry without transactions enabled"); + Assert.IsTrue(context.AttemptedToRemoveTimeout); + } + + public class Context : ScenarioContext + { + public bool MessageReceived { get; set; } + + public bool AttemptedToRemoveTimeout { get; set; } + + public int NumberOfProcessingAttempts { get; set; } + } + + public class TimeoutHandlingEndpoint : EndpointConfigurationBuilder + { + public TimeoutHandlingEndpoint() + { + EndpointSetup(); + } + + public class DelayedMessageHandler : IHandleMessages + { + Context context; + + public DelayedMessageHandler(Context context) + { + this.context = context; + } + + public void Handle(MyMessage message) + { + context.MessageReceived = true; + } + } + + public class EndpointConfiguration : IWantToRunWhenConfigurationIsComplete + { + Context context; + IPersistTimeouts originalPersister; + + public EndpointConfiguration(Context context, IPersistTimeouts originalPersister) + { + this.context = context; + this.originalPersister = originalPersister; + } + + public void Run() + { + Configure.Component(b => new TimeoutPersistenceWrapper(originalPersister, originalPersister as IPersistTimeoutsV2, context), DependencyLifecycle.SingleInstance); + } + } + + class TimeoutPersistenceWrapper : IPersistTimeouts, IPersistTimeoutsV2 + { + IPersistTimeouts originalTimeoutPersister; + IPersistTimeoutsV2 originalTimeoutPersisterV2; + Context context; + + public TimeoutPersistenceWrapper(IPersistTimeouts originalTimeoutPersister, IPersistTimeoutsV2 originalTimeoutPersisterV2, Context context) + { + this.originalTimeoutPersister = originalTimeoutPersister; + this.originalTimeoutPersisterV2 = originalTimeoutPersisterV2; + this.context = context; + } + + public List> GetNextChunk(DateTime startSlice, out DateTime nextTimeToRunQuery) + { + return originalTimeoutPersister.GetNextChunk(startSlice, out nextTimeToRunQuery); + } + + public void Add(TimeoutData timeout) + { + originalTimeoutPersister.Add(timeout); + } + + public bool TryRemove(string timeoutId, out TimeoutData timeoutData) + { + return originalTimeoutPersister.TryRemove(timeoutId, out timeoutData); + } + + public void RemoveTimeoutBy(Guid sagaId) + { + originalTimeoutPersister.RemoveTimeoutBy(sagaId); + } + + public TimeoutData Peek(string timeoutId) + { + context.NumberOfProcessingAttempts++; + return originalTimeoutPersisterV2.Peek(timeoutId); + } + + public bool TryRemove(string timeoutId) + { + context.AttemptedToRemoveTimeout = true; + + using (var tx = new TransactionScope(TransactionScopeOption.Suppress)) + { + // delete the timeout so it won't be available on retries + originalTimeoutPersisterV2.TryRemove(timeoutId); + tx.Complete(); + } + + return false; + } + } + } + + [Serializable] + public class MyMessage : IMessage + { + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.AcceptanceTests/Timeouts/When_dispatching_deferred_message_fails_without_dtc.cs b/src/NServiceBus.AcceptanceTests/Timeouts/When_dispatching_deferred_message_fails_without_dtc.cs new file mode 100644 index 0000000000..337490e705 --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/When_dispatching_deferred_message_fails_without_dtc.cs @@ -0,0 +1,113 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Config; + using NServiceBus.Transports; + using NUnit.Framework; + + public class When_dispatching_deferred_message_fails_without_dtc : NServiceBusAcceptanceTest + { + [Test] + public void Message_should_be_received() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(b => b.Given(bus => + { + bus.Defer(TimeSpan.FromSeconds(3), new MyMessage()); + })) + .Done(c => c.MessageReceived) + .Run(); + + Assert.IsTrue(context.SendingMessageFailedOnce); + Assert.IsTrue(context.MessageReceived); + } + + public class Context : ScenarioContext + { + public bool MessageReceived { get; set; } + + public bool SendingMessageFailedOnce { get; set; } + } + + public class TimeoutHandlingEndpoint : EndpointConfigurationBuilder + { + public TimeoutHandlingEndpoint() + { + EndpointSetup(config => + { + Configure.Transactions.Advanced(s => s.DisableDistributedTransactions()); + }).AllowExceptions(); + } + + public class DelayedMessageHandler : IHandleMessages + { + Context context; + + public DelayedMessageHandler(Context context) + { + this.context = context; + } + + public void Handle(MyMessage message) + { + context.MessageReceived = true; + } + } + + public class EndpointConfiguration : IWantToRunWhenConfigurationIsComplete + { + Context context; + ISendMessages originalMessageSender; + + public EndpointConfiguration(Context context, ISendMessages originalMessageSender) + { + this.context = context; + this.originalMessageSender = originalMessageSender; + } + + public void Run() + { + Configure.Component(b => new SenderWrapper(originalMessageSender, context), DependencyLifecycle.SingleInstance); + } + } + + class SenderWrapper : ISendMessages + { + ISendMessages wrappedSender; + Context context; + + public SenderWrapper(ISendMessages wrappedSender, Context context) + { + this.wrappedSender = wrappedSender; + this.context = context; + } + + public void Send(TransportMessage message, Address address) + { + string realtedTimeoutId; + if (message.Headers.TryGetValue("NServiceBus.RelatedToTimeoutId", out realtedTimeoutId)) + { + // dispatched message by timeout behavior + // fail first attempt: + if (!context.SendingMessageFailedOnce) + { + context.SendingMessageFailedOnce = true; + throw new Exception("simulated exception"); + } + } + + wrappedSender.Send(message, address); + } + } + } + + [Serializable] + public class MyMessage : IMessage + { + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_no_timeout_persistence.cs b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_no_timeout_persistence.cs new file mode 100644 index 0000000000..60d9b23781 --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_no_timeout_persistence.cs @@ -0,0 +1,98 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using AcceptanceTesting; + using EndpointTemplates; + using AcceptanceTesting.Support; + using Config.ConfigurationSource; + using Hosting.Helpers; + using NUnit.Framework; + + public class When_endpoint_uses_no_timeout_persistence + { + [Test] + public void Endpoint_should_start() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint() + .Done(c => c.EndpointsStarted) + .Run(); + + Assert.IsTrue(context.EndpointsStarted); + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(config => + { + config.DisableTimeoutManager(); + Configure.Transactions.Advanced(s => s.DisableDistributedTransactions()); + }); + } + } + + public class Context : ScenarioContext + { + } + + public class MinimalServer : 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 config = Configure.With(types) + //.DefineEndpointName(endpointConfiguration.EndpointName) + .CustomConfigurationSource(configSource) + .DefineBuilder(settings.GetOrNull("Builder")) + .DefineSerializer(settings.GetOrNull("Serializer")) + .DefineTransport(settings); + //.DefineSagaPersister(settings.GetOrNull("SagaPersister")); + + 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.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_sql_transport_with_disabled_dtc.cs b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_sql_transport_with_disabled_dtc.cs new file mode 100644 index 0000000000..8f8451123f --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_sql_transport_with_disabled_dtc.cs @@ -0,0 +1,81 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTesting.Support; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Settings; + using NServiceBus.Timeout.Core; + using NServiceBus.Transports; + using NUnit.Framework; + + public class When_endpoint_uses_outdated_sql_transport_with_disabled_dtc + { + [Test] + public void Endpoint_should_not_start_and_show_warning() + { + var context = new Context(); + + var scenarioException = Assert.Throws(() => Scenario.Define(context) + .WithEndpoint() + .Done(c => c.EndpointsStarted) + .Run()) + .InnerException as ScenarioException; + + Assert.IsFalse(context.EndpointsStarted); + StringAssert.Contains("You are using an outdated transport which can lead to message loss!", scenarioException.InnerException.Message); + } + + [Test] + public void Endpoint_should_start_when_warning_suppressed() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(c => c + .CustomConfig(configure => configure.SuppressOutdatedTransportWarning())) + .Done(c => c.EndpointsStarted) + .Run(); + + Assert.IsTrue(context.EndpointsStarted); + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(config => + { + config.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance); + config.UseTransport(); + Configure.Transactions.Advanced(s => s.DisableDistributedTransactions()); + }); + } + } + + public class Context : ScenarioContext + { + } + + public class OutdatedSqlServerTransport : TransportDefinition + { + // needs to contain SqlServer in the name + public OutdatedSqlServerTransport() + { + HasSupportForDistributedTransactions = true; + } + } + + public class OutdatedSqlServerTransportConfiguration : IConfigureTransport + { + public void Configure(Configure config) + { + var selectedTransportDefinition = new OutdatedSqlServerTransport(); + SettingsHolder.Set("NServiceBus.Transport.SelectedTransport", selectedTransportDefinition); + config.Configurer.RegisterSingleton(selectedTransportDefinition); + } + } + } + + +} \ No newline at end of file diff --git a/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_sql_transport_with_dtc.cs b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_sql_transport_with_dtc.cs new file mode 100644 index 0000000000..1338cdb1b5 --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_sql_transport_with_dtc.cs @@ -0,0 +1,59 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Settings; + using NServiceBus.Transports; + using NUnit.Framework; + + public class When_endpoint_uses_outdated_sql_transport_with_dtc + { + [Test] + public void Endpoint_should_start() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint() + .Done(c => c.EndpointsStarted) + .Run(); + + Assert.IsTrue(context.EndpointsStarted); + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(config => + { + config.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance); + config.UseTransport(); + }); + } + } + + public class Context : ScenarioContext + { + } + + public class OutdatedSqlServerTransport : TransportDefinition + { + // needs to contain SqlServer in the name + public OutdatedSqlServerTransport() + { + HasSupportForDistributedTransactions = true; + } + } + + public class OutdatedSqlServerTransportConfiguration : IConfigureTransport + { + public void Configure(Configure config) + { + var selectedTransportDefinition = new OutdatedSqlServerTransport(); + SettingsHolder.Set("NServiceBus.Transport.SelectedTransport", selectedTransportDefinition); + config.Configurer.RegisterSingleton(selectedTransportDefinition); + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_timeout_persistence_with_disabled_dtc.cs b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_timeout_persistence_with_disabled_dtc.cs new file mode 100644 index 0000000000..15430e4dc5 --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_timeout_persistence_with_disabled_dtc.cs @@ -0,0 +1,57 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTesting.Support; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Timeout.Core; + using NUnit.Framework; + + public class When_endpoint_uses_outdated_timeout_persistence_with_disabled_dtc + { + [Test] + public void Endpoint_should_not_start_and_show_warning() + { + var context = new Context(); + + var scenarioException = Assert.Throws(() => Scenario.Define(context) + .WithEndpoint() + .Done(c => c.EndpointsStarted) + .Run()) + .InnerException as ScenarioException; + + Assert.IsFalse(context.EndpointsStarted); + StringAssert.Contains("You are using an outdated timeout persistence which can lead to message loss!", scenarioException.InnerException.Message); + } + + [Test] + public void Endpoint_should_start_when_warning_suppressed() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint(c => c + .CustomConfig(config => config.SuppressOutdatedTimeoutPersistenceWarning())) + .Done(c => c.EndpointsStarted) + .Run(); + + Assert.IsTrue(context.EndpointsStarted); + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(config => + { + config.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance); + Configure.Transactions.Advanced(s => s.DisableDistributedTransactions()); + }); + } + } + + public class Context : ScenarioContext + { + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_timeout_persistence_with_dtc.cs b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_timeout_persistence_with_dtc.cs new file mode 100644 index 0000000000..3befc36cfe --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_timeout_persistence_with_dtc.cs @@ -0,0 +1,38 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NUnit.Framework; + + public class When_endpoint_uses_outdated_timeout_persistence_with_dtc + { + [Test] + public void Endpoint_should_start() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint() + .Done(c => c.EndpointsStarted) + .Run(); + + Assert.IsTrue(context.EndpointsStarted); + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(config => + { + config.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance); + Configure.Transactions.Advanced(s => s.EnableDistributedTransactions()); + }); + } + } + + public class Context : ScenarioContext + { + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_timeout_persistence_without_dtc.cs b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_timeout_persistence_without_dtc.cs new file mode 100644 index 0000000000..219736b63f --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_outdated_timeout_persistence_without_dtc.cs @@ -0,0 +1,62 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using System; + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTesting.Support; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Settings; + using NServiceBus.Transports; + using NUnit.Framework; + + public class When_endpoint_uses_outdated_timeout_persistence_without_dtc + { + [Test] + public void Endpoint_should_not_start_and_show_warning() + { + var context = new Context(); + + var scenarioException = Assert.Throws(() => Scenario.Define(context) + .WithEndpoint() + .Done(c => c.EndpointsStarted) + .Run()) + .InnerException as ScenarioException; + + Assert.IsFalse(context.EndpointsStarted); + StringAssert.Contains("You are using an outdated timeout persistence which can lead to message loss!", scenarioException.InnerException.Message); + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(config => + { + config.UseTransport(); + config.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance); + }); + } + } + + public class Context : ScenarioContext + { + } + + class NonDtcTransportDefinition : TransportDefinition + { + public NonDtcTransportDefinition() + { + HasSupportForDistributedTransactions = false; + } + } + + class NonDtcTransport : IConfigureTransport + { + public void Configure(Configure config) + { + var selectedTransportDefinition = Activator.CreateInstance(); + SettingsHolder.Set("NServiceBus.Transport.SelectedTransport", selectedTransportDefinition); + config.Configurer.RegisterSingleton(selectedTransportDefinition); + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_updated_sql_transport_with_disabled_dtc.cs b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_updated_sql_transport_with_disabled_dtc.cs new file mode 100644 index 0000000000..3f86c94bd5 --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_updated_sql_transport_with_disabled_dtc.cs @@ -0,0 +1,61 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NServiceBus.Settings; + using NServiceBus.Transports; + using NUnit.Framework; + + public class When_endpoint_uses_updated_sql_transport_with_disabled_dtc + { + [Test] + public void Endpoint_should_start() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint() + .Done(c => c.EndpointsStarted) + .Run(); + + Assert.IsTrue(context.EndpointsStarted); + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(config => + { + config.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance); + config.UseTransport(); + Configure.Transactions.Advanced(s => s.DisableDistributedTransactions()); + }); + } + } + + public class Context : ScenarioContext + { + } + + public class UpdatedSqlServerTransport : TransportDefinition + { + // needs to contain SqlServer in the name + public UpdatedSqlServerTransport() + { + HasSupportForDistributedTransactions = true; + SettingsHolder.Set("NServiceBus.Transport.SupportsNativeTransactionSuppression", true); + } + } + + public class UpdatedSqlServerTransportConfiguration : IConfigureTransport + { + public void Configure(Configure config) + { + var selectedTransportDefinition = new UpdatedSqlServerTransport(); + SettingsHolder.Set("NServiceBus.Transport.SelectedTransport", selectedTransportDefinition); + config.Configurer.RegisterSingleton(selectedTransportDefinition); + } + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_updated_timeout_persistence.cs b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_updated_timeout_persistence.cs new file mode 100644 index 0000000000..918a402643 --- /dev/null +++ b/src/NServiceBus.AcceptanceTests/Timeouts/When_endpoint_uses_updated_timeout_persistence.cs @@ -0,0 +1,38 @@ +namespace NServiceBus.AcceptanceTests.Timeouts +{ + using NServiceBus.AcceptanceTesting; + using NServiceBus.AcceptanceTests.EndpointTemplates; + using NUnit.Framework; + + public class When_endpoint_uses_updated_timeout_persistence + { + [Test] + public void Endpoint_should_start() + { + var context = new Context(); + + Scenario.Define(context) + .WithEndpoint() + .Done(c => c.EndpointsStarted) + .Run(); + + Assert.IsTrue(context.EndpointsStarted); + } + + public class Endpoint : EndpointConfigurationBuilder + { + public Endpoint() + { + EndpointSetup(config => + { + config.Configurer.ConfigureComponent(DependencyLifecycle.SingleInstance); + Configure.Transactions.Advanced(s => s.DisableDistributedTransactions()); + }); + } + } + + public class Context : ScenarioContext + { + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Core.Tests/Encryption/WireEncryptedStringSpecs.cs b/src/NServiceBus.Core.Tests/Encryption/WireEncryptedStringSpecs.cs index 1a9919c144..3acacc95b0 100644 --- a/src/NServiceBus.Core.Tests/Encryption/WireEncryptedStringSpecs.cs +++ b/src/NServiceBus.Core.Tests/Encryption/WireEncryptedStringSpecs.cs @@ -46,6 +46,7 @@ public class When_encrypting_a_message_with_indexed_properties : WireEncryptedSt [Test] public void Should_encrypt_the_property_correctly() { + // ReSharper disable once UseObjectOrCollectionInitializer var message = new MessageWithIndexedProperties { Secret = MySecretMessage @@ -81,6 +82,7 @@ public class When_encrypting_a_message_with_WireEncryptedString_as_an_indexed_pr [Test] public void Should_throw_exception() { + // ReSharper disable once UseObjectOrCollectionInitializer var message = new MessageWithIndexedProperties(); message[0] = MySecretMessage; @@ -129,6 +131,7 @@ public class When_decrypting_a_message_with_indexed_properties : WireEncryptedSt [Test] public void Should_decrypt_the_property_correctly() { + // ReSharper disable once UseObjectOrCollectionInitializer var message = new MessageWithIndexProperties { Secret = Create() diff --git a/src/NServiceBus.Core.Tests/Scheduler/ScheduleTests.cs b/src/NServiceBus.Core.Tests/Scheduler/ScheduleTests.cs index 05635fcf46..60d5b6d013 100644 --- a/src/NServiceBus.Core.Tests/Scheduler/ScheduleTests.cs +++ b/src/NServiceBus.Core.Tests/Scheduler/ScheduleTests.cs @@ -35,13 +35,24 @@ public void When_scheduling_an_action_with_a_name_the_task_should_get_that_name( Assert.That(EnsureThatNameExists(ACTION_NAME)); } + [Test] + public void When_scheduling_an_anonymous_action_without_a_name_the_task_should_get_the_DeclaringType_as_name() + { + Schedule.Every(TimeSpan.FromMinutes(5)).Action(() => { }); + Assert.That(EnsureThatNameExists("ScheduleTests")); + } + [Test] public void When_scheduling_an_action_without_a_name_the_task_should_get_the_DeclaringType_as_name() { - Schedule.Every(TimeSpan.FromMinutes(5)).Action(() => { }); + Schedule.Every(TimeSpan.FromMinutes(5)).Action(SomeSchedulingAction); Assert.That(EnsureThatNameExists("ScheduleTests")); } + private void SomeSchedulingAction() + { + } + [Test] public void Schedule_tasks_using_multiple_threads() { diff --git a/src/NServiceBus.Core.Tests/Serializers/XML/SerializerTests.cs b/src/NServiceBus.Core.Tests/Serializers/XML/SerializerTests.cs index 2fd2f048e6..af91876931 100644 --- a/src/NServiceBus.Core.Tests/Serializers/XML/SerializerTests.cs +++ b/src/NServiceBus.Core.Tests/Serializers/XML/SerializerTests.cs @@ -377,8 +377,10 @@ public void TestInterfaces() o.Start = DateTime.Now; o.Duration = TimeSpan.Parse("-01:15:27.123"); o.Offset = DateTimeOffset.Now; + // ReSharper disable once UseObjectOrCollectionInitializer o.Lookup = new MyDictionary(); o.Lookup["1"] = "1"; + // ReSharper disable once UseObjectOrCollectionInitializer o.Foos = new Dictionary>(); o.Foos["foo1"] = new List(new[] { new Foo { Name = "1", Title = "1" }, new Foo { Name = "2", Title = "2" } }); o.Data = new byte[] { 1, 2, 3, 4, 5, 4, 3, 2, 1 }; diff --git a/src/NServiceBus.Core/NServiceBus.Core.csproj b/src/NServiceBus.Core/NServiceBus.Core.csproj index aad3012362..3d76113a4f 100644 --- a/src/NServiceBus.Core/NServiceBus.Core.csproj +++ b/src/NServiceBus.Core/NServiceBus.Core.csproj @@ -16,6 +16,7 @@ ..\ ..\ b1e3a2fe + 4fc78492 true @@ -44,9 +45,6 @@ Designer - - ..\packages\Autofac\lib\net40\Autofac.dll - False ..\packages\Autofac.3.1.5\lib\net40\Autofac.dll @@ -178,6 +176,8 @@ + + @@ -669,13 +669,11 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - - + \ No newline at end of file diff --git a/src/NServiceBus.Core/Persistence/InMemory/TimeoutPersister/InMemoryTimeoutPersistence.cs b/src/NServiceBus.Core/Persistence/InMemory/TimeoutPersister/InMemoryTimeoutPersistence.cs index 025b9af15e..e22397ffde 100644 --- a/src/NServiceBus.Core/Persistence/InMemory/TimeoutPersister/InMemoryTimeoutPersistence.cs +++ b/src/NServiceBus.Core/Persistence/InMemory/TimeoutPersister/InMemoryTimeoutPersistence.cs @@ -5,7 +5,7 @@ namespace NServiceBus.Persistence.InMemory.TimeoutPersister using System.Linq; using Timeout.Core; - public class InMemoryTimeoutPersistence : IPersistTimeouts + public class InMemoryTimeoutPersistence : IPersistTimeouts, IPersistTimeoutsV2 { readonly IList storage = new List(); readonly object lockObject = new object(); @@ -57,5 +57,19 @@ public void RemoveTimeoutBy(Guid sagaId) storage.Where(t => t.SagaId == sagaId).ToList().ForEach(item => storage.Remove(item)); } } + + public TimeoutData Peek(string timeoutId) + { + lock (lockObject) + { + return storage.SingleOrDefault(t => t.Id == timeoutId); + } + } + + public bool TryRemove(string timeoutId) + { + TimeoutData timeoutData; + return TryRemove(timeoutId, out timeoutData); + } } } diff --git a/src/NServiceBus.Core/Persistence/Raven/RavenUserInstaller.cs b/src/NServiceBus.Core/Persistence/Raven/RavenUserInstaller.cs index edf2ccfc5d..f068704c57 100644 --- a/src/NServiceBus.Core/Persistence/Raven/RavenUserInstaller.cs +++ b/src/NServiceBus.Core/Persistence/Raven/RavenUserInstaller.cs @@ -162,16 +162,22 @@ class WindowsAuthData { public string Name; // ReSharper disable once NotAccessedField.Local +#pragma warning disable 414 public bool Enabled; +#pragma warning restore 414 public List Databases = new List(); } class DatabaseAccess { // ReSharper disable once NotAccessedField.Local +#pragma warning disable 414 public bool Admin; +#pragma warning restore 414 // ReSharper disable once NotAccessedField.Local +#pragma warning disable 414 public bool ReadOnly; +#pragma warning restore 414 public string TenantId; } // ReSharper restore NotAccessedField.Local diff --git a/src/NServiceBus.Core/Persistence/Raven/TimeoutPersister/RavenTimeoutPersistence.cs b/src/NServiceBus.Core/Persistence/Raven/TimeoutPersister/RavenTimeoutPersistence.cs index 0dcce334e8..aa21221648 100644 --- a/src/NServiceBus.Core/Persistence/Raven/TimeoutPersister/RavenTimeoutPersistence.cs +++ b/src/NServiceBus.Core/Persistence/Raven/TimeoutPersister/RavenTimeoutPersistence.cs @@ -10,7 +10,7 @@ namespace NServiceBus.Persistence.Raven.TimeoutPersister using Logging; using Timeout.Core; - public class RavenTimeoutPersistence : IPersistTimeouts + public class RavenTimeoutPersistence : IPersistTimeouts, IPersistTimeoutsV2 { readonly IDocumentStore store; @@ -171,6 +171,20 @@ public void RemoveTimeoutBy(Guid sagaId) } } + public TimeoutData Peek(string timeoutId) + { + using (var session = OpenSession()) + { + return session.Load(timeoutId); + } + } + + public bool TryRemove(string timeoutId) + { + TimeoutData timeoutData; + return TryRemove(timeoutId, out timeoutData); + } + IDocumentSession OpenSession() { var session = store.OpenSession(); diff --git a/src/NServiceBus.Core/Schedule.cs b/src/NServiceBus.Core/Schedule.cs index 44e3fda052..694b64438b 100644 --- a/src/NServiceBus.Core/Schedule.cs +++ b/src/NServiceBus.Core/Schedule.cs @@ -1,6 +1,8 @@ namespace NServiceBus { using System; + using System.Linq; + using System.Runtime.CompilerServices; using Scheduling; public class Schedule @@ -20,8 +22,16 @@ public static Schedule Every(TimeSpan timeSpan) } public void Action(Action task) - { - Action(task.Method.DeclaringType.Name, task); + { + var declaringType = task.Method.DeclaringType; + + while (declaringType.DeclaringType != null && + declaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any()) + { + declaringType = declaringType.DeclaringType; + } + + Action(declaringType.Name, task); } public void Action(string name, Action task) diff --git a/src/NServiceBus.Core/Timeout/Core/IPersistTimeoutsV2.cs b/src/NServiceBus.Core/Timeout/Core/IPersistTimeoutsV2.cs new file mode 100644 index 0000000000..ec6c5a5e42 --- /dev/null +++ b/src/NServiceBus.Core/Timeout/Core/IPersistTimeoutsV2.cs @@ -0,0 +1,19 @@ +namespace NServiceBus.Timeout.Core +{ + public interface IPersistTimeoutsV2 + { + /// + /// Reads timeout data. + /// + /// The timeout id to read. + /// of the timeout if it was found. null otherwise. + TimeoutData Peek(string timeoutId); + + /// + /// Removes the timeout if it hasn't been previously removed. + /// + /// The timeout id to remove. + /// true if the timeout has been successfully removed or false if there was no timeout to remove. + bool TryRemove(string timeoutId); + } +} \ No newline at end of file diff --git a/src/NServiceBus.Core/Timeout/Core/TimeoutPersistenceVersionCheck.cs b/src/NServiceBus.Core/Timeout/Core/TimeoutPersistenceVersionCheck.cs new file mode 100644 index 0000000000..3f46caf822 --- /dev/null +++ b/src/NServiceBus.Core/Timeout/Core/TimeoutPersistenceVersionCheck.cs @@ -0,0 +1,131 @@ +namespace NServiceBus.Timeout.Core +{ + using System; + using System.Configuration; + using NServiceBus.Config; + using NServiceBus.ObjectBuilder; + using NServiceBus.Settings; + using NServiceBus.Transports; + + public static class TimeoutPersistenceVersionCheckExtension + { + public static Configure SuppressOutdatedTimeoutPersistenceWarning(this Configure configure) + { + SettingsHolder.Set(TimeoutPersistenceVersionCheck.SuppressOutdatedTimeoutPersistenceWarning, true); + return configure; + } + + public static Configure SuppressOutdatedTransportWarning(this Configure configure) + { + SettingsHolder.Set(TimeoutPersistenceVersionCheck.SuppressOutdatedTransportWarning, true); + return configure; + } + } + + internal class TimeoutPersistenceVersionCheck : IWantToRunWhenConfigurationIsComplete + { + internal const string SuppressOutdatedTimeoutPersistenceWarning = "NServiceBus/suppress-outdated-timeout-persistence-warning"; + internal const string SuppressOutdatedTransportWarning = "NServiceBus/suppress-outdated-persistence-warning"; + + readonly IBuilder builder; + + public TimeoutPersistenceVersionCheck(IBuilder builder) + { + this.builder = builder; + } + + public void Run() + { + var suppressDtc = SettingsHolder.Get("Transactions.SuppressDistributedTransactions"); + if (IsTransportSupportingDtc() && !suppressDtc) + { + // there is no issue with the timeout persistence when using dtc + return; + } + + var timeoutPersister = TryResolveTimeoutPersister(); + if (timeoutPersister == null) + { + // no timeouts used + return; + } + + if (!(timeoutPersister is IPersistTimeoutsV2) && !UserSuppressedTimeoutPersistenceWarning()) + { + throw new Exception("You are using an outdated timeout persistence which can lead to message loss! Please update the configured timeout persistence. You can suppress this warning by configuring your bus using 'config.SuppressOutdatedTimeoutPersistenceWarning()' or by adding 'NServiceBus/suppress-outdated-timeout-persistence-warning' with value 'true' to the appSettings section of your application configuration file."); + } + + if (TransactionalTransportMissesNativeTxSuppression() && !UserSuppressedTransportWarning()) + { + throw new Exception("You are using an outdated transport which can lead to message loss! Please update the configured transport. You can suppress this warning by configuring your bus using 'config.SuppressOutdatedTransportWarning()' or by adding 'NServiceBus/suppress-outdated-transport-warning' with value 'true' to the appSettings section of your application configuration file."); + } + } + + bool TransactionalTransportMissesNativeTxSuppression() + { + // transports allowing native cross-queue transactions (without dtc) need to support sending messages suppressing an active transaction + // this currently only affects SqlServer transport since only MSMQ and SqlServer transports support this scenario whereas MSMQ already supports the suppresion. + + var selectedTransport = SettingsHolder.GetOrDefault("NServiceBus.Transport.SelectedTransport"); + return selectedTransport.GetType().Name.Contains("SqlServer") && !SettingsHolder.GetOrDefault("NServiceBus.Transport.SupportsNativeTransactionSuppression"); + } + + IPersistTimeouts TryResolveTimeoutPersister() + { + IPersistTimeouts timeoutPersister = null; + try + { + timeoutPersister = builder.Build(); + } + catch (Exception) + { + // catch potential DI exception when interface not registered. + } + + return timeoutPersister; + } + + bool UserSuppressedTimeoutPersistenceWarning() + { + if (SettingsHolder.HasSetting(SuppressOutdatedTimeoutPersistenceWarning)) + { + return SettingsHolder.GetOrDefault(SuppressOutdatedTimeoutPersistenceWarning); + } + + var appSetting = ConfigurationManager.AppSettings[SuppressOutdatedTimeoutPersistenceWarning]; + if (appSetting != null) + { + return bool.Parse(appSetting); + } + + return false; + } + + bool UserSuppressedTransportWarning() + { + if (SettingsHolder.HasSetting(SuppressOutdatedTransportWarning)) + { + return SettingsHolder.GetOrDefault(SuppressOutdatedTransportWarning); + } + + var appSetting = ConfigurationManager.AppSettings[SuppressOutdatedTransportWarning]; + if (appSetting != null) + { + return bool.Parse(appSetting); + } + + return false; + } + + bool IsTransportSupportingDtc() + { + var selectedTransport = SettingsHolder.GetOrDefault("NServiceBus.Transport.SelectedTransport"); + if (selectedTransport.HasSupportForDistributedTransactions.HasValue) + { + return selectedTransport.HasSupportForDistributedTransactions.Value; + } + + return !selectedTransport.GetType().Name.Contains("RabbitMQ"); + } + } +} \ No newline at end of file diff --git a/src/NServiceBus.Core/Timeout/Hosting/Windows/TimeoutDispatcherProcessor.cs b/src/NServiceBus.Core/Timeout/Hosting/Windows/TimeoutDispatcherProcessor.cs index 7a453a453c..c65cdfdf03 100644 --- a/src/NServiceBus.Core/Timeout/Hosting/Windows/TimeoutDispatcherProcessor.cs +++ b/src/NServiceBus.Core/Timeout/Hosting/Windows/TimeoutDispatcherProcessor.cs @@ -3,6 +3,7 @@ namespace NServiceBus.Timeout.Hosting.Windows using System; using Core; using Features; + using NServiceBus.Pipeline; using Satellites; using Transports; using Unicast.Transport; @@ -14,6 +15,8 @@ public class TimeoutDispatcherProcessor : IAdvancedSatellite public IPersistTimeouts TimeoutsPersister { get; set; } public TimeoutPersisterReceiver TimeoutPersisterReceiver { get; set; } + + public PipelineExecutor PipelineExecutor { get; set; } public Address InputAddress { @@ -31,11 +34,36 @@ public bool Disabled public bool Handle(TransportMessage message) { var timeoutId = message.Headers["Timeout.Id"]; - TimeoutData timeoutData; + + + var persisterV2 = TimeoutsPersister as IPersistTimeoutsV2; + if (persisterV2 != null) + { + var timeoutData = persisterV2.Peek(timeoutId); + if (timeoutData == null) + { + return true; + } - if (TimeoutsPersister.TryRemove(timeoutId, out timeoutData)) + try + { + PipelineExecutor.CurrentContext.Set("do-not-enlist-in-native-transaction", true); + MessageSender.Send(timeoutData.ToTransportMessage(), timeoutData.Destination); + } + finally + { + PipelineExecutor.CurrentContext.Set("do-not-enlist-in-native-transaction", false); + } + + return persisterV2.TryRemove(timeoutId); + } + else { - MessageSender.Send(timeoutData.ToTransportMessage(), timeoutData.Destination); + TimeoutData timeoutData; + if (TimeoutsPersister.TryRemove(timeoutId, out timeoutData)) + { + MessageSender.Send(timeoutData.ToTransportMessage(), timeoutData.Destination); + } } return true; diff --git a/src/NServiceBus.Core/Timeout/Hosting/Windows/TimeoutMessageProcessor.cs b/src/NServiceBus.Core/Timeout/Hosting/Windows/TimeoutMessageProcessor.cs index ba0a92f9e6..cb756654f8 100644 --- a/src/NServiceBus.Core/Timeout/Hosting/Windows/TimeoutMessageProcessor.cs +++ b/src/NServiceBus.Core/Timeout/Hosting/Windows/TimeoutMessageProcessor.cs @@ -72,8 +72,8 @@ void HandleBackwardsCompatibility(TransportMessage message) destination = Address.Parse(routeExpiredTimeoutTo); } - TimeoutManager.RemoveTimeout(timeoutId); MessageSender.Send(message, destination); + TimeoutManager.RemoveTimeout(timeoutId); } void HandleInternal(TransportMessage message) diff --git a/src/NServiceBus.Core/Transports/Msmq/MsmqMessageSender.cs b/src/NServiceBus.Core/Transports/Msmq/MsmqMessageSender.cs index 3e78ae33cd..1e9cadc3d9 100644 --- a/src/NServiceBus.Core/Transports/Msmq/MsmqMessageSender.cs +++ b/src/NServiceBus.Core/Transports/Msmq/MsmqMessageSender.cs @@ -4,6 +4,7 @@ namespace NServiceBus.Transports.Msmq using System.Messaging; using System.Transactions; using Config; + using NServiceBus.Pipeline; using Settings; using Unicast.Queuing; @@ -22,7 +23,7 @@ public class MsmqMessageSender : ISendMessages /// public MsmqUnitOfWork UnitOfWork { get; set; } - + public PipelineExecutor PipelineExecutor { get; set; } /// /// Sends the given to the . @@ -50,7 +51,9 @@ public void Send(TransportMessage message, Address address) new MessageQueue(MsmqUtilities.GetReturnAddress(message.ReplyToAddress.ToString(), address.ToString())); - if (UnitOfWork.HasActiveTransaction()) + bool suppressNativeTransactions; + PipelineExecutor.CurrentContext.TryGet("do-not-enlist-in-native-transaction", out suppressNativeTransactions); + if (UnitOfWork.HasActiveTransaction() && !suppressNativeTransactions) { q.Send(toSend, UnitOfWork.Transaction); } diff --git a/src/NServiceBus.Core/packages.config b/src/NServiceBus.Core/packages.config index a083bf8e65..fb0e0dd131 100644 --- a/src/NServiceBus.Core/packages.config +++ b/src/NServiceBus.Core/packages.config @@ -2,7 +2,7 @@ - + diff --git a/src/NServiceBus.Hosting.Tests/NServiceBus.Hosting.Tests.csproj b/src/NServiceBus.Hosting.Tests/NServiceBus.Hosting.Tests.csproj index 21fabce49a..ccc6ad12e9 100644 --- a/src/NServiceBus.Hosting.Tests/NServiceBus.Hosting.Tests.csproj +++ b/src/NServiceBus.Hosting.Tests/NServiceBus.Hosting.Tests.csproj @@ -43,9 +43,6 @@ ..\packages\log4net.1.2.10\lib\2.0\log4net.dll - - ..\packages\Castle.Windsor\lib\net40\Castle.Windsor.dll - False ..\packages\NUnit.2.6.3\lib\nunit.framework.dll diff --git a/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.WindowsAnyCpu.csproj b/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.WindowsAnyCpu.csproj index 40f57d8497..9851249138 100644 --- a/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.WindowsAnyCpu.csproj +++ b/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.WindowsAnyCpu.csproj @@ -16,6 +16,7 @@ ..\ ..\ 2f55fe34 + 14d16af8 NServiceBus.Host @@ -158,13 +159,11 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - - + \ No newline at end of file diff --git a/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.WindowsX86.csproj b/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.WindowsX86.csproj index d55ce58c25..75db6ec436 100644 --- a/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.WindowsX86.csproj +++ b/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.WindowsX86.csproj @@ -161,14 +161,12 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + - - + \ No newline at end of file diff --git a/src/NServiceBus.Hosting.Windows/packages.config b/src/NServiceBus.Hosting.Windows/packages.config index 771a87f368..7468a5837d 100644 --- a/src/NServiceBus.Hosting.Windows/packages.config +++ b/src/NServiceBus.Hosting.Windows/packages.config @@ -1,7 +1,7 @@  - + diff --git a/src/NServiceBus.Testing/NServiceBus.Testing.csproj b/src/NServiceBus.Testing/NServiceBus.Testing.csproj index eee8e5f013..cb1aa0286c 100644 --- a/src/NServiceBus.Testing/NServiceBus.Testing.csproj +++ b/src/NServiceBus.Testing/NServiceBus.Testing.csproj @@ -16,6 +16,7 @@ ..\ ..\ cb9f37af + 2332e084 true @@ -101,13 +102,11 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - - + \ No newline at end of file diff --git a/src/NServiceBus.Testing/packages.config b/src/NServiceBus.Testing/packages.config index fad11d3eda..5954135c4a 100644 --- a/src/NServiceBus.Testing/packages.config +++ b/src/NServiceBus.Testing/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/NServiceBus.sln.DotSettings b/src/NServiceBus.sln.DotSettings index 45b119f897..a48b73923b 100644 --- a/src/NServiceBus.sln.DotSettings +++ b/src/NServiceBus.sln.DotSettings @@ -1,6 +1,6 @@  - + CSharp50 True True True @@ -12,11 +12,27 @@ DO_NOT_SHOW DO_NOT_SHOW DO_NOT_SHOW + WARNING ERROR ERROR - WARNING + ERROR ERROR + ERROR + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + ERROR ERROR + ERROR + ERROR + ERROR + ERROR + ERROR + ERROR + ERROR + ERROR + ERROR + ERROR ERROR ERROR ERROR @@ -24,13 +40,15 @@ ERROR ERROR ERROR + ERROR ERROR DO_NOT_SHOW DO_NOT_SHOW + ERROR DO_NOT_SHOW DO_NOT_SHOW ERROR - WARNING + ERROR ERROR ERROR ERROR @@ -44,8 +62,10 @@ ERROR ERROR ERROR - SUGGESTION - DO_NOT_SHOW + ERROR + ERROR + SUGGESTION + SUGGESTION ERROR ERROR ERROR @@ -61,6 +81,7 @@ ERROR ERROR ERROR + ERROR ERROR ERROR WARNING @@ -84,27 +105,34 @@ DoHide DoHide DoHide - DoHide DoHide + ERROR ERROR ERROR ERROR + ERROR + ERROR + ERROR ERROR ERROR ERROR ERROR + ERROR ERROR ERROR DO_NOT_SHOW SUGGESTION + WARNING + WARNING ERROR - ERROR + HINT ERROR ERROR ERROR <?xml version="1.0" encoding="utf-16"?><Profile name="Format My Code Using &quot;Particular&quot; conventions"><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_TO_IMPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_IMPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_IMPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSReformatCode>True</CSReformatCode><CSReorderTypeMembers>True</CSReorderTypeMembers><JsInsertSemicolon>True</JsInsertSemicolon><JsReformatCode>True</JsReformatCode><CssReformatCode>True</CssReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><HtmlReformatCode>True</HtmlReformatCode><CSShortenReferences>True</CSShortenReferences><CSharpFormatDocComments>True</CSharpFormatDocComments><CssAlphabetizeProperties>True</CssAlphabetizeProperties></Profile> Default: Reformat Code Format My Code Using "Particular" conventions + False False ALWAYS_ADD ALWAYS_ADD @@ -120,6 +148,142 @@ CHOP_ALWAYS True True + <?xml version="1.0" encoding="utf-16"?> +<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> + <TypePattern DisplayName="COM interfaces or structs"> + <TypePattern.Match> + <Or> + <And> + <Kind Is="Interface" /> + <Or> + <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /> + <HasAttribute Name="System.Runtime.InteropServices.ComImport" /> + </Or> + </And> + <Kind Is="Struct" /> + </Or> + </TypePattern.Match> + </TypePattern> + <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"> + <TypePattern.Match> + <And> + <Kind Is="Class" /> + <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.TestCaseFixtureAttribute" Inherited="True" /> + </And> + </TypePattern.Match> + <Entry DisplayName="Setup/Teardown Methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <Or> + <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" /> + </Or> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="All other members" /> + <Entry Priority="100" DisplayName="Test Methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <HasAttribute Name="NUnit.Framework.TestAttribute" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> + <TypePattern DisplayName="Default Pattern"> + <Entry Priority="100" DisplayName="Public Delegates"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Kind Is="Delegate" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + <Entry Priority="100" DisplayName="Public Enums"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Kind Is="Enum" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Static Fields and Constants"> + <Entry.Match> + <Or> + <Kind Is="Constant" /> + <And> + <Kind Is="Field" /> + <Static /> + </And> + </Or> + </Entry.Match> + <Entry.SortBy> + <Kind Order="Constant Field" /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Constructors"> + <Entry.Match> + <Kind Is="Constructor" /> + </Entry.Match> + <Entry.SortBy> + <Static /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Properties, Indexers"> + <Entry.Match> + <Or> + <Kind Is="Property" /> + <Kind Is="Indexer" /> + </Or> + </Entry.Match> + </Entry> + <Entry Priority="100" DisplayName="Interface Implementations"> + <Entry.Match> + <And> + <Kind Is="Member" /> + <ImplementsInterface /> + </And> + </Entry.Match> + <Entry.SortBy> + <ImplementsInterface Immediate="True" /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="All other members" /> + <Entry DisplayName="Fields"> + <Entry.Match> + <And> + <Kind Is="Field" /> + <Not> + <Static /> + </Not> + </And> + </Entry.Match> + <Entry.SortBy> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Nested Types"> + <Entry.Match> + <Kind Is="Type" /> + </Entry.Match> + </Entry> + </TypePattern> +</Patterns> <?xml version="1.0" encoding="utf-8" ?> <!-- @@ -360,6 +524,8 @@ II.2.12 <HandlesEvent /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> @@ -367,6 +533,27 @@ II.2.12 <HandlesEvent /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> $object$_On$event$ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> @@ -384,6 +571,13 @@ II.2.12 <HandlesEvent /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True + True + True True True diff --git a/src/NServiceBus/NServiceBus.csproj b/src/NServiceBus/NServiceBus.csproj index cd31f4cf5c..11011c99f8 100644 --- a/src/NServiceBus/NServiceBus.csproj +++ b/src/NServiceBus/NServiceBus.csproj @@ -17,6 +17,7 @@ ..\ ..\ b2ae70fd + 0eac3bab true @@ -137,13 +138,11 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - - + \ No newline at end of file diff --git a/src/NServiceBus/packages.config b/src/NServiceBus/packages.config index fad11d3eda..5954135c4a 100644 --- a/src/NServiceBus/packages.config +++ b/src/NServiceBus/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/ObjectBuilder.Autofac/ObjectBuilder.Autofac.csproj b/src/ObjectBuilder.Autofac/ObjectBuilder.Autofac.csproj index f2c632aafd..b04009fb3e 100644 --- a/src/ObjectBuilder.Autofac/ObjectBuilder.Autofac.csproj +++ b/src/ObjectBuilder.Autofac/ObjectBuilder.Autofac.csproj @@ -18,6 +18,7 @@ ..\ ..\ 55a9567c + 9cb64551 true @@ -107,13 +108,11 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - - + \ No newline at end of file diff --git a/src/ObjectBuilder.Autofac/packages.config b/src/ObjectBuilder.Autofac/packages.config index 0e9c195e68..22af92e8e1 100644 --- a/src/ObjectBuilder.Autofac/packages.config +++ b/src/ObjectBuilder.Autofac/packages.config @@ -1,7 +1,7 @@  - + diff --git a/src/ObjectBuilder.CastleWindsor/ObjectBuilder.CastleWindsor.csproj b/src/ObjectBuilder.CastleWindsor/ObjectBuilder.CastleWindsor.csproj index f7af488b08..f3b35a17d1 100644 --- a/src/ObjectBuilder.CastleWindsor/ObjectBuilder.CastleWindsor.csproj +++ b/src/ObjectBuilder.CastleWindsor/ObjectBuilder.CastleWindsor.csproj @@ -17,6 +17,7 @@ ..\ ..\ 4e7c66b1 + 62aa5c45 true @@ -97,13 +98,11 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - - + \ No newline at end of file diff --git a/src/ObjectBuilder.CastleWindsor/packages.config b/src/ObjectBuilder.CastleWindsor/packages.config index f51ccf8fa2..8858a96615 100644 --- a/src/ObjectBuilder.CastleWindsor/packages.config +++ b/src/ObjectBuilder.CastleWindsor/packages.config @@ -2,7 +2,7 @@ - + diff --git a/src/ObjectBuilder.Ninject/ObjectBuilder.Ninject.csproj b/src/ObjectBuilder.Ninject/ObjectBuilder.Ninject.csproj index c3e50802f8..ef4a48b10b 100644 --- a/src/ObjectBuilder.Ninject/ObjectBuilder.Ninject.csproj +++ b/src/ObjectBuilder.Ninject/ObjectBuilder.Ninject.csproj @@ -16,6 +16,7 @@ ..\NServiceBus.snk ..\ 62d9979a + 6f9bb583 true @@ -101,13 +102,11 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - - + \ No newline at end of file diff --git a/src/ObjectBuilder.Ninject/packages.config b/src/ObjectBuilder.Ninject/packages.config index 9151aa5be2..a332a69117 100644 --- a/src/ObjectBuilder.Ninject/packages.config +++ b/src/ObjectBuilder.Ninject/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/ObjectBuilder.Spring/ObjectBuilder.Spring.csproj b/src/ObjectBuilder.Spring/ObjectBuilder.Spring.csproj index cd30c2f53e..a8017fc5c9 100644 --- a/src/ObjectBuilder.Spring/ObjectBuilder.Spring.csproj +++ b/src/ObjectBuilder.Spring/ObjectBuilder.Spring.csproj @@ -17,6 +17,7 @@ ..\ ..\ 62fc911e + da3d40cd true @@ -95,13 +96,11 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - - + \ No newline at end of file diff --git a/src/ObjectBuilder.Spring/packages.config b/src/ObjectBuilder.Spring/packages.config index d2862deeb8..4582ed7eac 100644 --- a/src/ObjectBuilder.Spring/packages.config +++ b/src/ObjectBuilder.Spring/packages.config @@ -1,7 +1,7 @@  - + diff --git a/src/ObjectBuilder.StructureMap/ObjectBuilder.StructureMap.csproj b/src/ObjectBuilder.StructureMap/ObjectBuilder.StructureMap.csproj index 288202dff0..88bc10590c 100644 --- a/src/ObjectBuilder.StructureMap/ObjectBuilder.StructureMap.csproj +++ b/src/ObjectBuilder.StructureMap/ObjectBuilder.StructureMap.csproj @@ -17,6 +17,7 @@ ..\ ..\ 6128deff + 34b3b613 true @@ -92,13 +93,11 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - - + \ No newline at end of file diff --git a/src/ObjectBuilder.StructureMap/packages.config b/src/ObjectBuilder.StructureMap/packages.config index 97ccf0b216..46c295d665 100644 --- a/src/ObjectBuilder.StructureMap/packages.config +++ b/src/ObjectBuilder.StructureMap/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/ObjectBuilder.Unity/ObjectBuilder.Unity.csproj b/src/ObjectBuilder.Unity/ObjectBuilder.Unity.csproj index b4e15ea3db..0bd66d8427 100644 --- a/src/ObjectBuilder.Unity/ObjectBuilder.Unity.csproj +++ b/src/ObjectBuilder.Unity/ObjectBuilder.Unity.csproj @@ -17,6 +17,7 @@ ..\ ..\ 84ff0e72 + fa41c347 true @@ -110,13 +111,11 @@ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - - + \ No newline at end of file diff --git a/src/ObjectBuilder.Unity/packages.config b/src/ObjectBuilder.Unity/packages.config index 2db477b01b..4385a121a4 100644 --- a/src/ObjectBuilder.Unity/packages.config +++ b/src/ObjectBuilder.Unity/packages.config @@ -1,7 +1,7 @@  - +