diff --git a/Source/Csla.Shared/Csla.Shared.projitems b/Source/Csla.Shared/Csla.Shared.projitems
index 40595e8c88..6b4ee25034 100644
--- a/Source/Csla.Shared/Csla.Shared.projitems
+++ b/Source/Csla.Shared/Csla.Shared.projitems
@@ -328,7 +328,7 @@
-
+
diff --git a/Source/Csla.Shared/DataPortalClient/HttpProxy.cs b/Source/Csla.Shared/DataPortalClient/HttpProxy.cs
index 79e5bdfb7d..7e05cd2cc8 100644
--- a/Source/Csla.Shared/DataPortalClient/HttpProxy.cs
+++ b/Source/Csla.Shared/DataPortalClient/HttpProxy.cs
@@ -9,6 +9,7 @@
using Csla.Core;
using Csla.Serialization.Mobile;
using Csla.Server;
+using Csla.Threading;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -395,11 +396,11 @@ public async Task Delete(Type objectType, object criteria, Dat
private async Task CallDataPortalServer(HttpClient client, byte[] serialized, string operation, string routingToken, bool isSync)
{
+ var task = CallDataPortalServer(client, serialized, operation, routingToken);
if (isSync)
- serialized = Threading.SyncTask.Run(new Func>(
- async () => await CallDataPortalServer(client, serialized, operation, routingToken)));
+ serialized = task.RunWithContext(_client.Timeout);
else
- serialized = await CallDataPortalServer(client, serialized, operation, routingToken);
+ serialized = await task;
return serialized;
}
diff --git a/Source/Csla.Shared/Threading/ContextParams.cs b/Source/Csla.Shared/Threading/ContextParams.cs
index e1c9731808..757d320479 100644
--- a/Source/Csla.Shared/Threading/ContextParams.cs
+++ b/Source/Csla.Shared/Threading/ContextParams.cs
@@ -40,13 +40,8 @@ internal void SetThreadContext()
{
Csla.ApplicationContext.User = User;
Csla.ApplicationContext.SetContext(ClientContext, GlobalContext);
-#if NETFX_CORE
- // do nothing because we can't set the context on a non-UI thread
- // in WinRT or UWP
-#else
Thread.CurrentThread.CurrentUICulture = UICulture;
Thread.CurrentThread.CurrentCulture = Culture;
-#endif
}
}
}
\ No newline at end of file
diff --git a/Source/Csla.Shared/Threading/SyncTask.cs b/Source/Csla.Shared/Threading/SyncTask.cs
deleted file mode 100644
index 9c4835327e..0000000000
--- a/Source/Csla.Shared/Threading/SyncTask.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-//-----------------------------------------------------------------------
-//
-// Copyright (c) Marimer LLC. All rights reserved.
-// Website: http://www.lhotka.net/cslanet/
-//
-//
-//-----------------------------------------------------------------------
-using System;
-using System.Globalization;
-using System.Security.Principal;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Csla.Threading
-{
- ///
- /// Run an async operation synchronously without
- /// blocking the UI thread.
- ///
- public static class SyncTask
- {
- private static readonly TaskFactory _myTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
-
- ///
- /// Run an async function synchronously without
- /// blocking the UI thread.
- ///
- public static T Run(Func> func)
- {
- var context = new ContextParams();
- return _myTaskFactory.StartNew>(delegate
- {
- context.SetThreadContext();
- return func();
- }).Unwrap().GetAwaiter().GetResult();
- }
- }
-}
diff --git a/Source/Csla.Shared/Threading/TaskExtensions.cs b/Source/Csla.Shared/Threading/TaskExtensions.cs
new file mode 100644
index 0000000000..f68a147984
--- /dev/null
+++ b/Source/Csla.Shared/Threading/TaskExtensions.cs
@@ -0,0 +1,99 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) Marimer LLC. All rights reserved.
+// Website: http://www.lhotka.net/cslanet/
+//
+//
+//-----------------------------------------------------------------------
+using System;
+using System.Globalization;
+using System.Security.Principal;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Csla.Threading
+{
+ ///
+ /// Run an async operation synchronously without
+ /// blocking the UI thread.
+ ///
+ public static class TaskExtensions
+ {
+ private static readonly TaskFactory _myTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
+
+ ///
+ /// Run an async function synchronously without
+ /// blocking the UI thread.
+ ///
+ ///
+ /// The async function is run on a thread in the thread
+ /// pool, the result is marshalled back to the calling
+ /// thread. The calling thread's context is carried
+ /// onto the background thread.
+ ///
+ /// Task to run synchronously.
+ public static T RunWithContext(this Task task)
+ {
+ var context = new ContextParams();
+ var background = Task.Run(() =>
+ {
+ context.SetThreadContext();
+ task.RunSynchronously();
+ });
+ SpinWait(background);
+ return task.Result;
+ }
+
+ ///
+ /// Run an async function synchronously without
+ /// blocking the UI thread.
+ ///
+ ///
+ /// The async function is run on a thread in the thread
+ /// pool, the result is marshalled back to the calling
+ /// thread. The calling thread's context is carried
+ /// onto the background thread.
+ ///
+ /// Task to run synchronously.
+ /// Max time to wait for completion.
+ public static T RunWithContext(this Task task, TimeSpan timeout)
+ {
+ var context = new ContextParams();
+ var background = Task.Run(() =>
+ {
+ context.SetThreadContext();
+ task.RunSynchronously();
+ });
+ SpinWait(background, timeout);
+ return task.Result;
+ }
+
+ ///
+ /// Wait synchronously (spinwait) for the task to complete.
+ ///
+ /// Task on which to wait.
+ public static void SpinWait(this Task task)
+ {
+ while (!task.IsCompleted)
+ {
+ Thread.Sleep(1);
+ }
+ }
+
+ ///
+ /// Wait synchronously (spinwait) for the task to complete.
+ ///
+ /// Task on which to wait.
+ /// Timeout value
+ public static void SpinWait(this Task task, TimeSpan timeout)
+ {
+ var deadline = DateTime.Now + timeout;
+ while (!task.IsCompleted)
+ {
+ if (DateTime.Now > deadline)
+ throw new TimeoutException();
+ Thread.Sleep(1);
+ }
+ }
+ }
+}
diff --git a/Source/csla.netcore.test/Threading/TaskExtenstionTests.cs b/Source/csla.netcore.test/Threading/TaskExtenstionTests.cs
new file mode 100644
index 0000000000..1bdebcfc4e
--- /dev/null
+++ b/Source/csla.netcore.test/Threading/TaskExtenstionTests.cs
@@ -0,0 +1,62 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) Marimer LLC. All rights reserved.
+// Website: http://www.lhotka.net/cslanet/
+//
+// no summary
+//-----------------------------------------------------------------------
+using System;
+using System.Threading.Tasks;
+
+#if !NUNIT
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+#else
+using NUnit.Framework;
+using TestClass = NUnit.Framework.TestFixtureAttribute;
+using TestInitialize = NUnit.Framework.SetUpAttribute;
+using TestCleanup = NUnit.Framework.TearDownAttribute;
+using TestMethod = NUnit.Framework.TestAttribute;
+#endif
+using Csla.Threading;
+
+namespace Csla.Test.Threading
+{
+ [TestClass]
+ public class TaskExtenstionTests
+ {
+ [TestMethod]
+ public void SpinWait()
+ {
+ int x = 0;
+ var task = Task.Run(() => { System.Threading.Thread.Sleep(10); x = 42; });
+ task.SpinWait();
+ Assert.AreEqual(42, x);
+ }
+
+ [TestMethod]
+ [ExpectedException(typeof(TimeoutException))]
+ public void SpinWaitTimeout()
+ {
+ var task = Task.Run(() => System.Threading.Thread.Sleep(10));
+ task.SpinWait(new TimeSpan(0, 0, 0));
+ }
+
+ [TestMethod]
+ public void RunWithContext()
+ {
+ int x = 0;
+ ApplicationContext.ClientContext["x"] = 42;
+ var task = new Task(() => (int)ApplicationContext.ClientContext["x"]);
+ x = task.RunWithContext();
+ Assert.AreEqual(42, x);
+ }
+
+ [TestMethod]
+ [ExpectedException(typeof(TimeoutException))]
+ public void RunWithContextTimeout()
+ {
+ var task = new Task(() => { System.Threading.Thread.Sleep(10); return 42; });
+ int x = task.RunWithContext(new TimeSpan(0, 0, 0));
+ }
+ }
+}
diff --git a/Source/csla.netcore.test/csla.netcore.test.csproj b/Source/csla.netcore.test/csla.netcore.test.csproj
index f9eab4141e..11e2d0c18b 100644
--- a/Source/csla.netcore.test/csla.netcore.test.csproj
+++ b/Source/csla.netcore.test/csla.netcore.test.csproj
@@ -4,6 +4,8 @@
netcoreapp2.1
false
+
+ Csla.Test