My function has three parts.
Part one Parameter Popup
Part two Executes the code in a new thread with ApartmentState.STA turned on.
Part three - Show ReportViewer
I am currently receiving this error the calling thread cannot access this object because a different thread owns it.
public async void AnticipatedEntriesReport(bool fund)
{
var anticipatedReport = new AnticipatedReport(fund);
ReportPreviewForm report = new ReportPreviewForm();
anticipatedReport.InitializeParameters();
if (anticipatedReport.GetParameters() != null)
{
await RunAsyncTask(
() =>
{
report = anticipatedReport.GenerateReport(SelectedLoans);
});
report.Show();
}
}
My code breaks at report.Show().
anticipatedReport.GenerateReport returns a ReportPreviewForm.
I'm wondering what am I doing wrong? I think it's based on where I created the object.
public async Task RunAsyncTask(System.Action action)
{
try
{
await ThreadManager.StartSTATask(action);
}
catch (Exception ex)
{
}
}
public static Task StartSTATask(System.Action func)
{
var tcs = new TaskCompletionSource<object>();
var thread = new Thread(() =>
{
try
{
func();
tcs.SetResult(null);
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
Just create the report inside the task and return it to task's parent:
public async Task AnticipatedEntriesReport(bool fund)
{
var anticipatedReport = new AnticipatedReport(fund);
ReportPreviewForm report = null;
anticipatedReport.InitializeParameters();
if (anticipatedReport.GetParameters() != null)
{
// Generate the report inside the task and return it.
report = await RunAsyncTask(
() =>
{
var result = anticipatedReport.GenerateReport(SelectedLoans);
return result;
});
}
}
and in RunAsyncTask:
public async Task<TResult> RunAsyncTask<TResult>(Func<TResult> function)
{
TResult result = default(TResult);
UpdateBusyUi(true);
try
{
result = await ThreadManager.StartSTATask(function);
}
catch (Exception ex)
{
SendException(ex);
LoadSucceed = false;
Events.PublishOnUIThread(new BackgroundCompletedEvent { Header = BackgroundCompletedEvent.EntityActions.Error, Error = true });
}
UpdateBusyUi(false);
return result;
}
The StartSTATask:
Task<TResult> StartSTATask<TResult>(Func<TResult> function)
{
TaskCompletionSource<TResult> source = new TaskCompletionSource<TResult>();
Thread thread = new Thread(() =>
{
try
{
source.SetResult(function());
}
catch (Exception ex)
{
source.SetException(ex);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return source.Task;
}
Related
Is there any way to convert the Task to a Task async or something similar?
I'm testing code, in short learning to perform different functions of Task type and learn to use its correct operation, however I have not been able to solve this "problem", so I want to ask people who have more knowledge about the Tasks.
Task<bool>.Factory.StartNew(() => {}); -> Task<bool>.Factory.StartNew(async () => {});
Here is a summary of what I want to do
private bool completed = false;
void Tester()
{
completed = false;
int iteration = 0;
var log = new Logger();
log.Log(Logger.Level.Debug, "Starting");
try
{
var theTask = Task<bool>.Factory.StartNew( () =>
{
while (!completed)
{
log.Log(Logger.Level.Debug, "Waiting",1);
iteration++;
Thread.Sleep(400);
if (iteration>20)
{
completed = true;
return true;
}
}
return false;
}).Result;
}
catch (Exception e)
{
log.Log(Logger.Level.Error, e.ToString());
}
finally
{
log.Log(Logger.Level.Info, "Completed");
}
}
You can do it. You can see this video to understand async/await pattern: https://www.youtube.com/watch?v=il9gl8MH17s.
Try this:
class Program
{
static async Task Main(string[] args)
{
bool result = await Tester();
System.Diagnostics.Debug.WriteLine($"result: {result}");
}
private static bool completed = false;
static async Task<bool> Tester()
{
completed = false;
int iteration = 0;
//var log = new Logger();
//log.Log(Logger.Level.Debug, "Starting");
try
{
await Task.Factory.StartNew(() =>
{
while (!completed)
{
//log.Log(Logger.Level.Debug, "Waiting", 1);
iteration++;
System.Diagnostics.Debug.WriteLine($"iteration {iteration}");
Task.Delay(2000);
if (iteration > 20)
{
completed = true;
}
}
});
}
catch (Exception e)
{
//log.Log(Logger.Level.Error, e.ToString());
}
finally
{
//log.Log(Logger.Level.Info, "Completed");
}
return completed;
}
}
I want to make a Wifimanager class for UWP (Raspberry pi 3)
I looked at some tutorials and figured i was good to go.
So I came up with this:
public class WifiManager
{
private WiFiAdapter adapter;
public List<WifiNetwork> Networks;
public WifiManager()
{
Initialize();
}
private async void Initialize()
{
var access = await WiFiAdapter.RequestAccessAsync();
if (access != WiFiAccessStatus.Allowed)
{
throw new WifiAdaperAccessDeniedException();
}
else
{
var result = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(WiFiAdapter.GetDeviceSelector());
if (result.Count >= 1)
{
adapter = await WiFiAdapter.FromIdAsync(result[0].Id);
}
else
{
throw new NoWifiAdapterFoundException();
}
}
}
public async Task GetAvailableNetWorksAsync()
{
try
{
if (adapter != null)
{
await adapter.ScanAsync();
}
}
catch (Exception err)
{
throw new WifiAdaperAccessDeniedException();
}
Networks = new List<WifiNetwork>();
foreach(var network in adapter.NetworkReport.AvailableNetworks)
{
Networks.Add(new WifiNetwork(network, adapter));
}
}
}
However when I try to get the Available Networks using the async function the adapter is null. When I remove the if statement around await adapter.ScanAsync(); I get an AccessViolation.
I dont have much experience with async tasks and such, but the tutorials i found did not gave me the explaination i needed to fix this.
The problem is that you are calling an async method from the constructor. Since you do no wait for the result and are probably calling GetAvailableNetWorksAsync directly after the constructor the adapter variable has not been set yet..
You need to take it out of the constructor like this:
public class WifiManager
{
private WiFiAdapter adapter;
public List<WifiNetwork> Networks;
public async Task InitializeAsync()
{
var access = await WiFiAdapter.RequestAccessAsync();
if (access != WiFiAccessStatus.Allowed)
{
throw new WifiAdaperAccessDeniedException();
}
else
{
var result = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(WiFiAdapter.GetDeviceSelector());
if (result.Count >= 1)
{
adapter = await WiFiAdapter.FromIdAsync(result[0].Id);
}
else
{
throw new NoWifiAdapterFoundException();
}
}
}
public async Task GetAvailableNetWorksAsync()
{
try
{
if (adapter != null)
{
await adapter.ScanAsync();
}
}
catch (Exception err)
{
throw new WifiAdaperAccessDeniedException();
}
Networks = new List<WifiNetwork>();
foreach(var network in adapter.NetworkReport.AvailableNetworks)
{
Networks.Add(new WifiNetwork(network, adapter));
}
}
}
Now your calling code probably looks like this:
var wifiManager = new WifiManager();
await wifiManager.GetAvailableNetWorksAsync();
change that to
var wifiManager = new WifiManager();
await wifiManager.InitializeAsync();
await wifiManager.GetAvailableNetWorksAsync();
Take away: do not call async methods in a constructor since you cannot await completion using the await keyword and using .Wait() or .Result might give other troubles . Applies for 99% of all situations.
Another approach could be something like:
public class WifiManager
{
private WiFiAdapter adapter;
public List<WifiNetwork> Networks;
pivate async Task InitializeAsync()
{
var access = await WiFiAdapter.RequestAccessAsync();
if (access != WiFiAccessStatus.Allowed)
{
throw new WifiAdaperAccessDeniedException();
}
else
{
var result = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(WiFiAdapter.GetDeviceSelector());
if (result.Count >= 1)
{
adapter = await WiFiAdapter.FromIdAsync(result[0].Id);
}
else
{
throw new NoWifiAdapterFoundException();
}
}
}
public async Task GetAvailableNetWorksAsync()
{
try
{
if (adapter == null)
{
await InitializeAsync();
}
if (adapter != null)
{
await adapter.ScanAsync();
}
}
catch (Exception err)
{
throw new WifiAdaperAccessDeniedException();
}
Networks = new List<WifiNetwork>();
foreach(var network in adapter.NetworkReport.AvailableNetworks)
{
Networks.Add(new WifiNetwork(network, adapter));
}
}
}
I am working on a Task parallel problem that I have many Tasks that may or may not throw Exception.
I want to process all the tasks that finishes properly and log the rest. The Task.WhenAll propage the Task exception without allowing me to gather the rest results.
static readonly Task<string> NormalTask1 = Task.FromResult("Task result 1");
static readonly Task<string> NormalTask2 = Task.FromResult("Task result 2");
static readonly Task<string> ExceptionTk = Task.FromException<string>(new Exception("Bad Task"));
var results = await Task.WhenAll(new []{ NormalTask1,NormalTask2,ExceptionTk});
The Task.WhenAll with throw the Exception of ExcceptionTk ignoring the rest results. How I can get the results ignoring the Exception and log the exception at same time?
I could wrap the task into another task that try{...}catch(){...} the internal exception but I don't have access to them and I hope I will not have to add this overhead.
You can create a method like this to use instead of Task.WhenAll:
public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks)
{
return Task.WhenAll(
tasks.Select(
task => task.ContinueWith(
t => t.IsFaulted
? new ResultOrException<T>(t.Exception)
: new ResultOrException<T>(t.Result))));
}
public class ResultOrException<T>
{
public ResultOrException(T result)
{
IsSuccess = true;
Result = result;
}
public ResultOrException(Exception ex)
{
IsSuccess = false;
Exception = ex;
}
public bool IsSuccess { get; }
public T Result { get; }
public Exception Exception { get; }
}
Then you can check each result to see if it was successful or not.
EDIT: the code above doesn't handle cancellation; here's an alternative implementation:
public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks)
{
return Task.WhenAll(tasks.Select(task => WrapResultOrException(task)));
}
private async Task<ResultOrException<T>> WrapResultOrException<T>(Task<T> task)
{
try
{
var result = await task;
return new ResultOrException<T>(result);
}
catch (Exception ex)
{
return new ResultOrException<T>(ex);
}
}
You can get the result of each successfully completed Task<TResult> from its property Result.
var normalTask1 = Task.FromResult("Task result 1");
var normalTask2 = Task.FromResult("Task result 2");
var exceptionTk = Task.FromException<string>(new Exception("Bad Task"));
Task<string>[] tasks = new[] { normalTask1, normalTask2, exceptionTk };
Task whenAll = Task.WhenAll(tasks);
try
{
await whenAll;
}
catch
{
if (whenAll.IsFaulted) // There is also the possibility of being canceled
{
foreach (var ex in whenAll.Exception.InnerExceptions)
{
Console.WriteLine(ex); // Log each exception
}
}
}
string[] results = tasks
.Where(t => t.IsCompletedSuccessfully)
.Select(t => t.Result)
.ToArray();
Console.WriteLine($"Results: {String.Join(", ", results)}");
Output:
System.Exception: Bad Task
Results: Task result 1, Task result 2
You can add HOC with exception handling and then check success.
class Program
{
static async Task Main(string[] args)
{
var itemsToProcess = new[] { "one", "two" };
var results = itemsToProcess.ToDictionary(x => x, async (item) =>
{
try
{
var result = await DoAsync();
return ((Exception)null, result);
}
catch (Exception ex)
{
return (ex, (object)null);
}
});
await Task.WhenAll(results.Values);
foreach(var item in results)
{
Console.WriteLine(item.Key + (await item.Value).Item1 != null ? " Failed" : "Succeed");
}
}
public static async Task<object> DoAsync()
{
await Task.Delay(10);
throw new InvalidOperationException();
}
}
I have a unit test which is running forever:
[Test]
public bool test()
{
manager.Send(10);
Thread.Sleep(1000);
manager.Messages.Should().HaveCount(10);
return true;
}
manager.Send() method is:
private void Send()
{
try
{
var entities = GetAllEntities();
foreach (var group in entities.GroupBy(r => r.Priority))
{
var tasks = group.Select(entity => Task.Factory.StartNew(() => manager.SendEntity(entity))).ToList();
Task.WaitAll(tasks.ToArray());
if (tasks.All(r => r.Result.Result == true))
{
// some code here...
}
}
}
catch (Exception e)
{
logger.FatalException(e.Message, e);
}
finally
{
logger.Info("End...");
}
}
and SendEntity() method:
public Task<bool> SendEntity(DeferredEntity entity)
{
var taskCompletionSource = new TaskCompletionSource<bool>();
try
{
logger.Info("Sending entity {0} with params: {1}", entity.Entity, GetEntityParams(entity));
server.SendToServer(entity, (response, result) =>
{
taskCompletionSource.SetResult(result);
});
}
catch (Exception e)
{
logger.FatalException(e.Message, e);
}
return taskCompletionSource.Task;
}
in unit test manager.Send(10) is running forever. I debuged the code and I see that the problem is in
if (tasks.All(r => r.Result.Result == true))
the debugger stops on this line and sleeps forever. What I am doing wrong? I added return value of unit test method to bool (async methods doesn't throw exceptions in void methods). But it doesn't help. Do you have any suggestions?
You get the deadlock there.
First of all you don't have to start the new Thread with
Task.Factory.StartNew(() => manager.SendEntity(entity)
It seems SendToServer is already async.
It also a bad practice to use the Task.Wait***/Task.Result, use the async flow
private async Task Send()
{
try
{
var entities = GetAllEntities();
foreach (var group in entities.GroupBy(r => r.Priority))
{
var tasks = group
.Select(entity => manager.SendEntity(entity))
.ToArray();
var results = await Task.WhenAll(tasks);
if (results.All(result => result))
{
// some code here...
}
}
}
catch (Exception e)
{
logger.FatalException(e.Message, e);
}
finally
{
logger.Info("End...");
}
}
But if you don't want to rewrite the Send Method you can use .ConfigureAwait(false)
return taskCompletionSource.Task.ConfigureAwait(false);
But anyway, remove the StartNew - you don't need this.
I have a method, shown below, which calls a service.
How can I run this method through thread?
public List<AccessDetails> GetAccessListOfMirror(string mirrorId,string server)
{
List<AccessDetails> accessOfMirror = new List<AccessDetails>();
string loginUserId = SessionManager.Session.Current.LoggedInUserName;
string userPassword = SessionManager.Session.Current.Password;
using (Service1Client client = new Service1Client())
{
client.Open();
accessOfMirror = client.GetMirrorList1(mirrorId, server, null);
}
return accessOfMirror;
}
In C# 3.5 or 4.0 you can do this.
var task = Task.Factory.StartNew<List<AccessDetails>>(() => GetAccessListOfMirror(mirrorId,server))
.ContinueWith(tsk => ProcessResult(tsk));
private void ProcessResult(Task task)
{
var result = task.Result;
}
In C# 4.5 there's the await/async keywords which is some sugar for above
public async Task<List<AccessDetails>> GetAccessListOfMirror(string mirrorId,string server)
var myResult = await GetAccessListOfMirror(mirrorId, server)
Try something like this:
public async Task<List<AccessDetails>> GetAccessListOfMirror(string mirrorId, string server)
{
List<AccessDetails> accessOfMirror = new List<AccessDetails>();
string loginUserId = SessionManager.Session.Current.LoggedInUserName;
string userPassword = SessionManager.Session.Current.Password;
using (Service1Client client = new Service1Client())
{
client.Open();
Task<List<AccessDetails>> Detail = client.GetMirrorList1(mirrorId, server, null);
accessOfMirror = await Detail;
}
return accessOfMirror;
}
Below is a helper class I use, it references RX.NET.
If you include that in your project, then you can thread stuff very simply - the code above you could spin off to a separate thread as follows:
int mirrorId = 0;
string server = "xxx";
ASync.Run<List<AccessDetails>>(GetAccessListOfMirror(mirrorId,server), resultList => {
foreach(var accessDetail in resultList)
{
// do stuff with result
}
}, error => { // if error occured on other thread, handle exception here });
Worth noting: that lambda expression is merged back to the original calling thread - which is very handy if you're initiating your async operations from a GUI thread for example.
It also has another very handy method: Fork lets you spin off multiple worker threads and causes the calling thread to block until all the sub-threads are either complete or errored.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Concurrency;
namespace MyProject
{
public static class ASync
{
public static void ThrowAway(Action todo)
{
ThrowAway(todo, null);
}
public static void ThrowAway(Action todo, Action<Exception> onException)
{
if (todo == null)
return;
Run<bool>(() =>
{
todo();
return true;
}, null, onException);
}
public static bool Fork(Action<Exception> onError, params Action[] toDo)
{
bool errors = false;
var fork = Observable.ForkJoin(toDo.Select(t => Observable.Start(t).Materialize()));
foreach (var x in fork.First())
if (x.Kind == NotificationKind.OnError)
{
if(onError != null)
onError(x.Exception);
errors = true;
}
return !errors;
}
public static bool Fork<T>(Action<Exception> onError, IEnumerable<T> args, Action<T> perArg)
{
bool errors = false;
var fork = Observable.ForkJoin(args.Select(arg => Observable.Start(() => { perArg(arg); }).Materialize()));
foreach (var x in fork.First())
if (x.Kind == NotificationKind.OnError)
{
if (onError != null)
onError(x.Exception);
errors = true;
}
return !errors;
}
public static void Run<TResult>(Func<TResult> todo, Action<TResult> continuation, Action<Exception> onException)
{
bool errored = false;
IDisposable subscription = null;
var toCall = Observable.ToAsync<TResult>(todo);
var observable =
Observable.CreateWithDisposable<TResult>(o => toCall().Subscribe(o)).ObserveOn(Scheduler.Dispatcher).Catch(
(Exception err) =>
{
errored = true;
if (onException != null)
onException(err);
return Observable.Never<TResult>();
}).Finally(
() =>
{
if (subscription != null)
subscription.Dispose();
});
subscription = observable.Subscribe((TResult result) =>
{
if (!errored && continuation != null)
{
try
{
continuation(result);
}
catch (Exception e)
{
if (onException != null)
onException(e);
}
}
});
}
}
}