I am working on a DelegatingHandler to intercept all the calls from one service to another. And I am totally new to DelegatingHandlers.
This is the issue.
We currently have an API that takes calls and measure the concurrent calls and it has some mechanisms to throttle it if needed. it is in this form. (Since actual API is heavy for debugging I am actually using following stub methods to test this)
private Task<HttpResponseMessage> ExecuteAsync1(Func<Task<HttpResponseMessage>> action)
{
return ExecuteAsync2(action);
}
private async Task<HttpResponseMessage> ExecuteAsync2(Func<Task<HttpResponseMessage>> action)
{
return await action().ConfigureAwait(false);
}
Now within this Delegating handler I have to use this API like this.
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (this.ThrottlingFactory == null || !this.ThrottlingEnabled)
{
return await base.SendAsync(request, cancellationToken);
}
else
{
var response = await this.ExecuteAsync1(() =>
{
return base.SendAsync(request, cancellationToken);
});
// Analyse response for certain thing here.
return response;
}
}
My problem is, after executing ExecuteAsync1 (it actually completes the ExecuteAsync2) the code never return back. I tried numerous variation of this like adding async/await to all the methods in the chain including the anon method etc. non worked. So can somebody please point me to things I am doing wrong here?
This is what I had to do. I had to ConfigureAwait(false) to the call.
var response = await this.ExecuteAsync1(() =>
{
return base.SendAsync(request, cancellationToken);
}).ConfigureAwait(false);
Related
I have the following Hub class in SignalR part and here I defined all of the methods related to connection:
public override Task OnConnected()
{
// here I cannot call this, and need to convert this method async
await AddToGroup("stockGroup");
//
string name = Context.User.Identity.Name;
_connections.Add(name, Context.ConnectionId);
return base.OnConnected();
}
public async Task AddToGroup(string groupName)
{
await Groups.Add(Context.ConnectionId, groupName);
await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} joined");
}
I have a look at many different examples regarding to these connection methods (and other Hub methods) and see that some of them use async method while some of them not. In this example above, I need to convert OnConnected() method to async in order to call AddToGroup() method. Of course the reverse situation would also be ok, but I am not sure which one is better. So, should I use async methods or non-async methods for all of the methods in the Hub? Any help would be appreciated.
Update 1 : Converted method (to async).
public override async Task OnConnected()
{
await AddToGroup("stockGroup");
string name = Context.User.Identity.Name;
_connections.Add(name, Context.ConnectionId);
return base.OnConnected();
}
Update 2:
public override async Task OnConnected()
{
// #1 There is no async method in "Microsoft.AspNet.SignalR" library.
//await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
// #2 I just have sync version of "AddToGroupAsync()" and used it
await Groups.Add(Context.ConnectionId, "SignalR Users");
/* #3 I think there is no need to use this custom method in the Hub.
Because the same method is already exist in the IGroupManager interface */
//await AddToGroup("jiraGroup");
string name = Context.User.Identity.Name;
_connections.Add(name, Context.ConnectionId);
// #4 Here also the same problem and I used sync version of OnConnected()
//await base.OnConnectedAsync();
await base.OnConnected();
}
Just add async if you need await inside method. async is a marker for compiler to generate async state machine.
should I use async- use if you need to await.
If you don't need to await just return task itself without async. In that case you can avoid creation of state machine.
Also please read Async/Await FAQ from Stephen Toub:
When you mark a method with the “async” keyword, you’re really telling
the compiler two things:
You’re telling the compiler that you want to be able to use the
“await” keyword inside the method (you can use the await keyword if
and only if the method or lambda it’s in is marked as async). In doing
so, you’re telling the compiler to compile the method using a state
machine, such that the method will be able to suspend and then resume
asynchronously at await points.
You’re telling the compiler to “lift”
the result of the method or any exceptions that may occur into the
return type. For a method that returns Task or Task, this
means that any returned value or exception that goes unhandled within
the method is stored into the result task. For a method that returns
void, this means that any exceptions are propagated to the caller’s
context via whatever “SynchronizationContext” was current at the time
of the method’s initial invocation.
You should use Async methods with await and return Task.
Asynchrony is viral so you should avoid async void.
Bad:
public async void MethodAsync()
{
var result = await SendAsync();
DoSomething(result);
}
Good:
public async Task MethodAsync()
{
var result = await SendAsync();
DoSomething(result);
}
There are some awesome async guidelines by #davidfowl here.
Update: remove the return:
public override async Task OnConnected()
{
await AddToGroup("stockGroup");
string name = Context.User.Identity.Name;
_connections.Add(name, Context.ConnectionId);
await base.OnConnected();
}
This question already has an answer here:
eliding async and await in async methods [duplicate]
(1 answer)
Closed 4 years ago.
When passing through method calls to another async method, should the caller method also be async and use await, or should I simply pass through the Task it receives from the callee? What if the calling method performs a bit more preparation?
public Task<Message> Unsubscribe(int subscriptionId, CancellationToken cancellationToken)
{
var data = new MessageData
{
["subscriptionId"] = subscriptionId
};
return SendAsync(OpCode.Unsubscribe, data, cancellationToken);
}
public Task<Message> Unsubscribe(int subscriptionId) =>
Unsubscribe(subscriptionId, CancellationToken.None);
SendAsync is async and returns Task<Message>. So should the first overload of Unsubscribe be like above or like that:
public async Task<Message> Unsubscribe(int subscriptionId, CancellationToken cancellationToken)
{
var data = new MessageData
{
["subscriptionId"] = subscriptionId
};
return await SendAsync(OpCode.Unsubscribe, data, cancellationToken);
}
The other alternative is with the second overload of Unsubscribe. It might be like above or like that:
public async Task<Message> Unsubscribe(int subscriptionId) =>
await Unsubscribe(subscriptionId, CancellationToken.None);
I guess that more asyncs and awaits add complexity introduced by the compiler (I see it in the stack traces!) and may degrade performance and memory consumption. But at least it should provide for a consistent exception propagation.
In the examples you cited, just returning the task without awaiting it is fine (and arguably preferable), but this does require some care.
Once case were you can get into trouble is when you're dealing with Tasks inside a using block. These can have vastly different behaviors:
public async Task<Something> AwaitTheTask()
{
using (var someResource = GetAResource())
{
return await SomeAsyncThing(someResource);
}
}
public Task<Something> DontAwaitTheTask()
{
using (var someResource = GetAResource())
{
return SomeAsyncThing(someResource);
}
}
In the first example, the using block will not dispose someResource until the awaited Task has completed. In the second example, someResource will be disposed right away, very likely causing problems for the code that needs that resource.
I seem to be getting a TaskCanceledException whenever I return another Task synchronously instead of awaiting it, following the guidelines in When at last you await.
TaskCanceledException code
public static class Download
{
public static Task<byte[]> FromYouTubeAsync(string videoUri)
{
using (var client = new HttpClient())
{
return FromYouTubeAsync(
() => client
.GetStringAsync(videoUri),
uri => client
.GetByteArrayAsync(uri));
}
}
public async static Task<byte[]> FromYouTubeAsync(
Func<Task<string>> sourceFactory, Func<string, Task<byte[]>> downloadFactory)
{
string source = await // TaskCanceledException here
sourceFactory()
.ConfigureAwait(false);
// find links
return await
downloadFactory(links.First())
.ConfigureAwait(false);
}
}
Exception-free code
Here, the first overload of the method's signature is changed to async, and it awaits the second overload. For some reason, this prevents the TaskCanceledException.
public static class Download
{
public async static Task<byte[]> FromYouTubeAsync(string videoUri)
{
using (var client = new HttpClient())
{
return await FromYouTubeAsync(
() => client
.GetStringAsync(videoUri),
uri => client
.GetByteArrayAsync(uri));
}
}
public async static Task<byte[]> FromYouTubeAsync(
Func<Task<string>> sourceFactory, Func<string, Task<byte[]>> downloadFactory)
{
string source = await // No exception!
sourceFactory()
.ConfigureAwait(false);
// find links
return await
downloadFactory(links.First())
.ConfigureAwait(false);
}
}
Why does this happen and what can I do to fix it (besides awaiting the method, which wastes resources as described in the link above)?
Sorry, the link you posted is about applying an optimization which is only applicable if the method does nothing after its await. To quote the post:
In this case, however, we’re being handed a task to represent the last statement in the method, and thus it’s in effect already a representation of the entire method’s processing...
In your example, the task does not represent the last statement in the method. Look again:
public async static Task<byte[]> FromYouTubeAsync(string videoUri)
{
using (var client = new HttpClient())
{
return await FromYouTubeAsync(...);
}
}
There's something happening after the await: specifically, the disposing of client. So the optimization mentioned in that blog post does not apply here.
This is why you're seeing an exception if you try to return the task directly:
public static Task<byte[]> FromYouTubeAsync(string videoUri)
{
using (var client = new HttpClient())
{
return FromYouTubeAsync(...);
}
}
This code is starting the download, then disposing the HttpClient, and then returning the task. HttpClient will cancel any outstanding operations when it is disposed.
The code using await will (asynchronously) wait for the HTTP operation to complete before it disposes the HttpClient. That is the behavior you need, and await is the cleanest way to express it. In this case, it's not a "waste of resources" at all, because you have to defer disposing until after the download completes.
In an ASP.NET Web API project, I have an action filter which checks for model state errors and returns the Bad Request status code if there are any. It looks like this:
public class ValidationFilter : IActionFilter
{
public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext context,
CancellationToken cancellationToken,
Func<Task<HttpResponseMessage>> continuation)
{
if(!actionContext.ModelState.IsValid)
{
return new Task<HttpResponseMessage>(() =>
actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest,
actionContext.ModelState);
}
return continuation();
}
}
Now, for some reason, any request with a model state error never returns. It just hangs there. If I debug, I get to the next filter in the pipeline, which starts with
var result = await continuation();
If I "Step Over" that line, the debugger sort of drops out to "waiting" mode, but no more code seems to be run.
I assume all of this is because I've somehow misunderstood how all these things interact, but despite hours of googling and reading, I still can't figure out how to make this work properly. Any help - both for understanding and bugfixing - is deeply appreciated.
You never start your task. You need to call Start when you use the Task constructor. Instead of calling the constructor and then Start a better option would be to use Task.Run:
if(!actionContext.ModelState.IsValid)
{
return Task.Run(() =>
actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest,
actionContext.ModelState);
}
In your case there's nothing really asynchronous about your operation, so you can simply use Task.FromResult to create a task with the result you get synchronously:
public Task<HttpResponseMessage> ExecuteActionFilterAsync(
HttpActionContext context,
CancellationToken cancellationToken,
Func<Task<HttpResponseMessage>> continuation)
{
if(!actionContext.ModelState.IsValid)
{
return Task.FromResult(actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest,
actionContext.ModelState);
}
return continuation();
}
I am trying to unit test an implementation of DelegateHandler. My simplified implementation:
public class FooHandler
: DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
Thread.CurrentPrincipal = new GenericPrincipal(
new GenericIdentity("Vegard"), new[] { "A", "B" });
return await base.SendAsync(request, cancellationToken);
}
}
When I try to unit test this, I do it like this:
public class TestHandler : DelegatingHandler
{
private readonly Func<HttpRequestMessage,
CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
public TestHandler()
{
_handlerFunc = (r, c) => Return(HttpStatusCode.OK);
}
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
return _handlerFunc(request, cancellationToken);
}
public static Task<HttpResponseMessage> Return(HttpStatusCode status)
{
return Task.Factory.StartNew(
() => new HttpResponseMessage(status));
}
}
[TestMethod]
public async Task SendAsync_CorrectTokens_IsAuthorized()
{
var message = new HttpRequestMessage(HttpMethod.Get, "http://www.test.com");
var handler = new AuthorizationHeaderHandler
{
InnerHandler = new TestHandler()
};
var invoker = new HttpMessageInvoker(handler);
var result = await invoker.SendAsync(message, new CancellationToken());
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
Assert.IsTrue(Thread.CurrentPrincipal.Identity.IsAuthenticated); // fails
Assert.AreEqual("Vegard", Thread.CurrentPrincipal.Identity.Name); // fails
}
My guess is that this happens because HttpMessageInvoker runs the DelegateHandler on a separate thread. Can I force these to be on the same thread?
Can I force these to be on the same thread?
You can't.
A better question is "how do I flow Thread.CurrentPrincipal to whatever thread is executing the request"? There is an answer to this question.
Thread.CurrentPrincipal is odd in ASP.NET. In fact, I recommend you don't use it at all; use HttpContext.User instead. But if you want, you can get it to work by understanding these points:
HttpContext.User is flowed by the ASP.NET SynchronizationContext.
Thread.CurrentPrincipal is overwritten by HttpContext.User whenever a thread enters an ASP.NET request SynchronizationContext.
Unfortunately, your current test is flawed in a couple of key points:
After a request is completed, the value of Thread.CurrentPrincipal is undefined.
The current way you're running your tests, there is no HttpContext (or ASP.NET SynchronizationContext), and this interferes with the flowing of the principal user.
To fully test authorization, you'd need an integration test.
Also see my answer to this question.
What you're actually running into is the behavior of await. Await will reset the principal to whatever it was when you entered the await when you exit the await. So since there is no current principal when you call await invoker.SendAsync, there will be no current principal after you await that call.
However, your test handler should see the right principal. What you could do is have your test handler store the current principal in its SendAsync implementation, expose it as a public property, and then have your test assert that the test handler saw the principal it was supposed to. That should work fine, and that should be the behavior you care about.