diff --git a/buildsupport/GitVersion/Build/GitVersionTask.targets b/buildsupport/GitVersion/Build/GitVersionTask.targets
deleted file mode 100644
index 10f64ecfc54..00000000000
--- a/buildsupport/GitVersion/Build/GitVersionTask.targets
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
- $(MSBuildProjectDirectory)..\
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/buildsupport/GitVersion/GitVersion.exe b/buildsupport/GitVersion/GitVersion.exe
deleted file mode 100644
index 7992cd07195..00000000000
Binary files a/buildsupport/GitVersion/GitVersion.exe and /dev/null differ
diff --git a/buildsupport/GitVersion/GitVersionTask.dll b/buildsupport/GitVersion/GitVersionTask.dll
deleted file mode 100644
index e93ec11d46b..00000000000
Binary files a/buildsupport/GitVersion/GitVersionTask.dll and /dev/null differ
diff --git a/buildsupport/GitVersionTask/Build/GitVersionTask.targets b/buildsupport/GitVersionTask/Build/GitVersionTask.targets
new file mode 100644
index 00000000000..2b3fcc62b28
--- /dev/null
+++ b/buildsupport/GitVersionTask/Build/GitVersionTask.targets
@@ -0,0 +1,51 @@
+
+
+
+ $(MSBuildProjectDirectory)..\
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/buildsupport/GitVersionTask/GitVersionCore.dll b/buildsupport/GitVersionTask/GitVersionCore.dll
new file mode 100644
index 00000000000..a4342bd7da0
Binary files /dev/null and b/buildsupport/GitVersionTask/GitVersionCore.dll differ
diff --git a/buildsupport/GitVersionTask/GitVersionTask.dll b/buildsupport/GitVersionTask/GitVersionTask.dll
new file mode 100644
index 00000000000..079924a095c
Binary files /dev/null and b/buildsupport/GitVersionTask/GitVersionTask.dll differ
diff --git a/buildsupport/GitVersionTask/LibGit2Sharp.dll b/buildsupport/GitVersionTask/LibGit2Sharp.dll
new file mode 100644
index 00000000000..e45661bd83e
Binary files /dev/null and b/buildsupport/GitVersionTask/LibGit2Sharp.dll differ
diff --git a/buildsupport/GitVersionTask/NativeBinaries/amd64/git2-06d772d.dll b/buildsupport/GitVersionTask/NativeBinaries/amd64/git2-06d772d.dll
new file mode 100644
index 00000000000..639b55ef416
Binary files /dev/null and b/buildsupport/GitVersionTask/NativeBinaries/amd64/git2-06d772d.dll differ
diff --git a/buildsupport/GitVersionTask/NativeBinaries/x86/git2-06d772d.dll b/buildsupport/GitVersionTask/NativeBinaries/x86/git2-06d772d.dll
new file mode 100644
index 00000000000..1ceb3b2ec36
Binary files /dev/null and b/buildsupport/GitVersionTask/NativeBinaries/x86/git2-06d772d.dll differ
diff --git a/buildsupport/MSBuild.Community.Tasks.dll b/buildsupport/MSBuild.Community.Tasks.dll
deleted file mode 100644
index 6d43c0e5bcd..00000000000
Binary files a/buildsupport/MSBuild.Community.Tasks.dll and /dev/null differ
diff --git a/buildsupport/PepitaPackage.dll b/buildsupport/PepitaPackage.dll
deleted file mode 100644
index d1509d1b2bd..00000000000
Binary files a/buildsupport/PepitaPackage.dll and /dev/null differ
diff --git a/buildsupport/RippleRestoreTask.dll b/buildsupport/RippleRestoreTask.dll
index e443473c54c..e84e8b68bf4 100644
Binary files a/buildsupport/RippleRestoreTask.dll and b/buildsupport/RippleRestoreTask.dll differ
diff --git a/buildsupport/ripple.exe b/buildsupport/ripple.exe
index f2b3de26832..5ed129f4cc6 100644
Binary files a/buildsupport/ripple.exe and b/buildsupport/ripple.exe differ
diff --git a/buildsupport/run-git.cmd b/buildsupport/run-git.cmd
deleted file mode 100644
index f09175c0a4c..00000000000
--- a/buildsupport/run-git.cmd
+++ /dev/null
@@ -1 +0,0 @@
-git %*
\ No newline at end of file
diff --git a/src/NServiceBus.AcceptanceTesting/NServiceBus.AcceptanceTesting.csproj b/src/NServiceBus.AcceptanceTesting/NServiceBus.AcceptanceTesting.csproj
index 02ff39e4bdb..fbb64d918dd 100644
--- a/src/NServiceBus.AcceptanceTesting/NServiceBus.AcceptanceTesting.csproj
+++ b/src/NServiceBus.AcceptanceTesting/NServiceBus.AcceptanceTesting.csproj
@@ -78,5 +78,5 @@
-
+
\ No newline at end of file
diff --git a/src/NServiceBus.Core.Tests/NServiceBus.Core.Tests.csproj b/src/NServiceBus.Core.Tests/NServiceBus.Core.Tests.csproj
index 05054ae12cd..7df5588e40b 100644
--- a/src/NServiceBus.Core.Tests/NServiceBus.Core.Tests.csproj
+++ b/src/NServiceBus.Core.Tests/NServiceBus.Core.Tests.csproj
@@ -238,6 +238,7 @@
+
diff --git a/src/NServiceBus.Core.Tests/Timeout/RavenTimeoutPersisterTests.cs b/src/NServiceBus.Core.Tests/Timeout/RavenTimeoutPersisterTests.cs
new file mode 100644
index 00000000000..d92d5238706
--- /dev/null
+++ b/src/NServiceBus.Core.Tests/Timeout/RavenTimeoutPersisterTests.cs
@@ -0,0 +1,260 @@
+namespace NServiceBus.Core.Tests.Timeout
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading;
+ using NServiceBus.Persistence.Raven;
+ using NServiceBus.Persistence.Raven.TimeoutPersister;
+ using NServiceBus.Timeout.Core;
+ using NUnit.Framework;
+ using Raven.Client;
+ using Raven.Client.Document;
+
+ [TestFixture]
+ public class RavenTimeoutPersisterTests
+ {
+ [TestCase, Repeat(200)]
+ public void Should_not_skip_timeouts()
+ {
+ var db = Guid.NewGuid().ToString();
+ documentStore = new DocumentStore
+ {
+ Url = "http://localhost:8080",
+ DefaultDatabase = db,
+ }.Initialize();
+ persister = new RavenTimeoutPersistence(new StoreAccessor(documentStore))
+ {
+ TriggerCleanupEvery = TimeSpan.FromHours(1), // Make sure cleanup doesn't run automatically
+ };
+
+ var startSlice = DateTime.UtcNow.AddYears(-10);
+ // avoid cleanup from running during the test by making it register as being run
+ Assert.AreEqual(0, persister.GetCleanupChunk(startSlice).Count());
+
+ var expected = new List>();
+ var lastExpectedTimeout = DateTime.UtcNow;
+ var finishedAdding = false;
+
+ new Thread(() =>
+ {
+ var sagaId = Guid.NewGuid();
+ for (var i = 0; i < 10000; i++)
+ {
+ var td = new TimeoutData
+ {
+ SagaId = sagaId,
+ Destination = new Address("queue", "machine"),
+ Time = DateTime.UtcNow.AddSeconds(RandomProvider.GetThreadRandom().Next(5, 20)),
+ OwningTimeoutManager = string.Empty,
+ };
+ persister.Add(td);
+ expected.Add(new Tuple(td.Id, td.Time));
+ lastExpectedTimeout = (td.Time > lastExpectedTimeout) ? td.Time : lastExpectedTimeout;
+ }
+ finishedAdding = true;
+ Console.WriteLine("*** Finished adding ***");
+ }).Start();
+
+ // Mimic the behavior of the TimeoutPersister coordinator
+ var found = 0;
+ TimeoutData tempTd;
+ while (!finishedAdding || startSlice < lastExpectedTimeout)
+ {
+ DateTime nextRetrieval;
+ var timeoutDatas = persister.GetNextChunk(startSlice, out nextRetrieval);
+ foreach (var timeoutData in timeoutDatas)
+ {
+ if (startSlice < timeoutData.Item2)
+ {
+ startSlice = timeoutData.Item2;
+ }
+
+ Assert.IsTrue(persister.TryRemove(timeoutData.Item1, out tempTd));
+ found++;
+ }
+ }
+
+ WaitForIndexing(documentStore);
+
+ // If the persister reports stale results have been seen at one point during its normal operation,
+ // we need to perform manual cleaup.
+ while (true)
+ {
+ var chunkToCleanup = persister.GetCleanupChunk(DateTime.UtcNow.AddDays(1)).ToArray();
+ Console.WriteLine("Cleanup: got a chunk of size " + chunkToCleanup.Length);
+ if (chunkToCleanup.Length == 0) break;
+
+ found += chunkToCleanup.Length;
+ foreach (var tuple in chunkToCleanup)
+ {
+ Assert.IsTrue(persister.TryRemove(tuple.Item1, out tempTd));
+ }
+
+ WaitForIndexing(documentStore);
+ }
+
+ using (var session = documentStore.OpenSession())
+ {
+ var results = session.Query().ToList();
+ Assert.AreEqual(0, results.Count);
+ }
+
+ Assert.AreEqual(expected.Count, found);
+ }
+
+ [TestCase, Repeat(200)]
+ public void Should_not_skip_timeouts_also_with_multiple_clients_adding_timeouts()
+ {
+ var db = Guid.NewGuid().ToString();
+ documentStore = new DocumentStore
+ {
+ Url = "http://localhost:8080",
+ DefaultDatabase = db,
+ }.Initialize();
+ persister = new RavenTimeoutPersistence(new StoreAccessor(documentStore))
+ {
+ TriggerCleanupEvery = TimeSpan.FromDays(1), // Make sure cleanup doesn't run automatically
+ };
+
+ var startSlice = DateTime.UtcNow.AddYears(-10);
+ // avoid cleanup from running during the test by making it register as being run
+ Assert.AreEqual(0, persister.GetCleanupChunk(startSlice).Count());
+
+ const int insertsPerThread = 10000;
+ var expected1 = new List>();
+ var expected2 = new List>();
+ var lastExpectedTimeout = DateTime.UtcNow;
+ var finishedAdding1 = false;
+ var finishedAdding2 = false;
+
+ new Thread(() =>
+ {
+ var sagaId = Guid.NewGuid();
+ for (var i = 0; i < insertsPerThread; i++)
+ {
+ var td = new TimeoutData
+ {
+ SagaId = sagaId,
+ Destination = new Address("queue", "machine"),
+ Time = DateTime.UtcNow.AddSeconds(RandomProvider.GetThreadRandom().Next(1, 20)),
+ OwningTimeoutManager = string.Empty,
+ };
+ persister.Add(td);
+ expected1.Add(new Tuple(td.Id, td.Time));
+ lastExpectedTimeout = (td.Time > lastExpectedTimeout) ? td.Time : lastExpectedTimeout;
+ }
+ finishedAdding1 = true;
+ Console.WriteLine("*** Finished adding ***");
+ }).Start();
+
+ new Thread(() =>
+ {
+ using (var store = new DocumentStore
+ {
+ Url = "http://localhost:8080",
+ DefaultDatabase = db,
+ }.Initialize())
+ {
+ var persister2 = new RavenTimeoutPersistence(new StoreAccessor(store));
+
+ var sagaId = Guid.NewGuid();
+ for (var i = 0; i < insertsPerThread; i++)
+ {
+ var td = new TimeoutData
+ {
+ SagaId = sagaId,
+ Destination = new Address("queue", "machine"),
+ Time = DateTime.UtcNow.AddSeconds(RandomProvider.GetThreadRandom().Next(1, 20)),
+ OwningTimeoutManager = string.Empty,
+ };
+ persister2.Add(td);
+ expected2.Add(new Tuple(td.Id, td.Time));
+ lastExpectedTimeout = (td.Time > lastExpectedTimeout) ? td.Time : lastExpectedTimeout;
+ }
+ }
+ finishedAdding2 = true;
+ Console.WriteLine("*** Finished adding via a second client connection ***");
+ }).Start();
+
+ // Mimic the behavior of the TimeoutPersister coordinator
+ var found = 0;
+ TimeoutData tempTd;
+ while (!finishedAdding1 || !finishedAdding2 || startSlice < lastExpectedTimeout)
+ {
+ DateTime nextRetrieval;
+ var timeoutDatas = persister.GetNextChunk(startSlice, out nextRetrieval);
+ foreach (var timeoutData in timeoutDatas)
+ {
+ if (startSlice < timeoutData.Item2)
+ {
+ startSlice = timeoutData.Item2;
+ }
+
+ Assert.IsTrue(persister.TryRemove(timeoutData.Item1, out tempTd)); // Raven returns duplicates, so we can't assert on this here
+ found++;
+ }
+ }
+
+ WaitForIndexing(documentStore);
+
+ // If the persister reports stale results have been seen at one point during its normal operation,
+ // we need to perform manual cleaup.
+ while (true)
+ {
+ var chunkToCleanup = persister.GetCleanupChunk(DateTime.UtcNow.AddDays(1)).ToArray();
+ Console.WriteLine("Cleanup: got a chunk of size " + chunkToCleanup.Length);
+ if (chunkToCleanup.Length == 0) break;
+
+ found += chunkToCleanup.Length;
+ foreach (var tuple in chunkToCleanup)
+ {
+ Assert.IsTrue(persister.TryRemove(tuple.Item1, out tempTd));
+ }
+
+ WaitForIndexing(documentStore);
+ }
+
+ using (var session = documentStore.OpenSession())
+ {
+ var results = session.Query().ToList();
+ Assert.AreEqual(0, results.Count);
+ }
+
+ Assert.AreEqual(expected1.Count + expected2.Count, found);
+ }
+
+ IDocumentStore documentStore;
+ RavenTimeoutPersistence persister;
+
+ [TearDown]
+ public void TearDown()
+ {
+ if (documentStore != null)
+ documentStore.Dispose();
+ }
+
+ static void WaitForIndexing(IDocumentStore store, string db = null, TimeSpan? timeout = null)
+ {
+ var databaseCommands = store.DatabaseCommands;
+ if (db != null)
+ databaseCommands = databaseCommands.ForDatabase(db);
+ var spinUntil = SpinWait.SpinUntil(() => databaseCommands.GetStatistics().StaleIndexes.Length == 0, timeout ?? TimeSpan.FromSeconds(20));
+ Assert.True(spinUntil);
+ }
+
+ static class RandomProvider
+ {
+ private static int seed = Environment.TickCount;
+
+ private static ThreadLocal randomWrapper = new ThreadLocal(() =>
+ new Random(Interlocked.Increment(ref seed))
+ );
+
+ public static Random GetThreadRandom()
+ {
+ return randomWrapper.Value;
+ }
+ }
+ }
+}
diff --git a/src/NServiceBus.Core.Tests/Timeout/When_pooling_timeouts.cs b/src/NServiceBus.Core.Tests/Timeout/When_pooling_timeouts.cs
index 3cdb3b47cc2..5375c456b9d 100644
--- a/src/NServiceBus.Core.Tests/Timeout/When_pooling_timeouts.cs
+++ b/src/NServiceBus.Core.Tests/Timeout/When_pooling_timeouts.cs
@@ -16,7 +16,6 @@ namespace NServiceBus.Core.Tests.Timeout
using Raven.Client.Embedded;
[TestFixture]
- [Explicit]
public class When_pooling_timeouts_with_raven : When_pooling_timeouts
{
private IDocumentStore store;
@@ -37,10 +36,21 @@ public void Cleanup()
{
store.Dispose();
}
+
+ [Test]
+ public void Should_retrieve_all_timeout_messages_that_expired_even_if_it_needs_to_page()
+ {
+ expected = 1024 + 5;
+
+ Enumerable.Range(1, expected).ToList().ForEach(i => persister.Add(CreateData(DateTime.UtcNow.AddSeconds(-5))));
+
+ StartAndStopReceiver(5);
+
+ WaitForMessagesThenAssert(5);
+ }
}
[TestFixture]
- [Explicit]
public class When_pooling_timeouts_with_inMemory : When_pooling_timeouts
{
protected override IPersistTimeouts CreateTimeoutPersister()
@@ -54,7 +64,7 @@ public abstract class When_pooling_timeouts
private IManageTimeouts manager;
private FakeMessageSender messageSender;
readonly Random rand = new Random();
- private int expected;
+ protected int expected;
protected IPersistTimeouts persister;
protected TimeoutPersisterReceiver receiver;
@@ -187,14 +197,14 @@ private void Push(int total, DateTime time)
Enumerable.Range(1, total).ToList().ForEach(i => manager.PushTimeout(CreateData(time)));
}
- private void StartAndStopReceiver(int secondsToWaitBeforeCallingStop = 1)
+ protected void StartAndStopReceiver(int secondsToWaitBeforeCallingStop = 1)
{
receiver.Start();
Thread.Sleep(TimeSpan.FromSeconds(secondsToWaitBeforeCallingStop));
receiver.Stop();
}
- private static TimeoutData CreateData(DateTime time)
+ protected static TimeoutData CreateData(DateTime time)
{
return new TimeoutData
{
@@ -204,7 +214,7 @@ private static TimeoutData CreateData(DateTime time)
};
}
- private void WaitForMessagesThenAssert(int maxSecondsToWait)
+ protected void WaitForMessagesThenAssert(int maxSecondsToWait)
{
var maxTime = DateTime.Now.AddSeconds(maxSecondsToWait);
@@ -216,4 +226,4 @@ private void WaitForMessagesThenAssert(int maxSecondsToWait)
Assert.AreEqual(expected, messageSender.MessagesSent);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/NServiceBus.Core/NServiceBus.Core.csproj b/src/NServiceBus.Core/NServiceBus.Core.csproj
index 9e764921cef..7d6aa072510 100644
--- a/src/NServiceBus.Core/NServiceBus.Core.csproj
+++ b/src/NServiceBus.Core/NServiceBus.Core.csproj
@@ -619,5 +619,5 @@
-
+
\ No newline at end of file
diff --git a/src/NServiceBus.Core/Persistence/Raven/TimeoutPersister/RavenTimeoutPersistence.cs b/src/NServiceBus.Core/Persistence/Raven/TimeoutPersister/RavenTimeoutPersistence.cs
index 87afe2a787e..a4a59fa43ea 100644
--- a/src/NServiceBus.Core/Persistence/Raven/TimeoutPersister/RavenTimeoutPersistence.cs
+++ b/src/NServiceBus.Core/Persistence/Raven/TimeoutPersister/RavenTimeoutPersistence.cs
@@ -14,9 +14,47 @@ public class RavenTimeoutPersistence : IPersistTimeouts
{
readonly IDocumentStore store;
- public RavenTimeoutPersistence(StoreAccessor storeAccessor)
+ public TimeSpan CleanupGapFromTimeslice { get; set; }
+ public TimeSpan TriggerCleanupEvery { get; set; }
+ DateTime lastCleanupTime = DateTime.MinValue;
+
+ public RavenTimeoutPersistence(StoreAccessor storeAccessor)
{
store = storeAccessor.Store;
+ TriggerCleanupEvery = TimeSpan.FromMinutes(2);
+ CleanupGapFromTimeslice = TimeSpan.FromMinutes(1);
+ }
+
+ private static IRavenQueryable GetChunkQuery(IDocumentSession session)
+ {
+ session.Advanced.AllowNonAuthoritativeInformation = true;
+ return session.Query()
+ .OrderBy(t => t.Time)
+ .Where(
+ t =>
+ t.OwningTimeoutManager == String.Empty ||
+ t.OwningTimeoutManager == Configure.EndpointName);
+ }
+
+ public IEnumerable> GetCleanupChunk(DateTime startSlice)
+ {
+ using (var session = OpenSession())
+ {
+ var chunk = GetChunkQuery(session)
+ .Where(t => t.Time <= startSlice.Subtract(CleanupGapFromTimeslice))
+ .Select(t => new
+ {
+ t.Id,
+ t.Time
+ })
+ .Take(1024)
+ .ToList()
+ .Select(arg => new Tuple(arg.Id, arg.Time));
+
+ lastCleanupTime = DateTime.UtcNow;
+
+ return chunk;
+ }
}
public List> GetNextChunk(DateTime startSlice, out DateTime nextTimeToRunQuery)
@@ -24,28 +62,31 @@ public List> GetNextChunk(DateTime startSlice, out DateT
try
{
var now = DateTime.UtcNow;
- var skip = 0;
var results = new List>();
+
+ // Allow for occasionally cleaning up old timeouts for edge cases where timeouts have been
+ // added after startSlice have been set to a later timout and we might have missed them
+ // because of stale indexes.
+ if (lastCleanupTime.Add(TriggerCleanupEvery) > now || lastCleanupTime == DateTime.MinValue)
+ {
+ results.AddRange(GetCleanupChunk(startSlice));
+ }
+
+ var skip = 0;
var numberOfRequestsExecutedSoFar = 0;
RavenQueryStatistics stats;
-
do
{
using (var session = OpenSession())
{
session.Advanced.AllowNonAuthoritativeInformation = true;
- var query = session.Query()
+ var query = GetChunkQuery(session)
.Where(
t =>
- t.OwningTimeoutManager == String.Empty ||
- t.OwningTimeoutManager == Configure.EndpointName)
- .Where(
- t =>
- t.Time > startSlice &&
+ t.Time > startSlice &&
t.Time <= now)
- .OrderBy(t => t.Time)
- .Select(t => new {t.Id, t.Time})
+ .Select(t => new { t.Id, t.Time })
.Statistics(out stats);
do
{
@@ -61,33 +102,29 @@ public List> GetNextChunk(DateTime startSlice, out DateT
}
} while (skip < stats.TotalResults);
- using (var session = OpenSession())
+ // Set next execution to be now if we received stale results.
+ // Delay the next execution a bit if we results weren't stale and we got the full chunk.
+ if (stats.IsStale)
{
- session.Advanced.AllowNonAuthoritativeInformation = true;
-
- //Retrieve next time we need to run query
- var startOfNextChunk =
- session.Query()
- .Where(
- t =>
- t.OwningTimeoutManager == String.Empty ||
- t.OwningTimeoutManager == Configure.EndpointName)
- .Where(t => t.Time > now)
- .OrderBy(t => t.Time)
- .Select(t => new {t.Id, t.Time})
- .FirstOrDefault();
-
- if (startOfNextChunk != null)
- {
- nextTimeToRunQuery = startOfNextChunk.Time;
- }
- else
+ nextTimeToRunQuery = now;
+ }
+ else
+ {
+ using (var session = OpenSession())
{
- nextTimeToRunQuery = DateTime.UtcNow.AddMinutes(10);
+ var beginningOfNextChunk = GetChunkQuery(session)
+ .Where(t => t.Time > now)
+ .Take(1)
+ .Select(t => t.Time)
+ .FirstOrDefault();
+
+ nextTimeToRunQuery = (beginningOfNextChunk == default(DateTime))
+ ? DateTime.UtcNow.AddMinutes(10)
+ : beginningOfNextChunk.ToUniversalTime();
}
-
- return results;
}
+
+ return results;
}
catch (WebException ex)
{
@@ -114,9 +151,6 @@ public bool TryRemove(string timeoutId, out TimeoutData timeoutData)
if (timeoutData == null)
return false;
- timeoutData.Time = DateTime.UtcNow.AddYears(-1);
- session.SaveChanges();
-
session.Delete(timeoutData);
session.SaveChanges();
diff --git a/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.Windows.csproj b/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.Windows.csproj
index 734e5dc8623..c8738068928 100644
--- a/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.Windows.csproj
+++ b/src/NServiceBus.Hosting.Windows/NServiceBus.Hosting.Windows.csproj
@@ -178,5 +178,5 @@
Projects="$(ProjectPath)"
Properties="SolutionDir=$(SolutionDir);Configuration=$(ConfigurationName);Platform=x86"/>
-
+
\ No newline at end of file
diff --git a/src/NServiceBus.NHibernate/NServiceBus.NHibernate.csproj b/src/NServiceBus.NHibernate/NServiceBus.NHibernate.csproj
index f796ed2689e..49d8654905a 100644
--- a/src/NServiceBus.NHibernate/NServiceBus.NHibernate.csproj
+++ b/src/NServiceBus.NHibernate/NServiceBus.NHibernate.csproj
@@ -123,5 +123,5 @@
-
+
\ No newline at end of file
diff --git a/src/NServiceBus.PowerShell/NServiceBus.PowerShell.csproj b/src/NServiceBus.PowerShell/NServiceBus.PowerShell.csproj
index 4ed804c4cc0..b2fc6a50451 100644
--- a/src/NServiceBus.PowerShell/NServiceBus.PowerShell.csproj
+++ b/src/NServiceBus.PowerShell/NServiceBus.PowerShell.csproj
@@ -99,5 +99,5 @@
-
+
\ No newline at end of file
diff --git a/src/NServiceBus.Serializers.XML.XsdGenerator/NServiceBus.Serializers.XML.XsdGenerator.csproj b/src/NServiceBus.Serializers.XML.XsdGenerator/NServiceBus.Serializers.XML.XsdGenerator.csproj
index e6a9989f22f..831f3e0f4c4 100644
--- a/src/NServiceBus.Serializers.XML.XsdGenerator/NServiceBus.Serializers.XML.XsdGenerator.csproj
+++ b/src/NServiceBus.Serializers.XML.XsdGenerator/NServiceBus.Serializers.XML.XsdGenerator.csproj
@@ -85,5 +85,5 @@
-
+
\ No newline at end of file
diff --git a/src/NServiceBus.Testing/NServiceBus.Testing.csproj b/src/NServiceBus.Testing/NServiceBus.Testing.csproj
index 4d9e0825ed6..186e15dd9af 100644
--- a/src/NServiceBus.Testing/NServiceBus.Testing.csproj
+++ b/src/NServiceBus.Testing/NServiceBus.Testing.csproj
@@ -95,5 +95,5 @@
-
+
diff --git a/src/NServiceBus/NServiceBus.csproj b/src/NServiceBus/NServiceBus.csproj
index 7eca0598357..a34a1cbbf80 100644
--- a/src/NServiceBus/NServiceBus.csproj
+++ b/src/NServiceBus/NServiceBus.csproj
@@ -129,5 +129,5 @@
-
+
\ No newline at end of file
diff --git a/src/ObjectBuilder.Autofac/ObjectBuilder.Autofac.csproj b/src/ObjectBuilder.Autofac/ObjectBuilder.Autofac.csproj
index 10d02f628c7..720397d5910 100644
--- a/src/ObjectBuilder.Autofac/ObjectBuilder.Autofac.csproj
+++ b/src/ObjectBuilder.Autofac/ObjectBuilder.Autofac.csproj
@@ -102,5 +102,5 @@
-
+
diff --git a/src/ObjectBuilder.CastleWindsor/ObjectBuilder.CastleWindsor.csproj b/src/ObjectBuilder.CastleWindsor/ObjectBuilder.CastleWindsor.csproj
index 035c359c33b..bddbd58c176 100644
--- a/src/ObjectBuilder.CastleWindsor/ObjectBuilder.CastleWindsor.csproj
+++ b/src/ObjectBuilder.CastleWindsor/ObjectBuilder.CastleWindsor.csproj
@@ -106,5 +106,5 @@
-
+
diff --git a/src/ObjectBuilder.Ninject/ObjectBuilder.Ninject.csproj b/src/ObjectBuilder.Ninject/ObjectBuilder.Ninject.csproj
index 7a80e6d3ba0..daf03d29a7f 100644
--- a/src/ObjectBuilder.Ninject/ObjectBuilder.Ninject.csproj
+++ b/src/ObjectBuilder.Ninject/ObjectBuilder.Ninject.csproj
@@ -90,5 +90,5 @@
-
+
diff --git a/src/ObjectBuilder.Spring/ObjectBuilder.Spring.csproj b/src/ObjectBuilder.Spring/ObjectBuilder.Spring.csproj
index 6db5f795f31..2f0f20849fe 100644
--- a/src/ObjectBuilder.Spring/ObjectBuilder.Spring.csproj
+++ b/src/ObjectBuilder.Spring/ObjectBuilder.Spring.csproj
@@ -84,5 +84,5 @@
-
+
\ No newline at end of file
diff --git a/src/ObjectBuilder.StructureMap/ObjectBuilder.StructureMap.csproj b/src/ObjectBuilder.StructureMap/ObjectBuilder.StructureMap.csproj
index f4bfb62ae55..1831bfbfc9d 100644
--- a/src/ObjectBuilder.StructureMap/ObjectBuilder.StructureMap.csproj
+++ b/src/ObjectBuilder.StructureMap/ObjectBuilder.StructureMap.csproj
@@ -99,5 +99,5 @@
-
+
diff --git a/src/ObjectBuilder.Unity/ObjectBuilder.Unity.csproj b/src/ObjectBuilder.Unity/ObjectBuilder.Unity.csproj
index 03878590bf7..8682417a3f4 100644
--- a/src/ObjectBuilder.Unity/ObjectBuilder.Unity.csproj
+++ b/src/ObjectBuilder.Unity/ObjectBuilder.Unity.csproj
@@ -96,5 +96,5 @@
-
+
\ No newline at end of file
diff --git a/src/ReturnToSourceQueue/ReturnToSourceQueue.csproj b/src/ReturnToSourceQueue/ReturnToSourceQueue.csproj
index 3ed2544399c..bfb7c4dfadd 100644
--- a/src/ReturnToSourceQueue/ReturnToSourceQueue.csproj
+++ b/src/ReturnToSourceQueue/ReturnToSourceQueue.csproj
@@ -85,5 +85,5 @@
-
+
\ No newline at end of file
diff --git a/src/licenseinstaller/LicenseInstaller.csproj b/src/licenseinstaller/LicenseInstaller.csproj
index 0f1c7d369a7..2db2a8fdcc0 100644
--- a/src/licenseinstaller/LicenseInstaller.csproj
+++ b/src/licenseinstaller/LicenseInstaller.csproj
@@ -53,5 +53,5 @@
-
+
\ No newline at end of file