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();
}
}
Related
I have the following SignalR Hub with in-memory connection management.
[Authorize]
public class ChatHub : Hub
{
private static readonly ConnectionMapping<string> _connections =
new ConnectionMapping<string>();
private readonly IMessageRepository _messagesRepository;
public ChatHub(IMessageRepository messageRepository)
{
_messagesRepository = messagesRepository;
}
public override async Task OnConnectedAsync()
{
var name = Context.User.Identity.Name;
_connections.Add(name, Context.ConnectionId);
//await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception exception)
{
var name = Context.User.Identity.Name;
_connections.Remove(name, Context.ConnectionId);
//await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnDisconnectedAsync(exception);
}
public async void SendMessage(ChatMessage chatMessage)
{
var name = Context.User.Identity.Name;
var chatHistoryMessage = await _messagesRepository.SaveMessageAsync(chatMessage);
var availableConnections = _connections.GetConnections(name);
if (availableConnections.Any())
{
foreach (var connectionId in availableConnections)
{
Clients.Client(connectionId).SendAsync("ReceiveMessage", chatHistoryMessage);
}
}
else
{
}
}
}
However, when executing the code the following line
Clients.Client(connectionId).SendAsync("ReceiveMessage", 1);
raises an object disposed error on Clients.
This issue started happening when I added the repository line:
var chatHistoryMessage = await _messagesRepository.SaveMessageAsync(chatMessage);
SaveMessageAsync method:
public async Task<ChatHistory> SaveMessageAsync (ChatMessage chatMessage)
{
using (var conn = new SqlConnection(ConnProvider.ConnectionString))
{
await conn.OpenAsync();
return (await conn.QueryAsync<ChatHistory>("[mob].[spSaveChatMessage]",
new
{
..
},
commandType: CommandType.StoredProcedure)).FirstOrDefault();
}
}
Why would my Clients object be disposed? If I wait with the debugger that issue never happens.
It looks like the SendMessage method should be an async Task rather than an async void.
The issue could be caused by the way the SignalR framework runs async voids.
See this article for a good overview.
Async methods returning void don’t provide an easy way to notify the
calling code that they’ve completed.
Is it a good idea to make large classes fully Async compatible or should another method be used?
Example for understanding:
AsyncValidateUserInput.cs
public async Task<TaskStateHelper> CheckSiteIsReachable()
public async Task<TaskStateHelper> VerifyCertificate()
public async Task<TaskStateHelper> TestAccount()
{
#DoStuff
await exchangeAccount.FetchAccountInformation
#DoStuff
await exchangeAccount.GetAccountBalance
#DoStuff
}
GetAccountBalance is based on the AccountManager class:
AccountManager.cs
public async Task<decimal> GetAccountBalance()
{
#DoStuff
await FooAPI.GetAccountBalanceAsync()
}
FooAPI.cs
public async Task<Dictionary<string, decimal>> GetAccountBalanceAsync()
{
var queryResult = await QueryPrivateAsync("Balance");
#DoStuff
}
private async Task<Stream> QueryPrivateAsync(string method, Dictionary<string, string> param = null)
{
#DoStuff
await postStream.WriteAsync(postData);
#DoStuff
await ReadFromStreamAsync(webResponse.GetResponseStream());
#DoStuff
}
Another way would be to simply create a task.
result = await Task.Factory.StartNew(exchangeAccount.GetAccountBalance);
Do I use Async rule-compliant?
Thank you for your time
Yes, it is generally a good idea to make anything Async that should be, no matter the size. This article might help: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
I am trying to delete a row from my database based on a Primary Key ID field. When I try to do it, all of the code executes without any errors, but the item doesn't get deleted from the database.
I'm passing the item to my C# backend from an angular frontend call like this:
delete(customerId: number, materialCustomerId: number): Observable<Response> {
return this.http.delete(`${this.getBaseUrl()}/${customerId}/materialcustomer/${materialCustomerId}`).catch(error => this.handleError(error));
}
It then hits my controller method:
[HttpDelete]
[Route("{customerId}/materialcustomer/{materialCustomerId}")]
[AccessControl(Securable.Customer, Permissions.Delete, Permissions.Execute)]
public async Task Delete(int customerId, int materialCustomerId)
{
await _materialCustomerDeleter.DeleteAsync(MaterialCustomer.CreateWithOnlyId(materialCustomerId), HttpContext.RequestAborted);
}
Manipulator method:
public async Task DeleteAsync(MaterialCustomer model, CancellationToken cancellationToken = default(CancellationToken))
{
if (model == null)
throw new ArgumentNullException(nameof(model));
await _materialCustomerDeleter.DeleteAsync(new TblMaterialCustomer { MaterialCustomerId = model.MaterialCustomerId }, cancellationToken);
if (cancellationToken.IsCancellationRequested)
return;
await _customerWriter.CommitAsync(cancellationToken);
}
and finally, my repository method:
public async Task DeleteAsync(TblMaterialCustomer entity, CancellationToken cancellationToken = new CancellationToken())
{
var item =
await _context.TblMaterialCustomer.FirstOrDefaultAsync(i => i.MaterialCustomerId == entity.MaterialCustomerId, cancellationToken);
if (item == null || cancellationToken.IsCancellationRequested)
return;
_context.SetModified(item);
}
What am I missing?
Assuming that await _customerWriter.CommitAsync(cancellationToken); calls through to the same DbContext instance and calls method SaveAsync you should re-write the delete method like this:
public void Delete(TblMaterialCustomer entity)
{
_context.TblMaterialCustomer.Remove(entity);
}
Also it would probably be a good idea to return a result from the WebAPI call, although it is not required, like OK/200.
public async Task<IHttpActionResult> Delete(int customerId, int materialCustomerId)
{
await _materialCustomerDeleter.DeleteAsync(MaterialCustomer.CreateWithOnlyId(materialCustomerId), HttpContext.RequestAborted);
return Ok();
}
I have a old data access library that I need to use in my ASP.NET MVC application but I'm having trouble bringing it into the MVC world where many server-side operations are expected to be asynchronous. My data access library looks a like this:
public class MyOldDAL
{
public TaskResult CreateUser(string userName)
{
try
{
// Do user creation
return new TaskResult { Success = true, Message = "success" };
}
catch (Exception ex)
{
return new TaskResult { Success = false, Message = ex.Message };
}
}
}
And is called by my MVC application like this:
public class MyUserStore : IUserStore<ApplicationUser>
{
private readonly MyOldDAL _dal = new MyOldDAL();
public async Task CreateAsync(ApplicationUser user)
{
await Task.Run(() => _dal.CreateUser(user.UserName));
}
}
This is fine until the method in Task.Run() fails for some reason. I'd like to be able to return TaskStatus.Faulted if TaskResult.Success is false but I can't find an example online on how to do it properly - all my Google searches turn up is how to use Task<T> which the IUserStore interface doesn't permit.
For the record, much as I'd like to I can't change MyOldDAL - it's targeting .NET 3.5 so no async or await there!
The normal way to report errors from tasks is via exceptions, so you'll just need to do that transformation yourself:
public class MyUserStore : IUserStore<ApplicationUser>
{
private readonly MyOldDAL _dal = new MyOldDAL();
public Task CreateAsync(ApplicationUser user)
{
var result = _dal.CreateUser(user.UserName);
if (result.Success)
return Task.CompletedTask;
return Task.FromException(new InvalidOperationException(result.Message));
}
}
Note that Task.Run should not be used on ASP.NET.
Note: As Stephen Cleary noticed in his answer, Task.Run should not be used on ASP.NET.
Original answer (before comments):
Your CreateAsync method should normally be like this:
public async Task<TaskResult> CreateAsync(ApplicationUser user)
{
return await Task.Run(() => _dal.CreateUser(user.UserName));
}
But if you can't return Task<TaskResult> from CreateAsync method... well, than you can't obtain TaskResult from CreateAsync by definition. In that case you can store result locally:
private TaskResult taskResult;
public async Task CreateAsync(ApplicationUser user)
{
var result = await Task.Run(() => _dal.CreateUser(user.UserName));
this.taskResult = result;
// process taskResult wherether you need
}
Or raise event with TaskResult payload, allowing client of MyUserStore to subscribe to this event:
public event EventHandler<TaskResult> TaskCompleted;
public async Task CreateAsync(ApplicationUser user)
{
var result = await Task.Run(() => _dal.CreateUser(user.UserName));
this.OnTaskCompleted(result);
}
private void OnTaskCompleted(TaskResult result)
{
this.TaskCompleted?.Invoke(this, result);
}
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.