I am trying to use an async task to read from my sqlite db using sqlite.net and my basic class is this one below:
public class Students
{
public string Fullname { get; }
public string Admnumber { get; }
}
A quick example of implementing this library is:
public static IEnumerable<Students> QueryVals ()
{
var db = new SQLiteConnection("Data Source=assets\\mydb.db;New=False;Version=3");
return db.Query<Students> ("select * from students");
}
but now when I try to use it an async task as below:
public static Task<Students> GetStudentsList ()
{
var db = new SQLiteConnection("Data Source=assets\\mydb.db;New=False;Version=3");
return db.Query<Students> ("select * from students");
}
I get an error:
Cannot implicitly convert type
'System.Collection.Generic.List' to
'System.Threading.Tasks.Task'
even tyring this doesn't work:
private async void Init()
{
IsBusy = true;
var db = new SQLiteConnection("Data Source=assets\\mydb.db;New=False;Version=3");
var myitems = await db.Query<Students>("select * from students");
IsBusy = false;
}
before I finish it gives the error that my class Students does not have GetAwaiter
You can't just make something asynchronous by changing the return type to Task<T>. Firstly, you need to switch to using the SQLiteAsyncConnection object and the async version of the Query method:
new SQLiteAsyncConnection("...");
...
db.QueryAsync<Students>("select * from students");
// ^^^^^
// Add this
Now you have two options. The first is to await the result, as shown in the answer by mm8. The other, and probably the one I would choose is to just return the task and let the caller await:
public static Task<IEnumerable<Students>> GetStudentsListAsync()
{
var db = new SQLiteAsyncConnection("Data Source=assets\\mydb.db;New=False;Version=3");
return db.QueryAsync<Students>("select * from students");
}
Note I'm also using the common convention of renaming the method to indicate it is async.
A method that returns a Task<T> is supposed to either be async and await something or return a Task.
You could add the async keyword to your method and await the asynchronous QueryAsync method:
public static async Task<IEnumerable<Students>> GetStudentsListAsync()
{
var db = new SQLiteAsyncConnection("Data Source=assets\\mydb.db;New=False;Version=3");
return await db.QueryAsync<Students>("select * from students");
}
Or return an uncompleted task to be awaited by the caller of the method:
public static Task<IEnumerable<Students>> GetStudentsListAsync()
{
var db = new SQLiteAsyncConnection("Data Source=assets\\mydb.db;New=False;Version=3");
return db.QueryAsync<Students>("select * from students");
}
Related
How can i await for a Task and return its result and putting the results of the Task into a BindableCollection.
Having trouble with the syntax for (return await Task.Run()) and putting it into a BindableCollection.
Basically what iam trying todo is to await for the result of the method, return it and put it into a BindableCollection in ViewModel and binding to the ItemsControl.
I looked up for some examples in multiple threads, unfortuneatly none of the threads contains anything about BindableCollection.
I can only guess that i have to Convert somehow the Generic List to IEnumerable, though i have no clue how.
public class DataAccess : Conductor<object>
{
public async Task<List<DataModel>> Starter(IProgress<ProgressReportModel> progress, CancellationToken cancellationToken)
{
List<DataModel> output = new List<DataModel>();
//What i tried so far
return await ScannerAsync(progress, cancellationToken);
List<GameDataModel>> output = await ScannerAsync(progress, cancellationToken);
}
private static async Task<List<DataModel>> ScannerAsync(IProgress<ProgressReportModel> progress, CancellationToken cs)
{
await Task.Run(() =>
{
Do Stuff
}).ConfigureAwait(true);
await Task.Run(() =>
{
Do Stuff and return output.
}).ConfigureAwait(true);
}
}
public class ViewModel : Conductor<object>
{
private BindableCollection<DataModel> Data { get; set; }
private CancellationTokenSource cts = new CancellationTokenSource();
private Progress<ProgressReportModel> progress = new Progress<ProgressReportModel>();
public void StartScan()
{
DataAccess da = new DataAccess();
Data = new BindableCollection<DataModel>(da.Starter(progress, cts.Token));
// ERROR: Cannot Convert from Tasks.Task to Generic.IEnumerable
}
}
Your code tries to convert the Task to BindableCollection, you'd want to convert the RESULT of the task instead, to do it you need to await the da.Start call:
Data = new BindableCollection<DataModel>(await da.Starter(progress, cts.Token));
You may need to tweak the signature of your StartScan method to
public async Task StartScan()
The following code enters GetIds method and never return.
public static class ANameOrchestrator
{
[FunctionName(CommonNames.AName)]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
var entityId = new EntityId(nameof(Documents), CommonNames.DocFlowFifo);
var px = context.CreateEntityProxy<IDocuments>(entityId);
IEnumerable<int> list = await px.GetIds();//never return or throw
}
}
I tried to wrap the method call with LockAsync in which case the execution deadlocked on the call.
public static class ANameInOrchestrator
{
[FunctionName(CommonNames.AName)]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
IEnumerable<int> list;
var entityId = new EntityId(nameof(Documents), CommonNames.DocFlowFifo);
using (var lk = await context.LockAsync(entityId)) //never goes beyond the call to LockAync
{
var x = context.CreateEntityProxy<IDocuments>(entityId);
list = await x.GetIds();
}
}
}
How to resolve the problem? What direction do I have to look?
Edit
using alternative version to call the entity operation doesn't work either
list = await context.CallEntityAsync<IEnumerable<int>>(entityId, nameof(Documents.GetIds));
I have the following code section in which SavePersonAsync method were calling 3 external methods and could anyone tell me the implementation of async/await methods were implemented correctly. Does any of the call chains in which async/await was not implemented correctly?
public PersonService(IPersonDbService personDbService,
IPersonEntityToPersonModelMapper personEntityToPersonModelMapper,
IPersonModelToPersonEntityMapper personModelToPersonEntityMapper)
{
_personDbService = personDbService;
_personEntityToPersonModelMapper = personEntityToPersonModelMapper;
_personModelToPersonEntityMapper = personModelToPersonEntityMapper;
}
public async Task<IEnumerable<PersonModel>> SavePersonAsync(IEnumerable<PersonModel> personsModel)
{
var personsEntity = await _personModelToPersonEntityMapper.MapPersonModelToPersonEntityAsync(personsModel);
var savedPersons = await _personDbService.SavePersonAsync(personsEntity.First()); // Currently only alow one person at a time, later it will allow to save a collection of persons
return await _personEntityToPersonModelMapper.MapPersonEntityToPersonModelyAsync(new List<PersonEntity>
{
savedPersons
});
}
}
public class PersonEntityToPersonModelMapper : IPersonEntityToPersonModelMapper
{
public async Task<IEnumerable<PersonModel>> MapPersonEntityToPersonModelyAsync(
IEnumerable<PersonEntity> personsEntity)
{
if (personsEntity.NullOrEmpty())
return await Task.FromResult(Enumerable.Empty<PersonModel>());
return await Task.FromResult(personsEntity.Select(personEntity => new PersonModel
{
FirstName = personEntity.FirstName,
LastName = personEntity.LastName
}));
}
}
public class PersonModelToPersonEntityMapper : IPersonModelToPersonEntityMapper
{
public async Task<IEnumerable<PersonEntity>> MapPersonModelToPersonEntityAsync(IEnumerable<PersonModel> personsModel)
{
if (personsModel.NullOrEmpty())
return await Task.FromResult(Enumerable.Empty<PersonEntity>());
return await Task.FromResult(personsModel.Select(personModel => new PersonEntity
{
FirstName = personModel.FirstName,
LastName = personModel.LastName
}));
}
}
From the definition of async await when you have written await the flow will start sequential, As you need the output to be used in the next statement then there is not much use of async await in your case
To breief about how it works
Suppose you have to method call which can work async in that can your code would be like:
Var a = GetMethodA();
Var b = GetMethodB();
await a;
await b;
In this case your method will work asynchronous
I'm trying to get the result of this queries to redis (using stackexchange C# client) in parallel but somehow I'm running in deadlock and not sure where
The method for retrieving the data:
public LiveData Get(string sessionId)
{
return GetAsync(sessionId).Result;
}
private async Task<LiveData> GetAsync(string sessionId)
{
var basketTask = GetBasketAsync(sessionId);
var historyTask = GetHistoryAsync(sessionId);
var capturedDataTask = GetCapturedDataAsync(sessionId);
var basket = await basketTask;
var history = await historyTask;
var capturedData = await capturedDataTask;
return new LiveData
{
Basket = basket.IsNullOrEmpty
? new List<Product>()
: JsonConvert.DeserializeObject<List<Product>>(basket),
History = history.Select(cachedProduct
=> JsonConvert.DeserializeObject<Product>(cachedProduct.Value.ToString())).ToList(),
CapturedData = capturedData.ToDictionary<HashEntry, string, object>(
hash => hash.Name, hash => JsonConvert.DeserializeObject(hash.Value))
};
}
And the methods for fetching the cached data from redis are:
private async Task<RedisValue> GetBasketAsync(string key)
{
key = $"{key}{BasketSuffix}";
var redisDb = RedisConnection.Connection.GetDatabase();
redisDb.KeyExpireAsync(key, _expire);
return await redisDb.StringGetAsync(key);
}
private async Task<HashEntry[]> GetHistoryAsync(string key)
{
key = $"{key}{HistorySuffix}";
var redisDb = RedisConnection.Connection.GetDatabase();
redisDb.KeyExpireAsync(key, _expire);
return await redisDb.HashGetAllAsync(key);
}
private async Task<HashEntry[]> GetCapturedDataAsync(string key)
{
key = $"{key}{CapturedDataSuffix}";
var redisDb = RedisConnection.Connection.GetDatabase();
redisDb.KeyExpireAsync(key, _expire);
return await redisDb.HashGetAllAsync(key);
}
I think it's fine calling the KeyExpireAsync like this, just because it's fine to trigger and forget but not sure if that could be related (I tried even removing it and it's still blocked)
The source of the deadlock is this snippet:
public LiveData Get(string sessionId)
{
return GetAsync(sessionId).Result;
}
Instead, invoke it the proper way "async all the way":
public async Task<LiveData> Get(string sessionId)
{
return await GetAsync(sessionId);
}
Invoking .Result can lead to deadlocking, as can using the .Wait() API. Also, from the looks of it -- the .KeyExpireAsync needs to be awaited.
async Task<RedisValue> GetBasketAsync(string key)
{
key = $"{key}{BasketSuffix}";
var redisDb = RedisConnection.Connection.GetDatabase();
await redisDb.KeyExpireAsync(key, _expire);
return await redisDb.StringGetAsync(key);
}
I understand your thought process on not using the await keyword on the .KeyExpireAsync call but if I were writing this code I would most certainly want to await it like I have demonstrated. It is a code smell to have a fire-and-forget, and can be easily avoided.
I have a simple Web API method that looks like this:
public async Task<HttpResponseMessage> RunTask(TaskType taskType)
{
var taskId = await TaskManager.CreateTask(taskType);
TaskManager.Run(taskId);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content =
new StringContent($"Task {taskType.GetDescription()} was started.")
};
}
TaskManager.Run is decalared like this:
public async Task Run(int id)
I was expecting it to return "Task was started" message immediately after TaskManager.Run(taskId) But the request continues to run synchronously.
But if to replace the call TaskManager.Run(taskId) with:
Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(100)));
Then it runs asynchronously.
So I believe this is something to do with the resources shared by TaskManager and main thread. Can a shared resource lock the execution?
I'm using Castle Windsor. One WindsorContainer container is declared in Web API project.
TaskManager utilizes BaseTaskRunner class inside of it. One more WindsorContainer is declared in BaseTaskRunner.
Web API's container uses LifeStyle.PerWebRequest for all components. BaseTaskRunner's container uses LifeStyle.Singleton (not sure if it's correct LifeStyle). Could the call be locked for example by DdContext or other classes declared in both of the containers?
UPD:
I don't want to wait the TaskManager.Run to complete. But what happens is that return statement still waits for the TaskManager.Run to complete (even without await statement on TaskManager.Run).
In other words it does not matter how I call the TaskManager.Run:
TaskManager.Run(taskId);
or
await TaskManager.Run(taskId);
It waits for TaskManager.Run to complete in both cases.
Here is the code of TaskManager:
public class TaskManager : ITaskManager
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
public async Task<int> CreateTask(TaskType type, byte[] data = null, object config = null)
{
var task = new BackgroundTask
{
Type = type,
Status = BackgroundTaskStatus.New,
Config = config?.SerializeToXml(),
Created = DateTime.Now,
Data = data
};
TaskRepository.Add(task);
TaskRepository.SaveChanges();
return task.Id;
}
public async Task Run(int id, bool removeOnComplete = true)
{
var task = TaskRepository.GetById(id);
Run(task, removeOnComplete);
}
public async Task Run(TaskType type, bool removeOnComplete = true)
{
var tasksToRun = TaskRepository.Get(t => t.Type == type);
tasksToRun.ForEachAsync(t => Run(t, removeOnComplete));
}
public async Task Run(BackgroundTask task, bool removeOnComplete = true)
{
switch (task.Type)
{
case TaskType.SpreadsheetImport:
new SpreadsheetImportTaskRunner().Run(task);
break;
}
}
}
And some other classes:
public class SpreadsheetImportTaskRunner : BaseTaskRunner
{
public IForecastSpreadsheetManager SpreadsheetManager { get; set; }
protected override void Execute()
{
SpreadsheetManager.ImportActuals(Task.Data);
}
protected override void Initialize()
{
base.Initialize();
SpreadsheetManager = _container.Resolve<IForecastSpreadsheetManager>();
}
}
BaseTaskRunner:
public class BaseTaskRunner
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
protected IWindsorContainer _container = new WindsorContainer();
protected BackgroundTask Task { get; set; }
public async Task Run(BackgroundTask task)
{
Initialize();
Task = task;
try
{
Execute();
}
catch (Exception ex)
{
SetError(ex.ToString());
}
}
protected virtual void Execute()
{
}
protected virtual void Initialize()
{
_container.Install(new TaskRunnerComponentsInstaller());
TaskRepository = _container.Resolve<IRepository<BackgroundTask>>();
}
}
I still believe this is something to do with the WindsorContainer and common classes which are resolved in several different threads.
The issue is that you're not using await on the Task being returned from the invocation of the TaskManager.Run function. Consider the below:
public async Task<HttpResponseMessage> RunTask(TaskType taskType)
{
var taskId = await TaskManager.CreateTask(taskType);
await TaskManager.Run(taskId);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content =
new StringContent($"Task {taskType.GetDescription()} was started.")
};
}
Now it will work asynchronously as you'd expect. The await sets a continuation marker in the async state-machine, instructing it to return to this portion of the method upon completion of the asynchronous operation defined in the TaskManager.Run.
UPDATE
You are missing lots of await statements, and there are times where you need to not mark methods as async. It appears as though there are some mis-understandings as it pertains to these keywords. Here is what your TaskManager class should look like.
public class TaskManager : ITaskManager
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
public async Task<int> CreateTask(TaskType type,
byte[] data = null,
object config = null)
{
var task = new BackgroundTask
{
Type = type,
Status = BackgroundTaskStatus.New,
Config = config?.SerializeToXml(),
Created = DateTime.Now,
Data = data
};
TaskRepository.Add(task);
TaskRepository.SaveChanges();
return task.Id;
}
public ask Run(int id, bool removeOnComplete = true)
{
var task = TaskRepository.GetById(id);
return Run(task, removeOnComplete);
}
public Task Run(TaskType type, bool removeOnComplete = true)
{
var tasksToRun = TaskRepository.Get(t => t.Type == type);
return tasksToRun.ForEachAsync(t => Run(t, removeOnComplete));
}
public Task Run(BackgroundTask task, bool removeOnComplete = true)
{
switch (task.Type)
{
case TaskType.SpreadsheetImport:
return new SpreadsheetImportTaskRunner().Run(task);
break;
}
}
}
}
Ideally, if the method is marked as a return type of Task and the method doesn't need to unwind any tasks within its execution it can simply return the Task functionality for its implementation. For example, notice how dramatically my TaskManager class differs from yours -- I'm only marking methods as async that need to actually await. These two keywords should be married, if a method uses async there should be an await. But only use await if the method needs to unwind and use the asynchronous operation.