I wrote this code in my Repository
Task<bool> UpdateUserAsync(User user);
But I do not know how to write supplementary code in the implementer class
This code receives the information of a user and edits it in the database
Given that this method must be Async
I'm not entirely sure what you want to do, post your code and you might get a better response but if you're asking about how to write an async method then it's pretty straightforward and clean.
If your "Repository" that you refer to is an interface and you're asking how to write your implementation async then you'll want to do something like this:
public async Task<bool> UpdateUserAsync(User user){
// Check the user exists
var existingUser = await GetUserAsync(user.Id);
if (existingUser == null) {
return false;
}
var success = await DoMySaveTransactions(); // This would be where you commit to your chosen backend.
return success;
}
If you're asking about how to use your new repository then you'd use something like the following inside a method which is decorated with async.
async void UpdateUsername(User existingUser, string newUsername) {
existingUser.username = newUsername;
var success = await _myRepository.UpdateUserAsync(existingUser);
// Do something with success.
}
If you want to use the implementation in a non async method then your code would be something like...
void UpdateUsername(User existingUser, string newUsername) {
existingUser.username = newUsername;
var success = myRepository.UpdateUserAsync(existingUser).GetAwaiter().GetResult();
// Do something with success.
}
If I've misunderstood what you're looking to do, please add some more explanation.
Is your problem in the async part, or in the "fetch and update user" part?
The parts about "Fetch and update user" are difficult to describe if you don't tell us the method you are using to access the database: are you using entity framework? SQL?
SQL, DbConnection, DbCommand
Let's assume you have already synchronous methods:
public User FetchUserById(int userId) {...}
private void UpdateExistingUser(User user) {...}
You will have to create similar async methods:
public Task<User> FetchUserByIdAsync(int userId);
private Task UpdateExistingUserAsync(User user);
If you use SQL, you will probably use class DbCommand and methods ExecuteReader, and ExecuteNonQuery. For your async methods, use similar async methods.
Note: to use DisposeAsync, you need C# 8. Otherwise use try ... finally and call DisposeAsync explicitly
private async dbConnection CreateFetchUserCommand(
DbConnection Connection,
int userId)
{
var dbCommand = connection.CreateCommand();
dbCommand.CommandText = ...
var dbParameter = dbCommand.CreateParameter();
... // etc.
return dbCommand;
}
private async DbCommand CreateUpdateUserCommand(DbConnection connection, User user)
{
var dbCommand = connection.CreateCommand();
dbCommand.CommandText = ...
var dbParameter = dbCommand.CreateParameter();
... // etc.
return dbCommand;
}
public Task<User> FetchUserByIdAsync(int userId)
{
using (var dbConnection = new DbConnection(...))
{
await dbConnection.OpenAsync();
using (var dbCommand = dbConnection.CreateFetchUserCommand(dbConnection, userId))
{
using (var dataReader = await dbCommand.ExecuteReaderAsync())
{
// use async methods to access fetched data
User user = await ...
return user;
}
}
}
}
Similarly: add an UpdateExistingUserAsync which is similar to your existing UpdateUser.
public UpdateUser(User user)
{
// TODO: exception if user null
User existingUser = await FetchUserById(user.Id);
if (existingUser == null)
{
// user does not exist
}
else
{
... // copy values from user to existingUser
await UpdateExistingUserAsync(existingUser);
}
}
The copying from user to existingUser makes it possible to update only the values that you provided. if you always want to update the complete user, then the FetchUserById is not necessary.
Entity Framework
using (var dbConext = new MyDbContext(...))
{
User existingUser = await dbConnection.Users.FindAsync(user.Id)
if (existingUser != null)
{
... // copy values from user to existingUser
await dbContext.SaveAsync();
}
Related
I have one service method with below syntax -
public async Task<List<responseModel>> SearchAsync(RequestModel request)
{
var temp = await _dbservice.searchAsyncDB(request);
// manipulation with temp
foreach(var i in temp)
{
// manipulation with i
var order = await checkstatus(i.orders); // this is a private method call
}
return order;
}
private async Task<someModel> CheckStatus(int orderNumbers)
{
// manipulation with ordernumber
var model = await checkagain(orderNumber) // private call that has Database Call
}
private async Task<someModel> checkagain(int ordernumber)
{
var temp = await _dbservice.checkagainDB(); // database call
}
Basically Multiple private methods with database call. Not sure if I can mock this using Moq or need to refactor the whole code.
I am trying to call Firebase functions inside a "DAL" class as I want to create some abstraction. I cannot figure out how to return a variable from inside the callback, or how to pass in a callback to execute from the controller class I created. How would I make UserExistsInFirebase async and call that from a controller class like
public void GetUser() {
bool exists = await firebase.UserExistsInFirebase("User1");
}
public Task<bool> UserExistsInFirebase(string Username)
{
bool isExists = false;
reference.Child("Users").Child(Username).Child("Username").Child(Username).GetValueAsync().ContinueWithOnMainThread(task =>
{
if (task.IsCompleted)
{
DataSnapshot snapshot = task.Result;
//checks to see if we found another user with the same username
if (snapshot.GetValue(true) != null)
{
isExists = true;
}
}
});
return isExists;
}
In your current code the issue is that ContinueWithInMainThread is callback called some time later once the task is finished. In the meantime it doesn't block your UserExistsInFirebase at all which rather directly continues and returns false.
Note btw that a method would need to be async in order to be able to use await within it ;)
So instead of ContinueWithInMainThread you would rather make your task async and use await once more.
public async Task<bool> UserExistsInFirebase(string Username)
{
var snapShot = await reference.Child("Users").Child(Username).Child("Username").Child(Username).GetValueAsync();
return snapShot.GetValue(true) != null;
}
Now this would then not be returned in the main thread though ;)
You can however again ensure that by using e.g.
public void GetUser()
{
firebase.UserExistsInFirebase("User1").ContinueWithOnMainThread(exists =>
{
// Do something with the bool exists after the request has finished
});
// again anything here would be immediately executed before the request is finihed
}
so basically you have just abstracted the task but keep the handling of the callback on the top level where you are starting your request.
If you still want the error handling like before you could probably also do something like
public async Task<bool> UserExistsInFirebase(string Username)
{
bool isExists = false;
await reference.Child("Users").Child(Username).Child("Username").Child(Username).GetValueAsync().ContinueWith(task =>
{
if (task.IsCompleted)
{
DataSnapshot snapshot = task.Result;
//checks to see if we found another user with the same username
if (snapshot.GetValue(true) != null)
{
isExists = true;
}
}
});
return isExists;
}
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");
}
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.
Can somebody tell if there is a way to get all users async in ASP.NET Identity 2?
In the UserManager.Users there is nothing async or find all async or somwething like that
There is no way to do this asynchronously with the UserManager class directly. You can either wrap it in your own asynchronous method: (this might be a bit evil)
public async Task<IQueryable<User>> GetUsersAsync
{
return await Task.Run(() =>
{
return userManager.Users();
}
}
Or use the ToListAsync extension method:
public async Task<List<User>> GetUsersAsync()
{
using (var context = new YourContext())
{
return await UserManager.Users.ToListAsync();
}
}
Or use your context directly:
public async Task<List<User>> GetUsersAsync()
{
using (var context = new YourContext())
{
return await context.Users.ToListAsync();
}
}