Turn off page-level caching in a user control - asp.net

I have a page with the following caching defined:
<%# OutputCache Duration="60" VaryByParam="None" %>
I have a user control inside that page that i don't want cached. How can I turn it off just for that control?

Option One
Use the Substitution control or API on your page. this enables you to cache everything on your page except the part contained within the substitution control.
http://msdn.microsoft.com/en-us/library/ms227429.aspx
One nice way to use this is to implement your control as a simple server control which renders the html as a string, but does so in the context of the page (that is with the correct Client IDs). Scott Guthrie has a really nice example of how this works. Works nicely with AJAX calls too by the way...
http://weblogs.asp.net/scottgu/archive/2006/10/22/Tip_2F00_Trick_3A00_-Cool-UI-Templating-Technique-to-use-with-ASP.NET-AJAX-for-non_2D00_UpdatePanel-scenarios.aspx
Excerpt from Scott Gu's article...
[WebMethod]
public string GetCustomersByCountry(string country)
{
CustomerCollection customers = DataContext.GetCustomersByCountry(country);
if (customers.Count > 0)
//RenderView returns the rendered HTML in the context of the callback
return ViewManager.RenderView("customers.ascx", customers);
else
return ViewManager.RenderView("nocustomersfound.ascx");
}
Option Two
Render the dynamic control via an AJAX call on the page load. This way, you can safely cache the entire page (including the AJAX call) and it is only the rendered result of the call that changes between pages.

Related

ASP.NET and ajax response

I have a main web page ("Base Page") that makes an ajax call (using jQuery) to the server. The server-side page ("Ajax Page") is an ASP.NET web form (no MVC in use here). Because (in this case) I'm using a GridView to render data within the ajax response, I have to include the <form runat="server"> tag.
My complaint is this--when the Base Page receives the AJAX response, it inserts it into the DOM, but because the AJAX response is comprised of HTML markup that includes a <form> tag, this sometimes results in nested html forms, which is bad.
I realize that I can use jquery to only insert a fragment of the response into the Base Page DOM--or that I could use jquery to subsequently strip out the offending <form> tag. But these feel like klunky work-arounds. Is there really no way to prevent the ASP.NET page from serving out its response with a <form> tag? I realize that the form tag is the heart of the ASP.NET webform model, but it sure makes using AJAX in ASP.NET a complicated affair--very much swimming upstream. Surely Microsoft has realized that the postback / server-side model is a thing of the past?
I also realize that Microsoft has some server-side AJAX libraries that probably address this issue--but I'd still like to know if there's a solution native to ASP.NET webforms.
Any suggestions?
You can add your GridView to a Web User Control and then render it to a string like this:
public static string ExecuteToString(this Control control)
{
Page page = new Page();
page.Controls.Add(control);
StringBuilder sb = new StringBuilder();
using (StringWriter writer = new StringWriter(sb))
{
HttpContext.Current.Server.Execute(page, writer, false);
}
return sb.ToString();
}
This means you don't need to point your ajax request to a page. You can use a web service. Query a specific method and then dynamically load the User Control, render it to a string and return the HTML. Because you put your HTML and code in a User Control you don't need to worry about stripping out form tags and you can still use all the asp controls as you would on a page.
I have no idea about the performance costs of using this method but I've been using it for a while and it seems fine to me.
Working with WebForms & AJAX for many years I can understand your frustration.
Usually when working with loading WebForm pages using jQuery AJAX, I wrap an ajax class around my page, just nested inside the form:
<html>
<head></head>
<body>
<form runat="server">
<div class="ajax">
Content here..
</div>
</form>
</body>
</html>
Then when I load the page, I call just this ajax class:
$("element").load("http://domain.com/webpage.aspx .ajax");
This means the form element isn't rendered into my page, preventing nested form issues, but your GridView can still be rendered into HTML successfully.
I was dealing with the same kind of issue, I resolved it the following way:
Response.Write("whatever content")
Response.End()
This will send ONLY what you put in "Response.Write()"... You're still free to alter headers, etc.
If your ajax server page is an aspx page(ex : ajaxpage.aspx) , you can remove the HTML makup in the ajaxpage.aspx except the first line which mentions the Page directive. So it should be something like this.
<%# Page Language="C#" CodeBehind="ajaxpage.aspx.cs" Inherits="MyProject.ajaxpage" %>
And in the code behind, you can return the data using response.Write
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("your markup to return here");
}
If it is to return some kind of (clean) HTML markup / some part of data, I am inclined to use a generic handler (ex : ajaxresponse.ashx )file instead of an aspx file and return data from that
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("<h3>Here is the Markup for UserDetails</h3>");
}
You can not use ASP.NET server controls on an ashx file. And you can not have a page to have a server control (ex : GridView ) without a form tag. It should be placed inside a form tag. Note that your server controls like gridview is going to render an HTML table markup only.
Personally if i want to get some clean & controlled HTML markup which i want to show /inject into my current page using ajax, i will use an ashx handler and write my code to output my required markup. ASHX files has performance advantages compared to a aspx file as it wont go thru the normal ASPX page life cycle ( All those events !).

Call master page function from user control?

After searching Google I found one way to call a master page function from a user control:
Create an interface that includes your method.
Implement the interface in your master page
From your control, reference this.Page.Master via the interface type.
Call your method.
This is a good approach, but I don't know that can I call a master page static function in this way.
Another approach is :
// this is also good.
((MyMaster)this.Page.Master).MyFunction();
But I heard that this can also be done through an event.
1) Could someone show me how I could call a master page function from a user control through an event?
2) Also, how can I call a master page static function through a common interface way which I explained above.
I think it'd be better to have your user control raise an event and have your page listen for the event and then call the master page function. Controls shouldn't have any knowledge of the things that implement them - including whether or not the page has a master page.
In your content page, use the MasterType directive to generate the Master type. Then you can use the exposed Master property in the content page without casting. If you want to call a static function in the master from the content, you need to call it using the name of the master's code-behind class (since it is static)
content page:
<%# Page MasterPageFile="~/dir1/master1.master" ....... %>
<%# MasterType VirtualPath="~/dir1/master1.master" %> <!--This technique might change between .net versions. This is testing on 3.5-->
content page.cs
this.Master.nonStaticFunc();
dir1_master1.staticFunc();

ASP.NET MVC output cache with dynamic fragment

How could I cache an entire page except a bit at the top which says something along the lines of "Welcome back, Matt! | Log Out" if the user is logged in and so-on?
I'm using ASP.NET MVC 2.
What you are trying to achieve is called donut-caching or cache substitution. As of ASP.NET MVC 2 there is no built in helper to support this scenario. As much as I know it was a planned feature in MVC v.1 but it was dropped somewhere in the way to the release. For more info check this links http://haacked.com/archive/2008/11/05/donut-caching-in-asp.net-mvc.aspx, Is Donut Caching working properly with ASP.NET MVC?.
VaryByParam option that is mentioned by Oleg here is not a good idea in your case. If you have VaryByParam a different version of the page will be put in the cache for every different value of the parameter (in your case for every user-name).
Personally I would think of caching the data, not the whole output of the page.
Probably helps
<%# OutputCache Duration="15" VaryByParam="*" %>
or with some other value for the VaryByParam. See http://msdn.microsoft.com/en-us/library/hdxfb6cy.aspx, http://blog.maartenballiauw.be/post/2008/06/Creating-an-ASPNET-MVC-OutputCache-ActionFilterAttribute.aspx and http://blogs.microsoft.co.il/blogs/gilf/archive/2010/07/18/asp-net-output-cache-provider.aspx.
Moreover, if you have the start page which is not user depended, it is possible to replace the start page with a very static welcome page with the empty field (hidden div) instead of "Welcome back, Matt! | Log Out". After that an ajax request for filling of the user name can be started at the client side. This kind of the welcome page page can be very good cached.
Not Supported != Not Possible
http://blog.maartenballiauw.be/post/2008/07/01/Extending-ASPNET-MVC-OutputCache-ActionFilterAttribute-Adding-substitution.aspx
http://www.klopfenstein.net/lorenz.aspx/output-donut-caching-attribute-asp-net-mvc-partial-requests
http://haacked.com/archive/2009/05/12/donut-hole-caching.aspx
Here you have a workaround solution:
*Add the OuptutCache attribute to the Controller that manages the whole view as usually:
[OutputCache(Duration = 3600, VaryByParam = "*")]
public ActionResult Index(FormCollection formCollection)
{
//Controller code
}
*For the part that you don't want to do caching, load it using jquery + an ajax request (with its own controller and without the OutputCache attribute):
<div id="loginContainer"></div>
$(document).ready(function() {
$.post('controller/action', postdata, function(data) {
if (data.success == true) {
//Populate the container with the obtained data
}
});
});
The view will be retrieved from the Output Cache and, once it is loaded, a request to obtain the login info will be performed. Hopefully, it will be a very quick request and the user will not notice the delay.
Get this via nuget:
http://mvcdonutcaching.codeplex.com/
Add an action for LogOnPArtial, so you can change it from Html.Partial to Html.Action in the _Layout.cshtml
#Html.Action("_LogOnPartial","Account",true)
The true is a exclude parameter that says, exclude this from caching. The action will be called even if the page it is in is cached. This is the "hole" in the donut that is not cached.
On your page, such as About.cshtml that you want cached, apply DonutOutputCache attribute. This allows the new framework to inspect the page as it's caching it, and add flags where you've excluded actions.
The nice thing is the _LogOnPartial is not cached and will refresh for different users while the rest of the page is cached and the About() action will not be run. You could even configure caching on the _LogOnPartial action you created using the DonutOutputCache attribute, but a more frequent or less frequent interval, or vary by some other param. This allows you to compose pages of partials, and the cache refreshing logic is independently configured for each partial.
IMO this tool is exactly how I imagined caching in MVC should have been implemented.

Html.ActionLink() gives me an empty link when I use it inside Html.RenderAction()

I have a Microsoft MVC project with an action "Foo" whose view ("Foo.aspx") contains the lines:
<%= Html.ActionLink("mylinktext1", "bar") %>
<%= Html.ActionLink<MyController>(x => x.Bar(), "mylinktext2") %>
When I hit this from a web browser or load it from an AJAX call, it properly returns:
mylinktext1
mylinktext2
But when I call the action from another view like this:
<% Html.RenderAction<MyController>(x => x.Foo()); %>
Then the links are rendered without targets.
mylinktext1
mylinktext2
Why would this be happening, and how do I work around it?
I don't know if that is what you are doing wrong, but I have never used Html.RenderAction with actions that return ASPX views. When I call RenderAction, I make sure that I am calling a controller action that returns ASCX View User Control.
Typically .ASPX file is an entire page and you can't (shouldn't) render this inside another page.
So I think you should make it View User Control (ASCX) and put it either in Shared or in controller's view folder.
Based on your comment:
Of course this is fine. You just return your data as model to your views/view user controls. When you load them thru AJAX, you should consider implementing Render View to String. Search the Google or Stack for more information on it. You can also search for a thing called JsonPox attribute for your action methods - also implemented somewhere on the internet. It will enable decorating your action methods so that they are able to return HTML view, XML or JSON if that's what you also might need.

AJAX+ASP.NET

As far i learned ....AJAX is used for partial page refresh (overcoming the flickering effect in the web page) ....Is there any other features in AJAX....
Technically Yes. Ajax is used for "partial page" refresh there by eliminating the complete page refresh. There are 2 main advantages
Data transfer : Data transfer (To and from the server) is less compared to the entire page refresh
Better User experience : Since the user will not be seeing a blank page it gives the user an illusion of interacting with the site.
What can be done using AJAX is an ever ending list.
Ex: Gmail uses AJAX for it email. If you are using gmail and compare it with other email providers you will know the difference.
Facebook has rich AJAX features in its site.
SO uses AJAX for comments
I think What AJAX cannot do will be easier to mention. For example
AFAIK web browsers cannot maintain the view state of the AJAX enabled website.
Some AJAX enabled websites do not render properly in mobile browsers.
Anythign more?
Your question is a bit confusing, but you can do Ajax with ASP.NET. You can do partial page refreshes with Ajax among other things using the UpdatePanel in ASP.NET. You may also want to look at jQuery for a simpler more lightweight Ajax solution.
I think you're very mistaken. If AJAX had been created only to solve the problem of partial page refresh/page flickering, it would not have revolutionized the web in the way it has.
The single biggest advantage offerred by AJAX is Client-to-Server Communication that is initiated based on some action on the client. This instantly gives us the ability to make the web much more responsive and user friendly without users having to wait for page reloads and postbacks.
I would suggest that you spend some time researching the subject. Read up on the Wiki article on AJAX.
As far as ASP.NET is concerned, AJAX integrates very well into it. Mature AJAX frameworks such as ASP.NET AJAX and Anthem.NET obfuscate much of the internal details of the XmlHttpRequest.
Ajax has let me add some great new features to my web applications with the free Ajax toolkit. See the link
Ajax Examples
They do not come with out their issues but once you learn how to use them they can really add to the the users experience in you site.
ASP.NET uses as you know UpdatePanel for partial page refresh using AJAX.
A less known feature is something .NET calls web methods. This is really AJAX calls that is not connected to the GUI part of the page. You can declare (server-side) a method as a WebMethod, and in the client side, you can call that using JavaScript.
Example:
This example shows how to get the value of a session variable. Note that the method must be Shared - which means that it does not know of any member values on the page object.
As for all ASP.NET AJAX functionality, you need to have a ScriptManager element on the page. To enable page methods, you also need to add EnablePageMethods="true" to the ScriptManager like this:
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true" />
Server side code (VB):
<Services.WebMethod()> Public Shared Function GetPreviewImages() As String
Dim lPreviewImages As String = HttpContext.Current.Session("mPreviewImages")
If lPreviewImages IsNot Nothing Then
Return lPreviewImages
Else
Return ""
End If
End Function
Client side code:
//Declare the return methods:
function GetPreviewImages_Success(result, userContext, methodName) {
alert(result);
}
function GetPreviewImages_Failed(error, userContext, methodName) {
var errorMessage = 'Error in map server method ' + methodName ;
if(error !== null) errorMessage += '\n' + error.get_message();
alert(errorMessage);
}
// Call the page method:
PageMethods.GetPreviewImages(GetPreviewImages_Success, GetPreviewImages_Failed);
See also example in C#, which also includes how parameters work in the web method.

Resources