Asynchronous action for strongly-typed partial view in _Layout - asp.net

So, here's the rundown...
I've got a master layout page for my MVC 4 app that has some dynamic information and needs to be strongly typed to a specific domain entity to get that information. To keep my files cleaner, I've extracted out the typed fields to a partial view.
To grab the entity I need and map it to the partial's view-model, I have a LayoutController with an action that returns a Task<PartialViewResult>. This action uses a service layer to make an async call out to a Web API project, awaiting the entity. It massages that entity into the view-model and then returns PartialView("_LayoutPartial", viewModel).
From within the _Layout page, the partial is called via:
#{Html.RenderAction("LayoutInfo", "Layout", new { /*entity primary key*/ });}
I've stepped through the code and it does indeed get the correct entity back, but then after returning the partial view task, I get everybody's favorite Server Error page with the following error:
HttpServerUtility.Execute blocked while waiting for an asynchronous operation to complete.
I've done some Googling and SO searching and have no idea what this actually means. Am I thinking through this correctly?

That error message means that you're trying to invoke (and wait on!) an asynchronous method from within a synchronous method. In your specific case, the synchronous method is HtmlHelper.RenderAction, and the asynchronous method is your Task-returning action method. The reason the error occurs is that the point of writing an asynchronous Task-returning method is presumably to avoid blocking a thread, but RenderAction can't return until the Task is complete, so RenderAction ends up blocking while waiting for the operation to finish.
One option is to make the method that RenderAction calls synchronous instead of asynchronous, keeping in mind that this will continue to block the original thread. Another option is to populate the layout data asynchronously from within the original action method, then to pass that via ViewData to the layout page.

Related

Why is OutputCache a result filter and not an action filter in ASP.NET MVC?

The OutputCache attribute is commonly given as an example of a result filter in ASP.NET MVC. This MSDN page is one place. As such it wraps execution of the ActionResult object. But isn't that object executed at the end of the action method? I'm confused as to how it allows a cached response to be used and prevents the action itself from executing if it only wraps execution of the ActionResult at the end of that method. I know that caching works, so there is clearly some obvious piece that I'm missing.
The OutputCacheAttribute inherits from ActionFilterAttribute, which in turn implements IActionFilter, and IResultFilter. Thus the OutputCacheAttribute is both an action filter and a result filter.
When you think about it, this makes perfect sense. The logic behind a cache goes like this:
On execution
Is the item in the cache?
If Yes : return from cache (done)
If No, continue
Get result
On exiting
put in cache
return result
So part 1 is handled by the implementation of IActionFilter, if that doesn't immediately return a result, we continue with the action and the implementation of IResultFilter handles adding that result to the cache for future calls.
Thanks to ASP.NET being open source, this can be confirmed in code. Check out OutputCacheAttribute.cs on codeplex.
Line 222 is where the cahce is checked during OnActionExecuting (part of IActionFilter)
Line 237 - 249 the OnActionExecuting method sets up a callback that gets invoked during OnResultExecuted (part of IResultFilter)

ASP.NET MVC rendering common data such as notifications

In my requirement, all views should be able to display notifications based on what happened within Actions in the controllers. The implementation as it stands is in a BaseModel which is inherited by all Models needing to show notifications. Then, any view with this requirement simply calls:
#{ Html.RenderPartial("MessageCtrl", Model); }
And a notification is rendered. This works fine in cases where an Action is returning a view directly, and is usually handled like this in an Action:
model.SetMessage(response);
return View(model);
...where SetMessage updates the notification related properties of the model from an object returned from my service. All responses implemented an interface I created called IResponse, so messaging can be handled throughout.
The problem arrises when I need to return a View from a different Action and still show a notification.
For example, on my EditUser action, if edit was successful, I want to show the Index view. To achieve this from the EditUser action, I need to return RedirectToAction (because simply returning the view will return the correct view with the incorrect URL indicating it is EditUser when it is not). However, RedirectToAction loses all notion of my model and BaseModel, so by the time it redirects, it has lost my notification. I know I can use RouteValues, but that defeats the purpose of having a common base model driven notification approach. I even looked at the ViewBag (usually I dismiss it as the ugly part of MVC), but found that ViewBags only persist for the life time of a single request, and using RedirectToAction, the ViewBag is empty again by the time it hits the target Action. Another thought was to store it in a session object, but that sounds downright ugly to me.
This seems like its a pretty standard requirement. Is there a standardised approach to passing common data (like notifications) around to different views asside from through the querystring through a RedirectToAction?
I think you are looking for TempData which only persists data in session across one redirect.

Why is IHttpAsyncHandler being called over IHttpHandler?

I made a custom handler that derives from MvcHandler. I have my routes using a custom RouteHandler that returns my new handler for GetHttpHandler(), and I override ProcessRequest() in my custom handler. The call to GetHttpHandler is triggering a breakpoint and my handler's constructor is definitely being called, but BeginProcessRequest() is being called on the base MvcHandler instead of ProcessRequest().
Why are the async methods being called when I haven't done anything to call them? I don't want asynchronous handling, and I certainly didn't do anything explicit to get it. My controllers all derive from Controller, not AsyncController.
I don't have the source code with me right now, but I can add it later if needed. I was hoping someone might know some of the reasons why BeginProcessRequest might be called when it's not wanted.
Brad Wilson responded to my post on the Asp.net forums with the following answer http://forums.asp.net/t/1547898.aspx:
Short answer: yes.
With the addition of AsyncController,
the MvcHandler class needs to be an
IHttpAsyncHandler now, which means
that as far as the ASP.NET core
runtime is concerned, the entry points
are now BeginProcessRequest and
EndProcessRequest, not ProcessRequest.
It sounds like ProcessRequest is not even called anymore, but I could be mistaken. I can say that I haven't seen it in my testing.

Asp.net: Can a delegate ("Action") be serialized into control state?

I am implementing a user control that has a method that takes an Action delegate as a parm.
Attempting to store the delegate in Control State yields a serialization error. Is it even possible to serialize a delegate into Control State?
BP
Not easily - and it could open the door for potential problems.
It is theoretically possible to use reflection to determine which method of an object the delegate is invoking, and write a custom serialization process for it. Upon deserialization you would once again need to write logic to convert the information into a delegate reference.
The problem is that in the general case, discovering the object at runtime that you need to re-generate the delegate for is not always possible. If the delegate refers to a lambda or anonymous method that complicates things even more because their may be closures involved.
You are probably better off either:
Not preserving the Action delegate between requests and having the ASP.NET code re-attach the delegate on postback. This is the least risky option IMHO.
Storing the delegate reference in session state and reattach it to the deserialized object on postback. This option is risky for two reasons:
a) holding on to object references indefinitely in memory if the end user never posts back, or you forget to clear the object from server state.
b) if the delegate references page elements (controls, etc) you may run
into subtle bugs because the delegate will operate against the objects from the previous request, and not the new request.
In this post the author serializes an Action object to be executed later in time.
You can extend at your own action serializing to a string instead to a file.
Very interesting:
http://mikehadlow.blogspot.com/2011/04/serializing-continuations.html

ASP.NET control events exception handling

Suppose I have a button in an aspx page that performs a save of the form data to the database. In the associated event handler, before sending the updates, I read something from a webservice, operation that might result in an exception. In case of an error I want to have an adequate message displayed on the page, and all the data in the form preserved. How can I achieve this? Also, all my pages inherit from a basepage, so I would like, if possible to have all the error handling code in the base class. I do not want, if possible, to surround any web service call with try-catch blocks, I would in case of any unhandled exception to call some method automatically, something like Page_error, but still preserve the data in my forms.
You can easily put a method that manages the display message (maybe setting the text of some errorMessageLabel) in a superclass called from any derived class (if you wanna use inheritance to setup a template for your pages) if an exception is thrown (you can put the call to the superclas method in a catch block if there's actually an exception being thrown or you can manage this manually if the webservice is unavailable depending on your programming style).
As far as preserving the data presented, if viewstate is on and you are not populating your page dynamically then you're ok - if not, you need to explicitly save state information in viewState or session entries and retrieve them back if something goes wrong.
This bit really depends on how your page is actually implemented.

Resources