I am trying to implement Google SSO in my C# web application. It seemed to be pretty straightforward. Based on this tutorial, Google does its magic in the web browser to get an Id_Token JWT. I pass the token is passed it to my web service for validation and use it to match it to a user in the application.
Although I am not sure if my approach with the server-side Google API is correct yet, my big hangup is trying to figure out how to work with the async call in the Google API to see what I get back.
My code is pretty simple using the Google.Apis.Auth namespace:
public async Task<GoogleJsonWebSignature.Payload> wfValidateAsync(string pId_Token)
{
GoogleJsonWebSignature.Payload Sig = await GoogleJsonWebSignature.ValidateAsync(pId_Token, null, false);
return Sig;
}
Although brand new to this async/await paradigm, I do have some experience in AngularJS / NodeJS promises / callbacks. My challenge is that it seems async methods can only be called by other async methods all the way back up the call-stack. I think it means ending the service call before the async response finishes and the service can act on the result.
Also, for creating unit tests, putting async into the [TestMethod] method makes it completely disappear from the test explorer. I'm not sure how to test/debug this conundrum.
Thanks in advance to anyone who can help me screw my head back on straight with this.
Although brand new to this async/await paradigm, I do have some experience in AngularJS / NodeJS promises / callbacks.
But not use Typescript, right?
My challenge is that it seems async methods can only be called by other async methods all the way back up the call-stack.
They should. Bad things can happen if you don't.
I think it means ending the service call before the async response finishes and the service can act on the result.
No! The compiler generates a state machine for methods with the async modifier and the await keyword means "go do something else and I'll come back here when I'm done".
Also, for creating unit tests, putting async into the [TestMethod] method makes it completely disappear from the test explorer. I'm not sure how to test/debug this conundrum.
You're probably making your test methods async void. They should be async Task in order for the test engine to know when the test is done.
Have a look at Stephen Cleary's blog. He has lots of content on async-await.
Paulo, Thank you!!
I was able to get this working with your advice on the last part about the test method. I had to change this:
//THIS TEST METHOD DOESN'T SHOW IN THE TEST EXPLORER
[TestMethod]
public async void AuthenticateGoogle()
{
string lToken = "[JWT TOKEN HERE]";
wfUser lUser = new wfUser(_wfContext);
var lAuthenticateResult = await lUser.wfAuthenticateGoogle(lToken);
Assert.IsTrue(lAuthenticateResult, "JWT Token Validated");
}
To this:
//THIS TEST METHOD SHOWS IN THE TEST EXPLORER
[TestMethod]
public async Task AuthenticateGoogle()
{
string lToken = "[JWT TOKEN HERE]";
wfUser lUser = new wfUser(_wfContext);
var lAuthenticateResult = await lUser.wfAuthenticateGoogle(lToken);
Assert.IsTrue(lAuthenticateResult, "JWT Token Validated");
}
NOW -- as an additional gotcha that was hanging me up, this will also cause a unit test to disappear from the test explorer, which I found out through lazy copy/pasting a non-test method's definition and mindlessly just adding a return when the build output told me I needed to return a value.
//THIS TEST METHOD DOESN'T SHOW IN THE TEST EXPLORER DUE TO RETURN VALUE
[TestMethod]
public async Task<bool> AuthenticateGoogle()
{
string lToken = "[JWT TOKEN HERE]";
wfUser lUser = new wfUser(_wfContext);
var lAuthenticateResult = await lUser.wfAuthenticateGoogle(lToken);
Assert.IsTrue(lAuthenticateResult, "JWT Token Validated");
return true;
}
In addition to the excellent blog you shared, this article from MSDN Magazine entitled Async Programming : Unit Testing Asynchronous Code helped me get my brain around it too.
What was hanging me up with all of this was mixing synchronous and async methods which, to your point, was not working well. The code seemed to skip the debug points I had set after the await calls as if it never ran them or, if it did run them, ran them somewhere I could not see and couldn't log to the debugger.
It was one of those terrible moments late on a Friday night where a developer starts to question both competence and sanity! :)
Thanks again for the help!
p.s. I incorrectly typed Angular JS in my question and meant Angular 4...and I am using TypeScript there. Some day I'll stop incorrectly referring the newer versions of Angular as AngularJS.
My challenge is that it seems async methods can only be called by other async methods all the way back up the call-stack.
It's not entirely true. You can use async method in sync methods. Of course you are losing most of the 'async' effect, but sometimes you have to. As async methods returs tasks you have some options.
When Task is returning result, any reference to t.Result will block execution till it's known. Another option is to use Task.Wait(preferably with timeout). For example code to validate google jwt token:
public bool ValidateGoogleToken(string token)
{
try
{
if(GoogleJsonWebSignature.ValidateAsync(token).Wait(1000))
return true; //success
//timeout exceeded
}
catch (Exception e)
{
//tampered token
}
return false;
}
Related
I have a step class that has steps required to call async API and assert against it. Currently it looks like that:
[Given(#"a setting from API is correct")]
public async void GetSetting()
{
var setting = (await GetSettingsFromApi).Setting;
Assert.IsTrue(setting);
}
There are couple problems here:
I need this step to be performed at the correct time - after the previous and before the following, unsurprisingly. They can be sync or async, but they don't await each other. Making sure it's executed exactly first would also do. Is there a way to achieve it? Beside hardcoding all steps to explicitly await each other?
Assert failure exception is suppressed - it is shown in the in the debugger, but scenario is not stopped and failed as it should? Can I make it pass through and fail the test when the await result is received? This one is actually more important - if test is failed correctly on assert it's doesn't matter if that happens a bit later than expected.
I've recently run into a use case where the "Async" suffix recommended by the .NET Task-based Asynchronous Pattern (TAP) conflicts with what's already in existence.
I'm dealing with System.Management.Automation.Runspaces.Runspace during the course of attempting PowerShell remoting to execute cmdlets as part of my app.
Ignoring the questions that arise around whether it's best practice to knock-up a remoting session each time you want to run a cmdlet (for an enterprise scale application this might be a lot) or to create a connection and attempt to maintain it during the app's lifetime (with reconnection logic)...
My application is based on TAP which proliferates from the WebApi2 controller all the way down to the backend, what I'm trying to do is asynchronously open a Runspace connection - but noticed that there's already an OpenAsync method which isn't awaitable and returns void - which is like some weird mash-up between async void (for event handlers), void (non-async) and the Async suffix.
I'm using Stephen Cleary's Nito.AsyncEx nuget package to provide me with a AsyncAutoResetEvent which I can asynchronously await before attempting connection/reconnection).
The question is: should I care about the fact that my code really isn't going to be properly "async" in using either Open or OpenAsync on the Runspace?
If I should care - what's the best practice in this situation? It doesn't look like Microsoft have released updated DLLs which provide awaitable Open methods for the Runspace. Strangely despite MS giving information on how to use these libraries, they've added the caveat on the nuget site:
Versions 6.1.7601.* are unofficial packages for .Net 4.0 and are not
supported by Microsoft.
There also seems to be this DLL-esque package on nuget from Microsoft, aagggghh!
Currently my plan is something akin to this:
public async Task<Result> StartAsync()
{
if (!IsConnected)
{
try
{
await _asyncRunspaceLock.WaitAsync();
if (!IsConnected)
{
var protocol = IsHttpsEnabled ? "https" : "http";
var serverUrl = $"{protocol}://{Fqdn}/OcsPowershell";
var uri = new Uri(serverUrl);
var connectionInfo = new WSManConnectionInfo(uri, ShelUri, PSCredential.Empty)
{
SkipRevocationCheck = true,
};
var runspace = runspaceFactory.CreateRunspace(connectionInfo);
runspace.OpenAsync();
}
}
catch (Exception ex)
{
// TODO: Handle logging the 3rd party exception at the lowest level.
return Result.Fail(ex.Message);
}
finally
{
_asyncRunspaceLock.Set();
}
}
return Result.Ok();
}
It's a work in progress, I guess the same issue crops up around the RunspaceFactory's CreateRunspace static method which isn't async (at least it isn't named with the Async suffix).
Any helpful advice or experience would be greatly appreciated.
Thanks
peteski
From the documentation:
If you're adding a TAP method to a class that already contains that method name with the Async suffix, use the suffix TaskAsync instead. For example, if the class already has a GetAsync method, use the name GetTaskAsync.
I am trying to load a document out of RavenDb via a WebAPI call. When I open an async IDocumentSession and call LoadAsync, I get no exception or result, and the thread exits instantly with no error code.
I was able to bypass all the structure of my API and reproduce the error.
Here is the code that will not work:
public IHttpActionResult GetMyObject(long id)
{
try
{
var session = RavenDbStoreHolderSingleton.Store.OpenAsyncSession();
var myObject= session.LoadAsync<MyObject>("MyObject/1").Result;
return Ok(myObject);
}
catch (Exception e)
{
return InternalServerError(e);
}
}
I simply hard coded the object's Id to 1 for testing, but calling the function for an object that doesn't exist (such as "MyObject/1") has the same result.
However, this code works:
public async Task<IHttpActionResult> GetMyObject(long id)
{
try
{
var session = RavenDbStoreHolderSingleton.Store.OpenAsyncSession();
var myObject= await session.LoadAsync<MyObject>("MyObject/1");
return Ok(myObject);
}
catch (Exception e)
{
return InternalServerError(e);
}
}
Things I tried/fiddled with:
Changing the exceptions that are caught in debugging
Carefully monitoring Raven Studio to see if I could find any problems (I didn't, but I'm not sure I was looking in the right places)
Running the API without the debugger attached to see if the error occurred or if something showed up in Raven Studio (no changes)
So I guess I have stumbled on a "fix", but can someone explain why one of these would fail in such an odd way while the other one would work perfectly fine?
In the real application, the API call did not have the async/await pair, but the code that was making the call was actually using async/await.
Here is the repository class that was failing which caused me to look into this issue:
public async Task<MyObject> Load(string id)
{
return await _session.LoadAsync<MyObject>(id);
}
The first part that is failing is as per design, for ASP.Net async call, you are blocking the Synchronization context, when you call the Result on a Task returned and same Synchronization context is required for call to return the data. Check out the following link by Stephen Cleary, where the same mechanism is explained in detail.
Second part works since that is correct way of using it and it's not getting into the deadlock anymore. First part can only work if you are using the Console application, which doesn't have a synchronization context to block, even other UI like winforms will have a similar issue and need to use the use the Second part of the code
I have a REST API with an Basic Filter. The Filter checks against the DB (mongodb) before the actual request is made, wether the user is authorized. however this only works for the first time, afterwards it always gets stuck at
var filter = Builders<User>.Filter.Eq("email", email);
return _collection.Find(filter).FirstOrDefaultAsync();
which basically looks up the user in the DB based on the Email. The task doesn't finish and neither does it throw a timeout exception .
My question is somewhat related to this : C# Mongo FirstOrDefaultAsync hangs
however their fix didn't do it for me. I can't just keep passing the async tasks up the call hierarchy because at some point the filter expects a sychronous action based on the results. and an await doesnt cut it either.
Any ideas? I can't be the 1st one building a REST API with Basic Auth and a MongoDB behind it...
Help would be appreciated:)
Update:
a call like this also results in problems:
//...
await fbUserRepo.UpdateAsync(user);
//the method
public async Task<Guid> UpdateAsync(TEntity entity) {
entity.lastUpdatedTimestamp = DateTime.Now;
var filter = Builders<TEntity>.Filter.Eq("_id", entity.Id);
await _collection.ReplaceOneAsync(filter, entity);
return entity.Id;
}
when this method is called, nothing happens, nothing is returned.. its just stuck later at a .Wait() ... I haven't changed anything on my configuration and it happens both locally as well as in the azure cloud. performing queries directly on the mongodb is no problem, there are also no currentOp() pending. Also no timeout is thrown. its just like my application decided not to do anything anymore. the thread just stays still
Update again
The odd part is: I can CRUD all sorts of stuff into the DB. Only when I come from my AuthenticationFilter is where I get this trouble. I crawled over a 100k documents from FB and dropped then into my DB, updated them, etc. But fetching and updating my User Documents through my BasicAuthFilter is giving me so much trouble. I just can't explain it... you might notice my frustration (2am now..)
.Result after the sync method will solve your problem.
like given below.
var filter = Builders<User>.Filter.Eq("email", email);
return _collection.Find(filter).FirstOrDefaultAsync().Result;
However make sure, the Method you're working on isn't marked "async" as an async method should not be blocking. More details here.
AFAIK, MongoDB only provides an asynchronous API, which IMO is a correct design decision.
I can't just keep passing the async tasks up the call hierarchy because at some point the filter expects a sychronous action based on the results.
If this is an ASP.NET WebAPI, you can make it async all the way, since WebAPI supports async filters just fine.
However, if your REST API is ASP.NET MVC, then you're in a hard place. The current version of MVC does not support async filters (or child actions). Note that ASP.NET vNext is merging WebAPI with MVC, and the new merged version does support async filters (and child actions). In the meantime, you'll have to do a hacky solution like replacing MyUserAuthenticationAsync().Wait() with Task.Run(() => MyUserAuthenticationAsync()).Wait(). (Note that MyUserAuthenticationAsync will run on a thread outside the HTTP request context).
Hacks like this should be minimized; they're only necessary in MVC filters and child actions. Regular controller actions should be made async and use await instead of Wait. And if this is WebAPI, then just use await in every scenario; don't use any hacks at all.
I am having trouble with a demo from msdn
The demo
On the method updateUserName:
public static async Task updateUserName(TextBlock userName, Boolean signIn)
{
try
{
// Open Live Connect SDK client.
LiveAuthClient LCAuth = new LiveAuthClient();
LiveLoginResult LCLoginResult = await LCAuth.InitializeAsync();
try
{
//this is never reached
LiveLoginResult loginResult = null;
if (signIn)
......
the code hangs at ht InitialuzeAsync() method and never enters the try statement. Can someone who has used the live SDK please tell me what migh be wrong? The code is a direct copy-paste from the demo and the live SDK was installed via NuGet on VS2012.
I predict that you are calling Task.Wait or Task<T>.Result somewhere further up your call stack. As I describe on my blog, you are causing a deadlock because the await is attempting to resume on the UI thread.
The correct solution is to use await "all the way", which is one of the best practices I describe in my article. If you have a situation where you think you "can't" use await, then take a look at my async/OOP blog series, which describes various code patterns for async code, most notably constructors and properties.
Seems you have to associate your app with the store to use this feature, or else it hangs. After associating it, everything started working.