ASP.NET MVC 2 RC Caching Problem - asp.net-mvc

Since upgrading from mvc 2 beta 2 to rc I'm having trouble with an ajax submission in Internet Explorer. Upon carrying out a jquery form post, the function returns a url to a controller action. This worked fine with the controller action picking up it was a ajaxrequest and then piping back a partial view to update the page. This still works fine in Firefox, however in Internet Explorer the final call to the controller action now comes from cache and returns therefore returns a full view rather than partial.
I've tried setting the outputcache to 0 with no success and I've also tried the nocache actionfilter as described here Disable browser cache for entire ASP.NET website with no luck. The only way I can stop IE from pulling from cache is to physically delete the cached version.
Anyone have any ideas (apologies if this isn't very clear, tricky one to explain!)?

For some reason, IE is really aggressive about caching AJAX GETs. So if you are fetching that via AJAX, the behavior is not surprising to me. Also not surprising is that using output cache attribute didn't fix the problem, because it is IE, rather than the server, which is doing the caching. What you need to do is to tell IE not to cache the request, by setting the appropriate headers in the HTTP. Here is how we do it:
[CacheControl(HttpCacheability.NoCache), HttpGet]
public JsonResult DoStuff()
{
//...
}
public class CacheControlAttribute : ActionFilterAttribute
{
public CacheControlAttribute(HttpCacheability cacheability)
{
this._cacheability = cacheability;
}
private HttpCacheability _cacheability;
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
cache.SetCacheability(_cacheability);
}
}

My 2 cents to Craig's great solution -
If you're using a user control and rendering it using an "RenderAction"
<% Html.RenderAction("UserList", "User"); %>
And this page invokes it via GET as well as POST then don't mention the request method in the attribute declaration.
[CacheControl(HttpCacheability.NoCache)]
For example, I've a search Grid and a search panel on top of it. I've made my Grid a user-control so that I can invoke the sort & paging via AJAX (GET) still it is also invoked when I press the "search" button (POST) so I need it for both.

Related

Glimpse Tab is not updating

I am implementing some custom Glimpse Tabs to show advanced statistics from our framework. So far that works great. The problem I could not fix so far is, that the tab content does not get updated after AJAX calls. In the debugger I see that GetData() gets called and returns the up to date stats but the Glimpse UI is still showing the old tab content.
Here is the simplest of my pages returning a plain object with a few prop in it (database command counter, etc. - nothing fancy).
public class GlimpseTabOverview : TabBase
{
public override string Name
{
get { return "Overview"; }
}
public override object GetData(ITabContext context)
{
if (context == null) { throw new ArgumentNullException("context"); }
return WebStatisticsHelper.GetBasicStatsData();
}
}
Refreshing the whole page does show the new values but not when doing Ajax. I took a look (or two) at the Glimpse source but could not yet find what could cause that.
We use ASP.Net MVC 5.1 with IIS-Express and the latest Glimpse and Glimpse.AspMvc5.
Does anybody have an idea why the Glimpse UI does not take the new data?
Are you selecting the Ajax request that occurred from the Ajax tab? The Glimpse context doesn't just change when an Ajax call occurs. Since these calls could happen very quickly or when you are trying to read the data of the origin request, we leave it up to you to decide when you view the ajax requests Glimpse data. To do this, simply go to the Ajax tab and when the request appears, select that request and view the relevant tab. Let em know if that fixes the issue you are having.

MVC OutputCache for Child Actions: where is it stored?

I'm using OutputCache for caching an horizontal menu and a vertical menu in my app. I usually use something like this in the actions I want to be cached
[OutputCache(Duration=3600, VaryByParam="none", Location=OutputCacheLocation.Client, NoStore=true)]
public ActionResult ActionName()
{
.......
}
But if it is a child actions i must use
[ChildActionOnly]
[OutputCache(Duration = 180, VaryByParam = "none")]
public ActionResult Menu()
{
......
}
When you use OutputCache with child actions you can´t specify properties like Location or NoStore. So the question is, if i can´t specify the cache location (client, server, any) for a child action, where is it stored by default?? Thanks!!
(sorry for my english)
I'm just guessing here, but it would probably get stored just on the server. The idea of a partial view (likely the result of a child action) being stored on the client doesn't make sense -- the client doesn't have any idea of the page's action break-down on the server.
The way I see it, unless the entire page is cached, the client must go to the server to get the page rendered, at which point, the server can returned the cache child action result.
When we use Output Cache for child action it is cached on Server not on client side.
Unfortunatly it is cached on client, Just set a breakpoint on your childAction Method, and run application from multiple browsers, for each browser ChildAction will called in cache duration.

Run MVC controller action without the view?

I have an ExcelResult action result that returns Microsoft Excel documents, based off the Stephen Walther tip. Basically it just writes a stream out to the Response. When debugging VS 2010 (ASP.NET Dev Server), it runs fine, but when I run it on an IIS 6 box, I get the following error:
The view 'GenerateExcel' or its master was not found. The following locations were searched:
~/Views/Home/GenerateExcel.aspx
~/Views/Home/GenerateExcel.ascx
~/Views/Shared/GenerateExcel.aspx
~/Views/Shared/GenerateExcel.ascx
There is no associated View, and therefore no file, but there shouldn't have to be. What am I doing wrong?
UPDATE
By simply returning void instead of an ActionResult, I no longer have this issue. Instead of returning the ExcelResult, I'm explicitly calling it's ExecuteResult method, which is writing to the output stream.
Before
public ActionResult GenerateExcel()
{
return this.Excel(parameters);
}
After
public void GenerateExcel()
{
ExcelResult excelResult = this.Excel(parameters);
excelResult.ExecuteResult(null);
}
After that, I had security issues with my NTLM authentication, but they 'went away' (meaning I expect them to come back). For now, though, everything is working properly.
Make sure your action method does not return a ActionResult:
public void DoSomething()
I didn't look at the code for the action result in much detail, but there must be something wrong with your action result. Did you inherit from some other action result as opposed to the ActionResult class? Did you call base.ExecuteResult? If so, that would explain why it is looking for the view. I have created several custom controller actions to return various file types and they never look for a view.
I agree with the comments on the answer saying to return void. That definitely is a hack. You should not call ExecuteResult from inside your action. You are basically writing directly to the response stream from your controller action. Obviously it works but it really doesn't fit the MVC model.

How to call a function *only once* in ASP.NET MVC page cycle

I have an ASP.NET MVC web app and have a function that I need to call when the page loads only once. Right now I have the function being called from a base controller OnActionExecuted.
The issue I'm having is that this function is called multiple times - once for the page, and then multiple times for different ajax calls that I have on the page. I've tried putting the function on Controller Initialize but this is also called for each ajax call to a controller action. So is there some function in the ASP.NET MVC page cycle that only gets called when a page is requested (GET) and not for all of the ajax calls (POST)? The only thing I can think of is putting all of the ajax calls in separate controllers that don't inherit from the base controller but there must be a nicer solution.
Depending on how you're doing your AjaxRequests you could use something like the following:
public ActionResult Index()
{
if (!Request.IsAjaxRequest())
{
LoadConfiguration();
}
// Rest of Action method (snip)...
}
This works if, for instance, you're performing Ajax with the jQuery JavaScript library which sends a special token to the server to indicate that it's an Ajax call (I'm sure other libraries do this). This might be better just in case someone changes the JavaScript code to perform GET Ajax requests.
One thing you mentioned does intrigue me though "The issue I'm having is that this function is called multiple times" - actually 'technically' this is not true. It IS only getting called once....per request, all those Ajax calls are treated as separate requests by the server, as if the user is requesting a page via the web browser. It sounds like what you really need is a way to differentiate between web page HTTP Requests, and Ajax HTTP Requests, hence the above solution.
It came to me right after posting the question...
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
if (Request.HttpMethod == "GET")
{
LoadConfiguration();
}
}
You can either do this work in the application scope (on start, in global.asax or other similar approaches), or store a configuration object in the session (or a flag to identify it has already been done, if there is nothing to store).

MVC Controller Called twice

I have a Product controller with Index action, which basically creates the view form for post and Index (Post action verb) action on the ProductController which basically save the product to db but when validation errors occur, I am returning a View(mymodel) else when saved, I am returning RedirectToAction("Created,"Product") but for some odd reason when I break into the code , it is hitting the Product Controller action twice rather than just once. Hence the product has 2 records instead of one.
public ActionResult Index()
{
return View()
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection fc)
{
// 2 calls are made to this controller
try
{
// save the product
return RedirectToAction("Created");
}
catch(Exception ex)
{
// recreate the model from form collection
return View(viewData); // when a validation error occurs it comes into the catch block
}
}
Sometimes I have found Firebug to cause this behavior. Try disabling its Script panel, if you have it installed.
Explanation: In some cases Firebug isn't able to get the script sources for the display within its Script panel. In these cases it initiates a second request to get them. See issue 7401 for some discussion about this, which alleviates the problem and is fixed with Firebug 2.0.2.
Here's a basic checklist (copied from here):
Check that you don’t have any image or another elements in the View with an
empty src attribute (<img src=”" /> for example) or have src
attribute referencing something that no longer exists. You better
check directly in the browser's “Page Source”, than in the View itself due to the
possibility of some “dynamic” issues when the View is rendered. Once you
find such empty element in the page's HTML source its usually trivial to
find the same element in your View and fix the issue. This can also happen with <link href="">.
Check that you don’t have any AJAX calls referencing an empty URL (browsers will interpret such empty URL as the current page and will request the current page again making the Controller action execute few times).
You forgot to return “false” from the JavaScript click event handler for a link or button that makes an AJAX call. If you forget to “return false”, the browser simply interprets the default action of the link – regular, non AJAX, calling the same page again)
Sometimes Firebug and YSlow [ Firefox (FF) plugins ] can cause such issues. Just temporarily disable them in FF or test with a different browser.
Watch out for duplicate filters decorating your controller or action. (this was my problem)
Another solution for this case..
I had exactly same problem, running and testing from Chrome. I couldn't debug it because the second call was coming from (external call). I have randomly tested it in Firefox and Internet Explorer where there was no double hit.
Whatever nasty thing it was, I have deleted Chrome cache (everything!!!) and problem has been resolved.
Hope it will help some of you :)
I had a similar issue with a controller action that generated an image, and I was only seeing it with Firefox. There is a really old bug that causes this, that I guess is still there.
https://bugzilla.mozilla.org/show_bug.cgi?id=304574

Resources