I am trying to use ActionFilters to capture the result in my api call and change it if needed.
But it appears to change only the object i pass not the result type. (from OK to BadRequest)
return Ok(await _Data.Remove());
The above code in my controller leads to my filter:
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var resultContext = await next();
Guid userId = await _data.GetId();
BaseModel baseModel = (BaseModel)((ObjectResult)resultContext.Result).Value;
if (baseModel.ApiResponse == ApiResponse.AllGood)
{
BaseModel m = _data.GetBaseModel(userId);
m.ApiResponse = baseModel.ApiResponse;
resultContext.Result = new OkObjectResult(m);
}
else if (baseModel.ApiResponse == ApiResponse.NotFound)
resultContext.Result = new NotFoundObjectResult(baseModel);
else
resultContext.Result = new BadRequestObjectResult(baseModel);
}
The model is correctly captured and i can check against its contents. And i can change it and pass it back. But it always goes back to the controller and then returns the "ok" with the new model.
What i want is it returning BadRequest
I have tried putting doing this:
resultContext.Result = new BadRequestObjectResult(baseModel);
As you can see from the above code, but it does not work.
The reason you cannot get it to work, is because this approach isn't possible (in the general case, at least).
The async variant of the ActionFilter combines both the pre and post variants of the synchronous variant, in one callback, by giving you next().
Once you have called and successfully returned from next(), you are in 'executed' land, not 'executing' land anymore.
The trouble is, if next() has started sending the response to the client, it is too late to change the response. Your receiving client may already sit with 'http 200 ok' in his hand!
You can observe this, by trying to write to the response in context.HttpContext.Response (You can set the Http Status Code on it, and use WriteAsync on it),
in the spot where you attempt to modify Result.
If next had already started the response, you'll get a direct exception telling you this.
However, IF next() hadn't begun the response, you may actually be able to control the response.
A last-resort option you have, is to throw at this point, it will (mostly) break your http response into http-500 server error. This may or may not be good for your client.
Lastly, your resultContext actually has a 'Cancelled' attribute which you can flag.
However I don't know if that has any effect if the response has already begun (it might affect the middleware server side).
In my own case for this, I concluded it was the wrong place to solve our issue, so I moved our necessary handling to a wrapper in the controller method return statement.
I.e. you then get
return wrapper(OK(response));
where wrapper will decide whether to pass on OK(..) unharmed.
If you use this approach, be careful if you had
return OK(responseWIthSideEffect(..));
in that case, you must make sure the side effect code is forced to execute,
before your wrapper makes its decision (i.e. assuming the wrapper checks something that might depend on that side effect).
Related
I am implementing facial recognition functionality. I can upload a person and an image but when I try to send image for comparison the DetectAsync method fails with no error message. I am not sure if the problem lies in the method (I have successfully implemented it in other projects) or in the way I am sending the webcam/image through javascript or something else.
I am using javascript to detect a face on webcam and take a picture. The picture is sent to converted to a stream and send to DetectAsync(stream). It's in a try-catch block but I don't get an exception, it just returns to the UI where it seems frozen and I can't reload the page or navigate to another page. In the Quickwatch window, it I type faceServiceClient.DetectAsync(stream) and then force execution I get the following:
Exception: null
Id: 643
Status: WaitingForActivation
results: null (not yet computed)
a few others but these seemed like the most relevent
I expect to get either an array of FaceIDs (GUIDS). One per face in the image. Or an error message. After I get GUIDS I can try to find a match against faces in my personGroup. If I find a match I return the username to my UI. I have gotten this to work in an MVC app. This is an ASP.NET app.
code:
public async Task<string> DoFacialRecognition(string image)
{
string response = "";
FaceServiceClient faceServiceClient = new FaceServiceClient(subscriptionKey);
try
{
var imageToSend = ConvertBase64ToImage(image.Substring(22));
Stream stream = ConvertToStream(imageToSend, ImageFormat.Png);
var faces = await faceServiceClient.DetectAsync(stream, true, false);
var faceIds = faces.Select(face => face.FaceId).ToArray();
}
....
}
The issue was with the thread or threads... Im not sure of the technicality or terms but I will explain as best I can. This was an aspx page making an ajax call to an async method. This was the behavior I was expecting:
aspx-> ajax-> async method A-> async method B-> back to A-> back to ajax-> ajax deals with response.
what was actually happening:
aspx-> ajax-> async method A-> async method B-> back to ajax or aspx.
But ajax is waiting for a response from method A so it is ignoring response from method B (probably not even in the right format anyway). The page is still 'active' but when user tries to do anything the server doesn't respond because method A is still waiting for a response from B and is locking the code.
If you know more about threads and async calls feel free to correct my understanding!
to resolve:
The info I needed to resolve was provided by Stephen Cleary in this post: How to call asynchronous method from synchronous method in C#?.
you need to 'hide' the async method from the ajax call. To do this Stephen has a nuget packages called Nito.AsyncEx.
the sequence then looks like:
aspx-> ajax-> method A-> async method B-> back to A-> back to ajax-> ajax deals with response.
Note that method A is no longer async.
and code looks like this:
using Nito.AsyncEx;
[WebMethod]
public static string CheckImage(string image)
{
var result = AsyncContext.Run(() => MyAsyncMethod(image));
return result;
}
private static async Task<string> MyAsyncMethod(string image)
{
//do async stuff
}
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 learning C# again after a whole lot of years. I did C# programming back in the 2.0 days. The language has indeed evolved, and its fantastic. That being said, I am making a W8/WP8 universal app. Basically when the app launches, the constructor runs a method. This method checks for a connection and if the connection is enabled, the program flows forward.
private async void UpdateInformationSection(IUICommand command) {
InformationModel GeneralInformationModel = new InformationModel
{
apistatus = await voip_service.isAPIEnabled(),
apimessage = await voip_service.GetAPIMessage(),
currentbalance = await voip_service.getBalance(),
currentip = await voip_service.getIP()
};
if (GeneralInformationModel.apistatus == false) {
var msgdialog = new MessageDialog(
"Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
"API connection could not be established");
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
msgdialog.Commands.Add(new UICommand(
"Try again", new UICommandInvokedHandler(this.UpdateInformationSection)));
// Show the message dialog
await msgdialog.ShowAsync();
}
// set the data context for the first section of the hub
// so we can use bindings.
mainpagehub.Sections[0].DataContext = GeneralInformationModel;
So if you notice, if the connection fails then we have a message dialog popped up. There is a "try again" button the popup. When users click this button, it has a "callback function" associated with it (new stuff to me, I guess its like an event handler?). Anyways, instead of coding a new method, I made the callback method the same as the current method the messagebox is executed in. So basically what I did was added an argument so I have this UpdateInformationSection(IUICommand command). And then the callback function is the same method.
What I am scared of: Everytime they click the "try again" button, will it destroy the old instance of it? In other words, when they click the "try again" button, does the method finish executing? Otherwise I am imagining a scenario where the method is called again and again and each method is stuck in limbo (if this makes any sense).
Also, in my constructor when the method is FIRST called ,I had to change it to
//Update HUB Sections.
// send null as argument since its not coming from a "command button"
// the argument is required when the API connection cant be established
// and thus a modal dialog comes up with a "try again" command button.
UpdateInformationSection(null);
Is it okay sending a "null" like that to the "command" argument? What is the right procedure here.
For sure, there's no true recursion here, because you are using async. But it is possible (probable, actually, but I haven't double-checked) that the MessageDialog does not complete the ShowAsync() method call until your own command delegate completes. This would result in the multiple instances of MessageDialog remaining reachable until you finally don't show it, preventing them from being garbage-collected (i.e. the closest you can get to a real memory leak with managed objects).
IMHO, the method would be better-implemented if you avoided this potential re-entrancy, by queuing the method for execution again instead of call it directly. That could look something like this:
private async void UpdateInformationSection(IUICommand command) {
InformationModel GeneralInformationModel = new InformationModel
{
apistatus = await voip_service.isAPIEnabled(),
apimessage = await voip_service.GetAPIMessage(),
currentbalance = await voip_service.getBalance(),
currentip = await voip_service.getIP()
};
if (GeneralInformationModel.apistatus == false) {
var msgdialog = new MessageDialog(
"Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
"API connection could not be established");
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
msgdialog.Commands.Add(new UICommand("Try again"));
// Show the message dialog
await msgdialog.ShowAsync();
var _ = CoreWindow.GetForCurrentThread().Dispatcher
.RunAsync(CoreDispatcherPriority.Normal,
() => { var ignoreTask = UpdateInformationSection(command); });
return;
}
// set the data context for the first section of the hub
// so we can use bindings.
mainpagehub.Sections[0].DataContext = GeneralInformationModel;
This way, each time the MessageDialog is displayed, it's given the opportunity to go ahead and close before you redisplay it.
The above assumes "Try again" really is the only option you present. Of course, if you have additional options, you can use the UICommand object to distinguish between the selected option and do the appropriate thing; "Try again" would do the above call to RunAsync() the method again, while other options would do whatever they do.
All that said, personally I think it would be better to avoid this pattern. Presumably, the user did something else that originally initiated this dialog. At the very least, there ought to also be a "Cancel" option as an alternative to "Try Again". And IMHO it would actually be better to just present this as an alert with the default "Close", so that the user simply is taken back to wherever they were, so that after they fix the configuration issue, they can just explicitly attempt the action/operation again.
I'm of course making some assumptions about the program here. Lacking specific details, I admit there could be some compelling reason to do it the way you are now instead. But at least be sure this is really the best way to do it. Sticking a user in a potentially endless loop seems a bit "off" to me. :)
EDIT:
To elaborate on this bit of code:
var _ = CoreWindow.GetForCurrentThread().Dispatcher
.RunAsync(CoreDispatcherPriority.Normal,
() => { var ignoreTask = UpdateInformationSection(command); });
The RunAsync() method causes the given delegate to be executed in the Dispatcher's thread, i.e. the UI thread for your program. This is where the method is already (presumably) running, since it's a command invoked by some UI object. Doing it this way allows the method to be re-invoked, but in a non-re-entrant way. I.e. the current method call is allowed to complete and return before the next one starts. This eliminates any recursive aspect.
The invoked delegate itself — () => { var ignoreTask = UpdateInformationSection(command); } — using the statement body lambda syntax, is simply the method call to invoke your command method again.
Finally, both the RunAsync() method and your command method are async methods, returning a Task instance. In this particular case, we don't need to wait for them to finish, so there's no await, but if we don't do something with the return value the compiler will generate a warning. For me, the easiest, cleanest way to suppress the warning is to go ahead and copy the Task reference to a local variable, which is enough to make the compiler happy. The RunAsync() method is copied to a variable named _, which is what I usually use for variables that I don't actually need to use, while the command method's return value is copied to a variable named ignoreTask, named that way to be explicit about the purpose of the variable (which is to ignore the Task returned from your command method).
I've got the following code block. I'm confused how the code can go past the
Response.Redirect("~..")
Indeed it does. I thought any lines past that would automatically not execute. Am I missing somethig basic here? I find the debugger actually executing the next lines.
public ActionResult Index()
{
Response.Redirect("~/Default.aspx", true);
string year =
Utils.ConvertCodeCampYearToActualYear(
Utils.GetCurrentCodeCampYear().ToString(CultureInfo.InvariantCulture));
var viewModel = GetViewModel(year);
return View(viewModel);
}
You need to return it. It's a function. In your case you can use Redirect:
return Redirect("~/Default.aspx");
All Response.Redirect() does (really) is set location= response header to the specified URI and sets the http status to 302 Found. It also writes a little stub HTML in the response with a link to the new URI as well, but that's a mere decoration.
Unless you use the overload that allows you to specify whether or not processing should be continued via a bool flag, processing continues. If that bool flag is true, response processing is terminated by aborting the thread processing the request, throwing a ThreadAbortException as a side effect.