ASP.NET MVC hits outputcache for every action - asp.net-mvc

We are running quite a large site build with ASP.NET MVC 3 and AppFabric as a distributed caching solution. We have implemented a custom OutputCacheAdapter to use our AppFabric cluster.
We are seeing that ASP.NET calls the OutputCacheProvider.Get() method for every action, even if that action is NOT decorated with a #OutputCacheAttribute.
That isn't much of a problem if you use the default outputcacheprovider but it is when you are running an outputcacheprovider that resides on seperate machines.

It is by design that the the output cache is checked first for a cached copy of the page. If there is a cached copy, it's returned and nothing further is executed. In particular, no controller and no controller action is derived, inspected or executed. This happens only if the page is not cached.
You will need to change your cache provider so that it can quickly determine if a page can potentially be cached. Only if it is a cachable page, then it should go and check the distributed cache. This check cannot based on the OutputCacheAttribute as they are not available during this part of the request processing. Instead, the quick check must be made with the URL, the cookies and other HTML header information.

You can use Donut Cache outputcache attribute which lets you to define a prefix for output cache keys. So in your custom provider just get/set the cache if cache key starts with your own prefix.

Related

Asp.net MVC Pass onetime authentication to controller through Url.Action()

Background
I have an ASP.net MVC 4 web application with Forms authentication and a custom AuthorizeAttribute controlling access to all controllers minus the login screen. I am adding to some of the controllers, an action that allows the user to download a server generated PDF whose content and layout is being defined in a Razor View.
To carry out the conversion between Html and PDF, im using a trial version of ABCPdf9 and the bulk of the conversion works perfectly with all CSS, Text, static images, etc being displayed as required.
The problem is that I have images in the HTML that must also be rendered into the PDF file, but these images come from a controller which requires authentication.
Since the Html to PDF conversion takes place in ABCPdf using the Gecko engine, the existing user authentication cookies, etc are not available and as such the GET requests to the Image Controller are not authenticated and will not return anything. (This is the problem).
What I've discovered
From the research I have done, I came across the HttpAdditionalHeaders Property of ABCPdf which (from my understanding) is there to allow you to set header cookies, etc that will be sent with the requests made by the Gecko engine when fetching resources.
I have spent a good few hours trying to set the existing cookies from the originating request and pass them through to ABCPdf but this does not appear to work. Nor does creating a new set of authenticated cookies and pass them either.
So from what I gather, this solution is not possible....
My question
Does anyone know if it is possible to modify the Url.Action helper so it will generate and include a one-time authentication key in the url? Then implement some code in my custom AuthorizeAttribute that strip the key parameter and if valid, provide an alternative method of authentication to access the necessary image controller. This way, I can run the ABCPdf conversion process and it will be able to access the normally restricted resources in the image controller.
For example:
<img src="http://somesite.com/Image/Retrieve/1234?key=WFD6312DFV154WHSF3B1SGB69SB" />
The custom AuthorizeAttribute code should then recognise the key parameter passed in the requests query string and then bypass existing authentication processes.
Any help or even suggestions for where to look would be greatly appreciated!

When using OutputCache with MVC, sub.domain.com gives me www.domain.com cached page

I have a single ASP.NET MVC app which uses areas to deliver different functionality depending which url is hit. For example
www.domain.com - Website Area
app.domain.com - Application Area
*.domain.com - Client Area
So, the point is that depending on the incoming url, we route you to a different MVC Area. This is all done using Routing with some extensions and works great.
Now, if I enable outputcache on the Index() Action for my www default route, the next time i hit app.domain.com, i get the cached version of the www domain. I checked using fiddler and the response is a 200 OK so it's definately hitting the server. However, the logging in my custom routing tells me it's not hitting that code.
So, does OutputCache not work based off the uri and instead uses some other algorithm?
Thanks
[OutputCache(VaryByHeader="Host")] should help.
The behavior will depend on where you decided to store the cache (Location property). Ifv you stored the cache on the server (OutputCacheLocation.Server) then the result from the execution of the action will be stored on the server and when a subsequent request is made to this action, the server will be hit and it will directly return the cached version without executing the controller action which is the behavior you describe.
If you store the cache on the client (OutputCacheLocation.Client), then the cache will be kept on the client browser. In this case if a subsequent request is made to the same action, the client will no longer hit the server but will directly serve the page from its cache. And remember that if you hit F5 in your browser you will expire the cache for the given page, so the server will be hit.

how i can use cache in client side browser?

i have a website who have a list of information on the front page. the left side and right side bar have some information who rarely to update so i thing that i need to store them in cache.
how i can store them in cache in ASP.NET MVC 3. any suggetion for doing this.
David Hayden has a blog post on partial page OutputCache
http://davidhayden.com/blog/dave/archive/2011/01/25/partialpageoutputcachingaspnetmvc3.aspx
And Phil Haack has an article on donut hole caching (based on an older version of MVC)
http://haacked.com/archive/2009/05/12/donut-hole-caching.aspx
I don't think you want to store them in the browser cache, but rather in the server cache so you don't need the server to regenerate the content each time. Partial page caching on the client would be hard to do unless you were doing ajax calls. In that case you could cache the result from an ajax call and it would be reused by subsequent ajax calls.
You can use OutputCacheAttribute to store the return values of the controller in the web server cache. What this does is the next the controller action is invoked the cached data is returned instead of executing the method. Since you also mention you want to cache this on the client browser you might want to look at Google Gears or other solutions for that.

Is it possible for Rails sessions to be created 'just in time'?

My understanding of the session lifecycle in Ruby on Rails (specifically v3 and upwards) is that a session is created at the start of a request, for each and every request, and if that request doesn't carry an existing session cookie a new one will be created, otherwise the session cookie is deserialized and stored in the session hash.
The purpose of this, of course, supports a number of security features such as CSRF etc.
However, this poses a bit of an issue when it comes to caching of pages in a site with HTTP cache services and proxies such as Varnish, as most of the configurations tend to strip out these (generally all) cookies on both the request and response end (as the cache is usually intended for a generalized audience).
I know that it is possible to setup Varnish etc to create the object hash with the cookie details included, and this would scope the cached data to that session (and therefor that user), however I am wondering if this is completely necessary.
I have an application which is fairly 'static' in nature - content is pulled from a database, rendered into a page which can then be cached - there are a few elements (such as comment count, 'recent' items etc) which can be added in with an ESI, but for every request Rails still tends to want to setup a new session, and when a user already has a session this stuff is stripped out by the cache server.
I am wondering if it might be possible (via pre-existing functionality, or building the functionality myself) to allow the developer to control when a session is required, and only when that is specified is the back-and-forwards with cookies, session initialization/deserialization etc necessary.
That, or I am thinking about this problem the wrong way and need to address the issue from another angle...
From what I know rails sessions can be controlled fairly in-depth via ActionController::SessionManagement
http://ap.rubyonrails.org/classes/ActionController/SessionManagement/ClassMethods.html#M000070
There are examples in the API docs of disabling it per action, per controller, etc.
If your site is mostly static then you may want to use full page caching. This takes Rails out of the request entirely and let's the web server deal with it once the content has been generated. Might cause some serious headaches depending on your exact needs as far as the comment counts and user-specifics though.

ASP.NET MVC and Ajax, concurrent requests?

AJAX newbie here!
At the moment in my ASP.NET MVC web app my AJAX requests appear to be getting batched or queued, im not sure.
No requests seem to be getting completed until the previous request has finished.
How do I go about getting the requests to return independantly?
I dont necessarily want someone to give me the answer but maybe some links to good tutorials or resources which could help. Thanks
I'm expanding on Lachlan Roche's answer, which is correct.
The ASP.NET framework will "single-thread" requests that deal with Session scope (a global resource), to prevent one request from interfering with another. In WebForms I think you can use the Page directive to specify that individual pages don't use Session and therefore don't need to treated synchronously like this.
The problem is that in ASP.NET MVC all requests use Session, because it's used to implement TempData. You can disable session state entirely, as Lachlan Roche pointed out, or you can deal with this on a case-by-case basis.
A possible solution might be to kick off your own background threads to process any long-running code, so that the initial request "completes" as quickly as possible.
ASP.NET will serially process requests on a per-session basis unless sessions are configured as disabled or read only in web.config via the enableSessionState attribute on the pages element.
As this is a page setting, this will not affect MVC controllers and they will still be subject to serial request processing.
Curiously, even with sessions disabled or set to readonly, we can still read and write session data. It seems to only affect the session locking that causes serial request processing.
<system.web>
<pages enableSessionState="ReadOnly"/>
</system.web>
Pages can also have an enableSessionState property, though this is not relevant to MVC views.
<%# Page EnableSessionState="True" %>
With the release of ASP.MVC 3 you can now add an attribute to your controllers to mark the Session as readonly, which allows actions to be called concurrently from the same client.
Sessionless Controller Support:
Sessionless Controller is another great new feature in ASP.NET MVC 3. With Sessionless Controller you can easily control your session behavior for controllers. For example, you can make your HomeController's Session as Disabled or ReadOnly, allowing concurrent request execution for single user. For details see Concurrent Requests In ASP.NET MVC and HowTo: Sessionless Controller in MVC3 – what & and why?.
- from this DZone article.
By adding SessionState(SessionStateBehaviour.Disabled) to your controller, the runtime will allow you to invoke multiple actions concurrently from the same browser session.
Unfortunately I don't think there is a way to mark an action so as to only disable the session when that action is called, so if you have a controller that has some actions that require the session and others that do not, you will need to move the ones that do not into a separate controller.
In later versions of ASP MVC you can decorate individual controller classes with the SessionStateAttribute
[System.Web.Mvc.SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class MyController : Controller
{
}
Since .NET Framework v3.0 released, you can use "SessionStateBehavior" enum with SessionStateAttribute:
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class MyController : BaseController { }
Well Concurrent Request are more on browser dependent aswell if you fire suppose 10 concurrent request to an action Using AJax in Mozilla and same using IE 8 then you will find that Mozilla has style to fire one request wait for its response and then fire second and so on... for this is one by one basis whereas in IE * this fire about 6 concurrent request at a time to Server.
So Concurrent Request are also dependent on browser type.
I suggest using jQuery for your ajax needs with asp.net mvc, I have used it exclusively and it has been extremely easy.
As for tutorials I would look at this: http://docs.jquery.com/Ajax
There are tons of options to play with and I also suggest downloading firebug so you can watch requests launch from your page asynchronously and see if they fire and what they return etc.
Like the other guy side, AJAX request are asynchronous and don't get queued up and they all return independently when they finish, so if you watch in firebug it will be easy to see what is going on behind the scenes and before the debugger gets hit

Resources