I'm attempting to create an initial 'Super User' in an ASP.NET 5 application. Using the latest template files with MVC 6 / EF7.
I can follow the examples set out here:
http://wildermuth.com/2015/3/17/A_Look_at_ASP_NET_5_Part_3_-_EF7
This works fine - until I try to execute an async method. For example:
await _userManager.CreateAsync(user, "P#55w0rd!");
or even:
await _context.SaveChangesAsync();
Synchronous methods work without a problem and this code executes outside of the Startup.cs Configure{...} as well.
I get the 'White Screen of Death' on application start. I would do it all without async but I don't think the UserManager has a Create()in Identity 3.0.
Is this me not understanding asynchronous programming or should it be possible?
EDIT: Added the entire call:
Define a Seeder class and a method to create the user:
public class Seeder
{
private ApplicationDbContext _context;
private UserManager<ApplicationUser> _userManager;
public Seeder(
ApplicationDbContext context,
UserManager<ApplicationUser> userManager)
{
_context = context;
_userManager = userManager;
}
public async Task Seed()
{
await CreateUsersAsync();
}
public async Task CreateUsersAsync()
{
var user = await _userManager.FindByEmailAsync("superuser#superuser.com");
if (user == null)
{
var company = _context.Company.First(x => x.Name == "Acme Ltd");
user = new ApplicationUser
{
UserName = "superuser#superuser.com",
Email = "superuser#superuser.com",
CreatedDate = DateTime.Now,
IsActive = true,
CompanyID = company.CompanyId
};
await _userManager.CreateAsync(user, "P#55w0rd!!");
}
}
}
Configure the service:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<Seeder>();
...
}
Call it:
public async void Configure(Seeder seeder)
{
...
await seeder.Seed();
...
}
Funny thing is; it does actually create the User - it just doesn't continue. So the second time it executes user != null and it executes fine.
I think the problem is because a deadlock is formed by the signature
public async void Configure(Seeder seeder).
Since it returns void, the awaited Task is never returned to the caller which creates a dead lock. Can you make it:
public async Task Configure(Seeder seeder).
I haven't gotten to work with MVC 6 yet, :( so I may be missing something. But that's why there is a deadlock.
Edit:
Since you can't change the signature of Configure, create a method called ConfigureAsync that returns type Task. Now await as per usual inside of it with your user manager code and call ConfigureAsync from Configure but wait on it.
ConfigureAsync.ConfigureAwait(false).Wait()
ConfigureAwait (false) is used to prevent potential dead locks of waiting on the async method to complete.
Full example:
public void Configure(Seeder seeder)
{
//Edited due to typo/bad syntax.
ConfigureAsync(seeder).Wait();
}
public async Task ConfigureAsync(Seeder seeder)
{
//Now treat this like true async/await.
await seeder.Seed().ConfigureAwait(false);
}
If you run into deadlocks here, perhaps your seeder should just be synchronous? I would avoid using Task.Run() in an ASP.NET context because that will totally defeat the purpose of async/await in the first place by taking up two request threads that would have just been done on one if done synchronously.
Sometimes, you need to implement a sync interface but you only have async APIs available. There is no perfect solution.
Fortunately, this code is only called once so performance concerns don't matter. You can just do the dirty sync over async bridge:
public void ConfigureServices(IServiceCollection services)
{
ConfigureServicesImpl(services).Wait(); //bridge
}
public async Task ConfigureServicesImpl(IServiceCollection services)
{
await ...;
}
You might need to insert a deadlock protection such as ConfigureAwait(false) or Task.Run(() => ...).Wait().
Related
This question already has answers here:
Enforce an async method to be called once
(4 answers)
Closed 6 months ago.
I'm writing an ASP.net Core 6 application (but the question is more about C# in general) where I have a controller action like this:
[HttpGet]
public async Task<IActionResult> MyAction() {
var result = await myService.LongOperationAsync();
return Ok(result);
}
Basically, the action calls a service that needs to do some complex operation and can take a bit of time to respond, up to a minute. Obviously, if in the meantime another request arrives a second run of LongOperationAsync() starts, consuming even more resources.
What I would like to do is redesign this so that the calls to LongOperationAsync() don't run in parallel, but instead wait for the result of the first call and then all return the same result, so that LongOperationAsync() only runs once.
I thought of a few ways to implement this (for example by using a scheduler like Quartz to run the call and then check if a relevant Job is already running before enqueueing another one) but they all require quite a bit of relatively complicated plumbing.
So I guess my questions are:
Is there an established design pattern / best practice to implement this scenario? Is it even practical / a good idea?
Are there features in the C# language and/or the ASP.net Core framework that facilitate implementing something like this?
Clarification: basically I want to run the long-running operation only once, and "recycle" the result to any other call that was waiting without executing the long-running operation again.
You could use an async version of Lazy<T> to do this.
Stephen Toub has posted a sample implementation of LazyAsync<T> here, which I reproduce below:
public class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<T> valueFactory) :
base(() => Task.Run(valueFactory))
{ }
public AsyncLazy(Func<Task<T>> taskFactory) :
base(() => Task.Run(taskFactory))
{ }
public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
}
You could use it like this:
public class Program
{
public static async Task Main()
{
var test = new Test();
var task1 = Task.Run(async () => await test.AsyncString());
var task2 = Task.Run(async () => await test.AsyncString());
var task3 = Task.Run(async () => await test.AsyncString());
var results = await Task.WhenAll(task1, task2, task3);
Console.WriteLine(string.Join(", ", results));
}
}
public sealed class Test
{
public async Task<string> AsyncString()
{
Console.WriteLine("Started awaiting lazy string.");
var result = await _lazyString;
Console.WriteLine("Finished awaiting lazy string.");
return result;
}
static async Task<string> longRunningOperation()
{
Console.WriteLine("longRunningOperation() started.");
await Task.Delay(4000);
Console.WriteLine("longRunningOperation() finished.");
return "finished";
}
readonly AsyncLazy<string> _lazyString = new (longRunningOperation);
}
If you run this console app, you'll see that longRunningOperation() is only called once, and when it's finished all the tasks waiting on it will complete.
Try it on DotNetFiddle
As Matthew's answer points out, what you're looking for is an "async lazy". There is no built-in type for this, but it's not that hard to create.
What you should be aware of, though, is that there are a few design tradeoffs in an async lazy type:
What context the factory function is run on (the first invoker's context or no context at all). In ASP.NET Core, there isn't a context. So the Task.Factory.StartNew in Stephen Toub's example code is unnecessary overhead.
Whether failures should be cached. In the simple AsyncLazy<T> approach, if the factory function fails, then a faulted task is cached indefinitely.
When to reset. Again, by default the simple AsyncLazy<T> code never resets; a successful response is also cached indefinitely.
I'm assuming you do want the code to run multiple times; you just want it not to run multiple times concurrently. In that case, you want the async lazy to be reset immediately upon completion, whether successful or failed.
The resetting can be tricky. You want to reset only when it's completed, and only once (i.e., you don't want your reset code to clear the next operation). My go-to for this kind of logic is a unique identifier; I like to use new object() for this.
So, I would start with the Lazy<Task<T>> idea, but wrap it instead of derive, which allows you to do a reset, as such:
public class AsyncLazy<T>
{
private readonly Func<Task<T>> _factory;
private readonly object _mutex = new();
private Lazy<Task<T>> _lazy;
private object _id;
public AsyncLazy(Func<Task<T>> factory)
{
_factory = factory;
_lazy = new(_factory);
_id = new();
}
private (object LocalId, Task<T> Task) Start()
{
lock (_mutex)
{
return (_id, _lazy.Value);
}
}
private void Reset(object localId)
{
lock (_mutex)
{
if (localId != _id)
return;
_lazy = new(_factory);
_id = new();
}
}
public async Task<T> InvokeAsync()
{
var (localId, task) = Start();
try
{
return await task;
}
finally
{
Reset(localId);
}
}
}
Is this a proper way of using async/await with EF for an API? If not, can you please show me some options? The code is compiling and shows no errors. The application is working fine, but I want to make sure that it runs asynchronous.
public class AdminController : ControllerBase
{
[HttpGet("Users")]
public async Task<IResult> Users()
{
return await Admin.GetUsers();
}
}
public static class Admin
{
internal static async Task<IResult> GetUsers()
{
using var context = new DataBaseContext();
List<User>? _users = context.users.ToList();
return (_users.Count == 0) ?
Results.NotFound() :
Results.Ok(_users);
}
}
Or should I use this instead?
public class AdminController : ControllerBase
{
[HttpGet("Users")]
public Task<IResult> Users()
{
return Admin.GetUsers();
}
}
public static class Admin
{
internal static async Task<IResult> GetUsers()
{
using var context = new DataBaseContext();
List<User>? _users = await context.users.ToListAsync();
return (_users.Count == 0) ?
Results.NotFound() :
Results.Ok(_users);
}
}
The second one is what you want to use. Your first option lacks an async signature meaning you cannot await your static async method. To understand why you must understand what async and await does at runtime. So you have a bunch of threads running in a thread pool and when you have a request come in, a thread gets used to run your code and if its lacking async and await it would run in a synchronous fashion. This means that the thread will be out of that pool until the end of processing. If that admin function took 10 seconds to process, that thread will be locked to that request for 10 seconds. In that same example if you mark it as async and await, your thread goes back into the pool while you await and a callback gets used to say "Hey I'm done" and completes the execution from that await. It becomes more important as your application gets more requests. Hope I explained it well enough
I'm trying to write a custom policy for an ASP.NET Core 3.1 web application, using a custom Identity storage provider.
I've tried to wrap my head around the fact that policies in ASP.NET Core are designed to take user informations from an HttpContext object, when I read this in a MSDN Article:
once you hold a reference to the user, you can always find the username from the claims and run a query against any database or external service
I started writing my own policy (as of now a simple role requirement) injecting the UserManager into the constructor:
public class RoleHandler : AuthorizationHandler<RoleRequirement>
{
private UserManager<AppUser> UserManager;
public RoleHandler(UserManager<AppUser> usermanager)
{
UserManager = usermanager;
}
}
Now I have a couple problems:
INJECTING A SCOPED SERVICE IN A SINGLETON
Policies are supposed to be lasting for the entire application life, so that would be a Singleton:
services.AddSingleton<IAuthorizationHandler, RoleHandler>();
but the UserManager injected in the policy server is a scoped service and that is not allowed. Solution was very easy, changing the configuration of the policy service from a singleton to a scoped service
services.AddScoped<IAuthorizationHandler, RoleHandler>();
but I don't know whether that cause any issue or not.
WRITING AN ASYNCHRONOUS POLICY HANDLER
This is my implementation of the HandleRequirementAsync method:
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
{
AppUser user = UserManager.FindByIdAsync(context.User.Identity.Name).Result;
if (user != null)
{
bool result = UserManager.IsInRoleAsync(user, requirement.Role.ToString()).Result;
if (result) context.Succeed(requirement);
}
return Task.CompletedTask;
}
I used Task.Result but it blocks the thread. I can't use await because that would make the method returning a Task<Task> instead of a Task and I can't change it. How can I solve this?
Don't return Task.CompletedTask.
When you declare a method as async, it implicitly returns a Task when the first await is hit:
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
{
AppUser user = await UserManager.FindByIdAsync(context.User.Identity.Name);
if (user != null)
{
bool result = await UserManager.IsInRoleAsync(user, requirement.Role.ToString());
if (result) context.Succeed(requirement);
}
}
Task.CompletedTask is generally used when you need to implement a Task returning method synchronously, which you are not.
My HandleRequirementAsync also calls httpClient.GetAsync (Blazor server, .NET 5), adding async to the HandleRequirementAsync and execute the await hpptClient.GetAsync() breaks the authorization. With async method with delays, Try typing the route address in the browser and it will redirect to not authorized page, even though the context.Succeed(requirement) is executed.
The working solution for me is to keep the HandleRequirementAsync as it is, returning Task.CompletedTask. For the async method we need to call, just use pattern for calling async method from non async method.
The one I use is from https://stackoverflow.com/a/43148321/423356
my sample async method:
public async Task<IList<Permission>> GetGroupPermissions(int userId)
{
HttpResponseMessage response = await _httpClient.GetAsync(string.Format("Auth/GroupPermissions/{0}", userId));
try
{
var payload = await response.Content.ReadFromJsonAsync<List<Permission>>();
response.EnsureSuccessStatusCode();
return payload;
}
catch
{
return new List<Permission>();
}
}
HandleRequirementAsync:
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
var t2 = (Task.Run(() => GetGroupPermissions(userId)));
t2.Wait();
var userGroupPermissions = t2.Result;
if (!userGroupPermissions.Contains(requirement.Permission))
{
//context.Fail(); //no need to fail, other requirement might success
return Task.CompletedTask;
}
context.Succeed(requirement);
return Task.CompletedTask;
}
I know that this problem is here a lot, but I have to say I read everything I could found for like two days and don't get my error.
I created a ASP.net Core REST API and get always different errors:
"Can not access a disposed object.."
"An exception occurred while iterating over the results of a query
for context type.."
"A second operation started on this context before a previous
operation completed"..
Maybe someone of you sees my error or can explain to me, what I'm doing wrong.
Rest-API:
// POST api/events
[HttpPost("create")]
public async Task<IActionResult> CreateAsync([FromBody] EventDTO eventDTO)
{
var newEvent = _mapper.Map<Event>(eventDTO);
try
{
await _eventService.CreateEventAsync(newEvent);
return Ok(newEvent);
}
catch (AppException ex)
{
return BadRequest(new { message = ex.Message });
}
}
Interface:
public interface IEventService
{
Task<IEnumerable<Event>> GetAllEventsAsync();
Task<Event> GetEventByIDAsync(int id);
Task<IEnumerable<Event>> GetEventByCityAsync(string city);
Task<Event> CreateEventAsync(Event newEvent);
void UpdateEventAsync(Event newEvent, Event existing, int eventId);
void DeleteEventAsync(Event existing);
}
Eventservice:
public class EventService : IEventService
{
private MeMeContext _dbContext;
public EventService(MeMeContext dbContext)
{
_dbContext = dbContext;
}
public async Task<Event> CreateEventAsync(Event newEvent)
{
_dbContext.Events.Add(newEvent);
await _dbContext.SaveChangesAsync();
return newEvent;
}
...
}
Startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddMvc().
SetCompatibilityVersion(CompatibilityVersion.Version_2_2).
AddJsonOptions(opts => opts.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
services.AddDbContext<MeMeContext>(opts => opts.UseNpgsql(Configuration.GetConnectionString(DATABASE)));
services.AddScoped<MeMeContext>();
// configure DI for application services
services.AddScoped<IUserService, UserService>();
services.AddScoped<IEventService, EventService>();
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new AutoMapperProfile());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
...
}
One thing that I don't understand also, is that I get different errors, when I start my application with Visual Studio or with "dotnet run". One thing that also happens from time to time is, that sometimes my code works, when I do other things on the REST API.
When you need more information, just ask. I'm happy with every hint that you can give me :)
Thanks in advance!
You're not awaiting an async method. As such, the code in the action moves on while that CreateEventAsync logic is running. When the response returns, the context goes away, since its lifetime is that scope.
In other words, you have essentially a race condition. If the CreateEventAsync logic happens to finish before the response returns, everything is fine. However, if it takes longer than returning the response, then the context is gone (along with your other scoped services), and you start throwing exceptions.
Long and short, use the await keyword:
await _eventService.CreateEventAsync(newEvent);
Async is not the same as running something in the background. If you want the action to be able to return before this logic completes, then you should schedule this to run on a background service instead. See: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.2&tabs=visual-studio
I have a method called myMethodAsync, which needs to be executed, make some stuff and then run DoSomeWork method - however it doesn't need to wait until the method is done.
It's an asp.net core 2.0 application using Entity Framework Core and the built-in dependency injection. Every class in the sample is Scoped. I'm using repository pattern. There is no error, just nothing is happening If I set breakpoint after myRepository.GetAsync or in the GetAsync method the debugger doesn't get in.
The code:
public async Task myMethodAsync
{
...
await myRepository.AddAsync(entity);
DoSomeWork(id); // If it's lack of await the line below will not works
}
private async Task DoSomeWork(Guid id)
{
...
var someEntity = await myRepository.GetAsync(id); // This line will never be done
}
I thought that it's because the myRepository is shared somehow, so I extracted the DoSomeWork to other class with own myRepository, but the effect is the same.
Also If I use Task.Run nothing changes.
How do I know that the code is never executed? Beacuse I'm changing the entity and updating it to database later. However the entity is not changed.
Also really intersting is that this following code almost works:
public async Task myMethodAsync
{
...
await myRepository.AddAsync(entity);
DoSomeWork(id); // Now it almost works
await myRepository.GetAsync(randomID);
}
private async Task DoSomeWork(Guid id)
{
...
var someEntity = await myRepository.GetAsync(id); // It works now
...
await myRepository.UpdateAsync(entity); // But it doesn't work
}
I've found a solution. The problem was with EF - my DbContext was disposed(it didn't throw an exception cause of multi-threading I think). I needed to implement ICloneable interface to DbContext and myRepository. Now I'm passing cloned version of myRepository and everything works fine.
public async Task myMethodAsync
{
...
await myRepository.AddAsync(entity);
DoSomeWork(id, (Repository)myRepository.Clone());
}
private async Task DoSomeWork(Guid id, Repository clonedRepository)
{
...
var someEntity = await clonedRepository.GetAsync(id);
}