ASP.NET Page Level Caching (with authenticated sites) - asp.net

It is my understanding that page level caching does not take into account that, for authenticated sites, different users may request the exact same page (URL) while the rendered page itself is different (because it contains stuff that is user specific).
Unless you activate cookieless authentication (then the sessionID becomes part of the URL) all users will see the same cached page (regardless of who they are).
Is this correct?

Yes, you are 100% correct on this one.
Typically I'll move to user controls, to be able to cache the user controls of the items that do not change from user to user.
You can then use Session, or another cache store if you must cache user specific data.

Depending on how much dynamic contnent you have on a page you could use the Substitution control to render dynamic content on a cached page.
This control is bound to a static method (remember that the page lifecycle hasn't run as this is cached version of the page and none of the objects created in Page_Load etc wiil be available) that returns dynamic content and can be positioned wherever you want on the page.
<asp:Substitution ID="mySubstitution" runat="server" MethodName="GetLoggeninUserName" />

The other option is "Donut Caching" as Scott Guthrie calls it:
Implement "Donut Caching" with the ASP.NET 2.0 Output Cache Substitution Feature
This allows you to have page level caching, while implementing certain elements in non-cached "holes".

Yes you're correct and the Substitution control noted by Andy (and Zhaph) is your best answer if you're using ASP.NET 2.0 or above. Creating separate user controls for the non-user-specific content is a less ideal approach that should only be used if you're stuck working with ASP.NET v1.x (so you should mark Andy's as the answer, I would think).

Related

How can I do a partial page update with ajax using Sitecore?

I have a specific page (sitecore content item) in my web application composed of a sitecore layout and many sublayouts. One of those sublayouts is a user control that I would like to have refreshed once a certain button is clicked. I would like only that sublayout to be refreshed and the rest of the page to remain unchanged (typical ajax situation here). How do I accomplish this with sitecore when all of my sitecore content items are directly related to a full page in my web application (layout with sublayouts)? In my case, I want to use ajax to return the content of a specific, single sublayout only. What is the best practice for this kind of ajax situation with sitecore? I'm using sitecore 6.5.
Since you use the phrase "partial page update", I assume you are using an UpdatePanel. This doesn't really function any different than it would in a traditional ASP.NET application. You will handle the button click in a server-side handler method, modify properties on controls and let the update panel handle the rest.
If you are not using update panel, you have a few options depending on exactly what you want to achieve.
Typically, if you are clicking a button to trigger an ajax request, you are posting some data back to the server. For this case you would usually set up a web service to process the data and return some result. Your service can access Sitecore data, but does not utilize the Sitecore presentation engine.
Another option would be to make the request to a Sitecore page (possibly the same as the original request), but include a querystring parameter to trigger a different device. You could configure this device to render JSON, XML or a fragment of HTML rather than the normal Layout and battery of sublayouts.
Another option would be to use the Sitecore Item Web API. If you go this route, you will have another array of options (and a bit of a learning curve as well). Start by reading the documentation on SDN or some of the many blog posts on the topic.
There are a number of options available for achieving asynchronous behavior. None of these really relate to Sitecore directly, however, there are some Sitecore specific things to watch out for which I have highlighted below.
UpdatePanel Control
If you are performing something trivial where ultra-fast performance isn't a concern, simply wrap your button (and any other .NET controls that you would
like updated) in an UpdatePanel Control. You will also need to drop
a ScriptManager control into your base layout near the top inside
the <form> element. NOTE: When using this method, you will need to ensure that that your Sublayout does NOT have caching enabled, otherwise your button will not postback properly
Create your own web service
In this scenario, there are many client-side frameworks available for achieving the same result. My preferred method is to hook onto the client-side button click event with jQuery, prepare a request object, and post it to the server (getting back the information you need to update the client).
Here are a number of web service options that work with Sitecore - allowing you to have access to the Sitecore.Context and all of the subsequent Sitecore APIs.
Create an empty ASPX Web Form that accepts parameters as query strings. In the Page_Load method, do some work with the parameters and write directly to the response using Response.Write(). A JavaScriptSerializer comes in handy for serializing to JSON, just be sure to set Response.ContentType = "text/javascript";
Create an ASMX Web Service and decorate your methods with [WebMethod] (or [WebMethod(EnableSession = true)] if you need access to Session data).
Use MVC Controllers (ex: ASP.NET Web Api) to create an API. I believe there are some issues to work around in Sitecore 6.5 as described here.
Since this is all contained within a single Sublayout, you could simply use a standard <asp:UpdatePanel> surrounding your button and the usercontrol. In the code-behind, you can then do whatever databinding / data retrieval necessary to update the content of the usercontrol.
Note, if the button was on a different sublayout to the one where the content needs to be updated, you can use the approach described in this question as long as both controls have their content within <asp:UpdatePanel>.
In answer to your other question:
What is the best practice for this kind of ajax situation with sitecore?
There's not really a Sitecore-specific best practice for this sort of thing. In this case, any approach which works for plain ASP.NET will also work with Sitecore. The approach I described above is probably the simplest and quickest to implement, but you could also do this via jQuery and ajax to call a web service to load updated content.

ASP.NET page caching and session variable

I have a asp.net webpage that displays a link Login or Logout depending on a session variable "IsLogged". I want to implement caching in that page. But after applying caching the Login/Logout becomes inconsistent with the session variable. What is the best approach to address this problem so that I can also apply caching in that page?
Thanks,
Partha
I am not sure how you are caching specifically but you could break your page up into two user controls (ascx).
Your aspx page could contain the user control to that shows the login information (make sure that when you load the user control with a dynamic url so that the caching ignores it because the address is diff everytime like:
yourSessionInfo.ascx?stopcache=32487239875 (the number could be just current time in ticks)
You just need something that changes in your url so that the page 'looks' like it is different and reloads.
Then have the rest of your page in another user control that has a static url:
yourRestOfPage.asx
Notice nothing changing in the url so page can be cached.
Not sure if this will solve your exact problem but it should at least start you down the right path.

HttpRuntime.Cache how to discard

I have a problem with an asp.net site (4.0 framework) I would like to understand how to properly discard of values in HttpRuntime.Cache between page requests. I am storing values for pagination , control state etc on a search page, and it works fine .. except the values for controls exist (eg. combo box selection) if i open a different browser and open the page.
You should not be using Cache in this way. Not only is it cross-browser-window... it applies to the whole application.
You should use querystring/form values for saving which page is being viewed, instead.
If you want a storage per session, the HttpContext.Current.Session is a good place to put it. As Andrew Barber points out, the Cache is application-wide (shared by all users and sessions)

ASP.NET Caching : Good As Well As Bad ! Page shows old content!

I have an ASP.NET website where i have implemented page level caching using the OutPutCache directive.This boosted the page performance.My pages has few parts(Some buttons,links and labels) which are specific to the logged in user.If user is not logged in,they will see different links.Now Since i implemented the page level caching,Even after the user logged in,It's showing the old page content(Links and buttons meant for the Non logged in User).
Caching is obviously good.But how to get rid of this problem ? Do i need to completely remove caching ?
what you want is Partial Page caching:
http://msdn.microsoft.com/en-us/library/ms227429.aspx and http://msdn.microsoft.com/en-us/library/h30h475z.aspx
I ran into the exact same issue and was able to resolve it using Response.WriteSubstitution. Just create a static method that accepts HttpContext as an argument, returns the login status as a string, and render the method using WriteSubstitution:
Response.WriteSubstitution(new HttpResponseSubstitutionCallback(GetLoginStatus));
The rest of the page will cache as normal but the login status will be updated each time the page is loaded.
You can use the VaryByParam directive:
VaryByParam: This attribute allows us
to control how many cached versions of
the page should be created based on
name/value pairs sent through HTTP
POST/GET. The default value is None.
None implies that only one version of
the page is added to the Cache, and
all HTTP GET/POST parameters are
simply ignored. The opposite of the
None value is *. The asterisk implies
that all name/value pairs passed in
are to be used to create cached
versions of the page. The granularity
can be controlled, however, by naming
parameters (multiple parameter names
are separated using semi-colons).
Used like so in the page directive
<%# OutputCache Duration="10800" VaryByParam="State;City" %>
Be careful what you use in the VaryByParam, as this can cause the number of copies of the page in memory to be up to the number of different values of your parameter that exist.
EDIT: as mentioned in comments, this won't work if you're using cookies for login, but some people do use cookie-less login, which puts the info in the GET/POST portion.
See here for more details

Can I change the browser URL while maintaining ViewState in ASP.NET?

I'm doing some brainstorming for a portal framework, and I'm envisioning a breadcrumb navigation stack that is tracked via the ViewState (so that if the user clicks "back" in their browser and clicks some other link, the breadcrumb trail will depart from the right page). My pages are really just ascx controls that get loaded into a placeholder control on the main portal page based on the URL. When the user clicks a portal link, there is a postback that loads the original page and invokes the given link's "clicked" handler, which should then "push" the current location onto the breadcrumb stack before sending the browser a redirect instruction to change the URL to that of the page that I want to go to.
That's as far as my brainstorming goes for the moment, because once we perform a redirect, we lose the ViewState. Rather than doing the redirect, I've thought of simply telling my main portal page to replace the current page control with the target page control, thus avoiding the extra http round-trip and allowing me to keep the ViewState. But then my entire website experience occurs in the context of a single URL, so I lose URL bookmarking among other things. And if I wrap some of my controls in AJAX panels, the entire site happens in one page request as far as the browser's history is concerned.
What I would like is some way to have the browsing history and URLs behave as if each link is leading them to a new page with a descriptive URL and all that, but still have some way to know the path that the user took to get to the page that they're on (ViewState seeming to be the simplest way to track this).
Could anyone suggest some techniques I might try using?
First suggestion... You may want to look into ASP.NET MVC. However, I have to admit to some ignorance here as I'm not sure that would really solve your problem. But it sounds like the sort of thing MVC would be suited for.
Second... it's possible to override the methods responsible for saving and loading ViewState. One of the things you can do, for instance, is push the ViewState into the Session rather than sending it down to the user and back up on postback. You could easily add some custom code here.
Third... I think you may want to rethink part of your design. The ViewState really serves one purpose: It recreates the state of the page as it existed when the page was rendered for the user. If you are moving to a different page, or a new set of controls, why would you need the ViewState at all? The ViewState itself is really just a hack to begin with... ASP.NET's way of maintaining state on top of a stateless system. (but that's a whole 'nother discussion) We have other methods of maintaining state... the primary mechanism being the Session object. Why not save your breaacrumb data there instead?
I would look at using cookies. For performance reasons, you really want to avoid HTTP redirects if you can, and ViewState only works if the user submits a form, not for regular links.
You might do something like maintain several path lists in cookies that show the path that the user took to go from one page to another. Maybe you set a unique ID with each page that is applied by some JavaScript as a query string when the user clicks on a link, and the server uses that ID and the past history from the cookies to determine how to render the bread crumb on the next page?

Resources