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
Related
I am currently learning JSF and was rather amazed and puzzled when I realized that whenever we use <h:form>, the standard behavior of JSF is to always show me the URL of the previous page in the browser, as opposed to the URL of the current page.
I understand that this has to do with the way JSF always posts a form to the same page and then just renders whatever page the controller gives it back to the browser which doesn't know the page location has changed.
It seems like JSF has been around for long enough that there must be a clean, solid way to deal with this. If so, would you mind sharing?
I have found various workarounds, but sadly nothing that seems like a real solid solution.
Simply accept that the URL is misleading.
Append "?faces-redirect=true" to the return value of every bean's action and then
figure out how to replace #RequestScoped with something else (Flash Scopes, CDI conversation, #SessionScoped, ...).
accept to have two HTTP round trips for every user action.
Use some method (e.g. 3rd party library or custom code) to hide the page name in the URL, always using the same generic URL for every page.
If "?faces-redirect=true" is as good as it gets, is there a way do configure an entire application to treat all requests this way?
Indeed, JSF as being a form based application targeted MVC framework submits the POST form to the very same URL as where the page with the <h:form> is been requested form. You can confirm it by looking at the <form action> URL of the generated HTML output. This is in web development terms characterized as postback. A navigation on a postback does by default not cause a new request to the new URL, but instead loads the target page as content of the response. This is indeed confusing when you merely want page-to-page navigation.
Generally, the right approach as to navigation/redirection depends on the business requirements and the idempotence (read: "bookmarkability") of the request (note: for concrete code examples, see the "See also" links below).
If the request is idempotent, just use a GET form/link instead of POST form (i.e. use <a>, <form>, <h:link> or <h:button> instead of <h:form> and <h:commandXxx>).
For example, page-to-page navigation, Google-like search form, etc.
If the request is non-idempotent, just show results conditionally in the same view (i.e. return null or void from action method and make use of e.g. <h:message(s)> and/or rendered).
For example, in-page data entry/edit, multi-step wizard, modal dialog, confirmation form, etc.
If the request is non-idempotent, but the target page is idempotent, just send a redirect after POST (i.e. return outcome with ?faces-redirect=true from action method, or manually invoke ExternalContext#redirect(), or put <redirect/> in legacy XML navigation case).
For example, showing list of all data after successful editing, redirect after login, etc.
Note that pure page-to-page navigation is usually idempotent and this is where many JSF starters fail by abusing command links/buttons for that and then complain afterwards that URLs don't change. Also note that navigation cases are very rarely used in real world applications which are developed with respect to SEO/UX and this is where many JSF tutorials fail by letting the readers believe otherwise.
Also note that using POST is absolutely not "more secure" than GET because the request parameters aren't immediately visible in URL. They are still visible in HTTP request body and still manipulatable. So there's absolutely no reason to prefer POST for idempotent requests for the sake of "security". The real security is in using HTTPS instead of HTTP and checking in business service methods if currently logged-in user is allowed to query entity X, or to manipulate entity X, etc. A decent security framework offers annotations for this.
See also:
What is the difference between redirect and navigation/forward and when to use what?
JSF implicit vs. explicit navigation
What URL to use to link / navigate to other JSF pages
Bookmarkability via View Parameters feature
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
When should I use h:outputLink instead of h:commandLink?
Creating master-detail pages for entities, how to link them and which bean scope to choose
Retaining GET request query string parameters on JSF form submit
Pass an object between #ViewScoped beans without using GET params
My All Js and css are in script.jsp file and include on every page
<jsp:include page="../include/scripts.jsp" />
when page submit / refresh it reload again and again ?
How to control this ?
Here's an explanation I found that could explain it. It helped me out when i needed it
Here's an explanation of the problem...
Clicking the "submit" button on a form sends a request to the web server, which includes all the data entered on the form. Not only the URL but also the form data is part of the request, and this request is remembered by the browser. If the user clicks "refresh", the browser repeats the request, sending the same URL and form data to the web server again.
But forms can be submitted in two different ways, GET or POST, depending on the "method" attribute of the "form" tag. There is a convention that a GET request has no side-effects; it only fetches data but does not make any changes to the database. On the other hand, if a request changes data it should always use a POST request. As I said, these are only conventions, and there is not much technical difference between them, but a very important difference is that browsers will warn the user if they try to repeat a POST -- clicking "refresh" will pop up a dialog box warning the user that this may cause an operation to be repeated, and confirming that they really want to resubmit. The browser does not show this confirmation when refreshing a GET request.
Is your form using the GET method changing it to POST is the simplest solution, since this will at least mean that the user is warned if they try to refresh.
But a better solution is the POST+REDIRECT+GET idiom suggested by #cletus. This splits the database update (POST) and the view (GET) into two operations. Clicking refresh on the browser then merely repeats the GET, which has no side-effects.
Use the include directive <%# include/> as against the <jsp:include/> tag you're using now.
<jsp:include/> will instruct the jsp runtime to go and fetch the included resource everytime the compiler comes across that tag (first-time requests, refreshes) while <# include/> means that the included resource is built into the parent resource at compile-time
The difference is that the directive is a compile-time include. This means that the content of the directive (in your case scripts.jsp) is baked into the parent jsp (and ultimately the servlet that the jsp will be compiled into). The effect is that the included file is read only the first time the parent jsp is rendered.
What you should have:
<%# include page="../include/scripts.jsp" />
Related:
What is the difference between <jsp:include page = ... > and <%# include file = ... >?
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.
Hi One of the tips in "website performance tips" in various blogs says "Avoid Redirects". In my case, I am using Response.Redirect for the same page. I am passing a querystring and displaying appropriate information to the user.
Response.Redirect("FinalPage.aspx?NextID=" + ID);
So in our business logic, i am reloading the same page with different information.
So how do i avoid redirect? Is there any other alternative? BTW, my aim is to gain some performance there.
Redirect is the R in the PRG pattern which is an accepted pattern for processing posted requests. So it is definitely not evil.
However, there used to be a common interview question: "What is the difference between Server.Redirect() and Server.Transfer() and which one must be used?". People used to say Transfer because it did not involve a round-trip but web has changed so much since then. In those days you could not re-use the the common logic in the views unless you use Transfer or Redirect, but nowadays especially with ASP NET MVC there are tons of a ways to do that.
In your case, I am all for PRG and I believe redirect is semantically more correct. Also it prevents the form being re-submited if user clicks F5 or refresh.
The recommendation is for unnecessary redirects.
Your case is different - you are passing in information to the page, this is not strictly the same thing as a regular redirect (i.e. a page that moved).
You can also do a Server.Transfer, which does not require a new request to come in, thus lessening the load on the server. More information comparing the two is here.
In your case, you do want to do a Redirect because you are modifying the query string and changing something on the page, as opposed to shifting processing of the initial request to another page.
The main "evil" if it could be called such is that redirects require an extra round trip; the client requests one page (usually the same page, specifying that a particular button was clicked), and the server responds saying "request this page instead", and the browser then complies, resulting in the server actually serving up the next page.
It's sometimes necessary to do this, however there are now much better ways to control navigation in a website. For instance, instead of a "form" button that causes a postback and redirect, you could use a LinkButton that will behave like a hyperlink, allowing the browser to request the new page directly. You could also use a MultiView that shows different ASCXs, and control navigation by view-flipping (however, understand that this can have its own performance implications, especially when using them in a nested fashion).
I think if you want to redirect to same page then instead of doing Response.Redirect("FinalPage.aspx?NextID=" + ID); you could use NextID in ViewState also or Hidden Field so that you would not required to redirect SAME page and then check that hidden field or viewstate instead of checking QueryString
:D
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).