0

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..)

Community
  • 1
  • 1
pascalwhoop
  • 2,984
  • 3
  • 26
  • 40
  • 1
    do you have .result after this "FirstOrDefaultAsync()" method did you try that. something like this _collection.Find(filter).FirstOrDefaultAsync().Result; – Prashant Jul 07 '15 at 20:58
  • create an answer, you got a right one ;) idk i've tried so many things... but what's the point of having an async library like mongodb if I have to perform a blocking operation on the first call to it. I passed many mongo calls up the chain with awaits and async methods no problem. E.g. I have several GET REST Endpoints that all filter on my MongoDB and there its fully async async async.. odd – pascalwhoop Jul 07 '15 at 21:16

2 Answers2

1

.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.

Community
  • 1
  • 1
Prashant
  • 460
  • 3
  • 12
  • Hey. Could you also reference this : http://stackoverflow.com/a/21793240/1170940 and note, that a method should not be marked "async" in combination with the ".Result" technique? Otherwise we'd be back to deadlock situations or other trouble. UPDATE: Nevermind I didnt know i could edit other ppls stuff – pascalwhoop Jul 07 '15 at 21:26
  • off course we cannot have a aync with .Result if you try it will give a compilation error, aync can be used when you are returning a task. – Prashant Jul 07 '15 at 21:28
  • true, I still had my Task as return type since my method was asynchronous before. – pascalwhoop Jul 07 '15 at 21:37
  • sorry I have to remove the answer, since it's not really a solution. I though about it and still have problems all over the place. – pascalwhoop Jul 07 '15 at 23:41
1

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.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810