I have a AuthorizationHandler depending on a Service offering async methods for .NET Core 3.1's Authorization Middleware. I have o call some of these async methods inside the HandleRequirementAsync method. The overall code looks like this:
{
public class MyAuthorizationHandler : AuthorizationHandler<MyRequirement, Tuple<string, string>>
{
private readonly IAuthIntelRepository authIntelRepository;
public UserAssistanceAuthorizationHandler(IAuthIntelRepository authIntelRepository)
{
this.authIntelRepository = authIntelRepository;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement, Tuple<string, string> someRessource)
{
//some async calls to authIntelRepository
if (/*someCondition*/false)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class MyRequirement : IAuthorizationRequirement { }
}
As soon is I use an await statement though, I get an error that the signature isn't explicitly set as async. Adding async to the inherited method's signature causes the following error.
a return keyword must not be followed by an object expression. Did you intend to return 'Task<T>'?
This thread elaborates a similar issue but the solution doesn't seem to work in .NET Core 3.1.
Using Result in the following manner works, but AFAIK this will result in a blocking call:
Task<Object> obj= this.authIntelRepository.getSomeAsync(...);
obj.Result.property //do Something to check the requirement
I'm not sure what the correct solution would look like here.
If the return type of your async method is Task, then, apart from the await keyword, your treat your method as if it was void returning:
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement, Tuple<string, string> someRessource)
{
await authIntelRepository....
if (/*someCondition*/false)
{
context.Succeed(requirement);
}
return;
}
Adding async to HandleRequirementAsync and use await to call the async method inside HandleRequirementAsync breaks the authorization, try calling external db or httpClient (delays), Type in the browser the route address with authorization. The route will be redirected to the non authorized page even though the context.Succeed(requirement) is executed .
The working solution for me (blazor server .NET 5) is keeping the HandleRequirementAsync as it is, execute the async method we need to call using pattern for executing async method inside non async method.
My sample working code derived 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;
}
Related
I'm trying to store token I get from external api on session.
code snippet concerning this;
[HttpPost]
public async void Post()
{
if (HttpContext.Session.GetValue<User>("Token") == null)
{
HttpContext.Session.SetValue("Token", "test");
var res = await _loginBusiness.GetToken();
HttpContext.Session.SetValue("Token", res);
}
}
HttpContext.Session.SetValue("Token", "test");
in this part, it doesn't occur any error but second the same code line give an error after GetToken().
related error
System.ObjectDisposedException: 'IFeatureCollection has been disposed.
Object name: 'Collection'.'
Also GetToken():
public async Task<User> GetToken()
{
String url = "login/login";
var client = httpClientFactory.CreateClient("VoiceScope");
var postRes = await client.PostAsync<User>(new UserLogin(), url);
return postRes;
}
The problem is that you are using async void. These promises can't be observed and their semantics end up a lot different from a normal Task. Your disposal is happening early because the infrastructure just assumes your Post method has completed (it has no way to tell otherwise).
Change the signature of Post to be:
public async Task Post()
Please note that async void should be limited to event handlers.
I am not sure about using HttpContext. You have IHttpContextAccessor in asp.net core.
I think for store token you can use this
public class UserContext
{
public UserContext(IHttpContextAccessor context)
{
Token = GetAccessToken(context);
}
private static string GetAccessToken(IHttpContextAccessor contextAccessor)
{
var identity = (ClaimsIdentity)contextAccessor?.HttpContext?.User?.Identity;
return identity?.Claims.FirstOrDefault(x => x.Type == "token")?.Value;
}
public string Token { get; }
}
And then, add this staff in your DI like scope object and use it in controllers via ServiceProvider.
I have implemented Mediatr in my .NET framework project and would like to use a IPipelineBehavior.
I have implemented and registered the container using the example from the project: https://github.com/jbogard/MediatR/blob/master/samples/MediatR.Examples.Unity/Program.cs
This is my Behavior
public class AuditPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILeaveAuditTrail _auditor;
public AuditPipelineBehavior(ILeaveAuditTrail auditor)
{
_auditor = auditor;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
if (AuditPrevented(request))
return await next();
var response = await next();
var auditLog = _auditor.CreateAuditLog(request, response);
//Dispatch audit
return response;
}
private static bool AuditPrevented<TInput>(TInput query)
{
return query.GetType().GetCustomAttributes(typeof(PreventAuditAttribute), true).Any();
}
}
And i register is like this together with my Mediatr
container.RegisterMediator(new HierarchicalLifetimeManager());
container.RegisterMediatorHandlers(applicationAssembly);
container.RegisterType(typeof(IPipelineBehavior<,>), typeof(AuditPipelineBehavior<,>));
container.RegisterType<ILeaveAuditTrail, DefaultAuditor>();
When i send the IRequest with Mediatr it is handled fine and i get the results but the AuditPipeline is not called.
If i remove the async keyword and just return next(); It works. But this way i cannot correctly intercept my response.
Also on the example Github the handle is implemented async: https://github.com/jbogard/MediatR/wiki/Behaviors
The issue was not related to the registration of Mediatror the PipelineBehavior.
When calling the mediator.Send()method it was not in an async method. .Resultwas used instead of await. Because of this the handling of the pipeline only worked when the asynckeyword was not present.
Make sure to never use the .Result to chain these async calls. Mark the controller method async and await the mediator.Send()
I've got a class library for talking to a logging api server, the method "chain" is this:
Entry point ->
private static bool SendChecksumToServer(Checksum checksum)
{
var res = _api.GetAsync($"Checksum?assemblyName={checksum.CurrentAssembly}&checkSum={checksum.LogFileChecksum}&fileName={checksum.FileName}");
return _api.Deserialize<bool>(res.Result.Content.ReadAsStringAsync().Result);
}
Which calls this:
public async Task<HttpResponseMessage> GetAsync(string apiCall)
{
ApiGet get = new ApiGet();
return await get.GetAsync(apiCall, client);
}
Which calls this:
public async Task<HttpResponseMessage> GetAsync(string apiCall, HttpClient client)
{
var response = await client.GetAsync(apiCall);
return response;
}
This works completely fine when I use the class library within a console app, but as soon as I move it to an actual application (MVC) it stops working, it doesn't even hit the controller action at all, I've tried everything I can think of like checking firewalls, making sure the async is correct (although I'm sure it still isn't because the api not responding freezes the app, but I can't bubble the async any higher)
Most likely experiencing a deadlock because of .Result blocking call.
Don’t mix blocking and async code
Reference Async/Await - Best Practices in Asynchronous Programming
Refactor the code to be async all the way
private static async Task<bool> SendChecksumToServer(Checksum checksum) {
var res = await _api.GetAsync($"Checksum?assemblyName={checksum.CurrentAssembly}&checkSum={checksum.LogFileChecksum}&fileName={checksum.FileName}");
String data = await res.Result.Content.ReadAsStringAsync();
return _api.Deserialize<bool>(data);
}
Ensure what ever is calling SendChecksumToServer also awaits the task,
and also not using async-await in the other calls if nothing needs to be awaited.
public Task<HttpResponseMessage> GetAsync(string apiCall) {
ApiGet get = new ApiGet();
return get.GetAsync(apiCall, client);
}
ApiGet
public Task<HttpResponseMessage> GetAsync(string apiCall, HttpClient client) {
return client.GetAsync(apiCall);
}
I am working on an ASP.NET Core 2.2 application with Dapper. Virtually all methods follows the async/await pattern returning some sort of Task as a result.
Due to an issue we had with Dapper (I haven't personally investigated it, this part of the code I use as it is) but basically it boils down to the fact that if you want to execute in Transaction multiple async methods, which internally are calling other async methods and you may have several levels of nesting this way, you need to wrap all those method invocations within a single method which would be executed in a transaction.
The method that handles this is as follows:
public async Task<TOut> ExecuteInTransactionAsync<TOut>(
Delegate function,
params object[] parameters)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var result = await ((Task<TOut>)function.DynamicInvoke(parameters))
.ConfigureAwait(false);
scope.Complete();
return result;
}
}
So I have a very complex Entity which is saved by calling Save to a lot of smaller entities. This part of the code is working OK and looks like this:
public async SaveEntireEntity(EntityDTO entityDTO)
{
return await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task<dynamic>>(async dto => await SaveInTransaction(dto)),
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age });
}
And the SaveInTransaction method looks like:
private async Task<dynamic> SaveInTransaction(dynamic dto)
{
var entityId = await nameService.Add(dto.Name);
await addressService.Add(dto.Address);
await ageService.Add(dto.Age);
return entityId;
}
so this is simplified, but indeed I am calling a multiple services here, which on their part are calling multiple repositories and this works fine.
The Problem I have is when it comes to updating the same entity within a transaction. The whole purpose of showing the Save logic was to point out that at the end because I have this return entityId; I am able to chain everything together without any problems. However, as it is right now, by default our Update methods are not returning anything and this is where I can't figure out how to implement the Update logic.
Currently I have this:
public async Task UpdateEntireEntity(UpdateEntityDTO, entityDTO)
{
await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task<dynamic>>(async dto => await UpdateInTransaction(dto)),
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age });
}
And UpdateInTransaction looks like this:
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return await Task.FromResult<dynamic>(null);
}
This seems to work at least based on the several tests I made, however I really don't like this part:
return await Task.FromResult<dynamic>(null);
To me it seems like an ugly hack. The Update methods were thought not to return any value and this is just too artificial.
And even the worst part is that I can not figure out how implement the update method without having to return something.
One thing I've tried is to change the declaration of UpdateInTransaction to
private async Task UpdateInTransaction(dynamic dto)
and when I call the method I change it to:
await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task>( async dto => await UpdateInTransaction(dto)..
But I got the following exception:
AsyncStateMachineBox1[System.Threading.Tasks.VoidTaskResult,
<fully-qualified- name>.<<UpdateEntireEntity>b__0>d] to type
'System.Threading.Tasks.Task1[System.Threading.Tasks.Task]'
.
So basically that's it. Sorry for the long post. I would really appreciate some well explained answer.
I would avoid the use of Delegate since it isn't typed:
public async Task<TOut> ExecuteInTransactionAsync<TOut>(Func<Task<TOut>> function)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var result = await (function()).ConfigureAwait(false);
scope.Complete();
return result;
}
}
This signature would mean you'd need to capture parameters rather than pass them:
public async Task<dynamic> SaveEntireEntity(EntityDTO entityDTO)
{
return await _transactionProvider.ExecuteInTransactionAsync(
async () => await SaveInTransaction(
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age }));
}
Once you're using the strongly-typed Func<Task<T>> instead of Delegate in your method signature, you can create an overload for ExecuteInTransactionAsync as such:
public async Task ExecuteInTransactionAsync(Func<Task> function)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
await (function()).ConfigureAwait(false);
scope.Complete();
}
}
which can be used as such:
public async Task UpdateEntireEntity(UpdateEntityDTO entityDTO)
{
await _transactionProvider.ExecuteInTransactionAsync(
async () => await UpdateInTransaction(
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age }));
}
private async Task UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
}
You can change
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return await Task.FromResult<dynamic>(null);
}
to
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return null;
}
Suppose I'm writing a custom MVC filter which does some asynchronous calls within the method overrides, like so:
public class MyActionFilter : System.Web.Mvc.ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext ctx)
{
var stuff = ConfigureAwaitHelper1().Result;
// do stuff
}
public override void OnActionExecuting(ActionExecutingContext ctx)
{
var stuff = ConfigureAwaitHelper2().Result;
// do stuff
}
private async Task<string> ConfigureAwaitHelper1()
{
var result = await client.GetAsStringAsync("blah.com").ConfigureAwait(false);
return result;
}
private async Task<string> ConfigureAwaitHelper2()
{
return await client.GetAsStringAsync("blah.com").ConfigureAwait(false);
}
}
Why does OnActionExecuting deadlock, whereas OnActionExecuted does not? I don't see the fundamental difference between the two. The act of returning happens only after the asynchronous task is complete, which is rather like putting the result into an "anonymous return" local var before returning it, so I don't see why the former should deadlock.
Why does OnActionExecuting deadlock, whereas OnActionExecuted does not?
I'm surprised it works at all. The reason you're experiencing the deadlock is due to the fact that you're invoking a .Result on a Task. This is evil and you should only ever invoke .Result and .Wait in console applications.