Im adding a literal control to my ascx page
<asp:Literal ID="customLiteral" runat="server" />
Inside the Page_Load method I'm populating this text dynamically using the httpContext. I need to read some cookies to set the value of this Literal.
customLiteral.Text = Utility.RenderText(HttpContext.Current) + "<h3>" + DateTime.Now.ToShortTimeString() + "</h3>";
This works perfectly fine on the first load of the page. But does not hit my RenderText method on subsequent loads, so does not honor the value of cookies to render this literal. I added in the date value for testing and the value also remains a constant. Would the literal value be cached somehow? I'm also hitting the breakpoints inside my Page_Load only once on the first load. Is there a better way to achieve what I want here?
Based on your series of interactions with Greg, I suspect that some form of output caching is occurring. If so, there are handful of ways to get whatever data you're trying to have presented in real-time and on each load to show up on page refresh.
The key to implementation comes in the form of something called post-cache substitution (https://learn.microsoft.com/en-us/previous-versions/ms227429(v=vs.140)?redirectedfrom=MSDN) This technique is also known as "donut caching" because when you think about a donut, there's a hole that's cut in the middle. To compare: if your HTML page output were the donut, the "hole" in the middle of it would be the location where you want to place your output (your Literal control) on-demand each time the page is served and not just rendered in the page lifecycle.
Post-cache substitution can be done entirely within code, but I've preferred to use the Substitution control (https://learn.microsoft.com/en-us/dotnet/api/system.web.ui.webcontrols.substitution?view=netframework-4.8) as it makes things a little easier to understand. This control consists of two logically separate parts. There's the section that responds within the normal ASP.NET page/control lifecycle (e.g., Page_Load). The other portion is a public static method that gets called on the control just before the served back to a user from the output cache. That static method is where you might serve up the contents of what you're currently attempting to show with your Literal control.
I present at conferences and events on caching a lot, and I developed a sequence diagram to help my audiences understand what's going on:
I normally work with SharePoint, and I've implemented this in numerous scenarios to great effect. I hope it works for you!
Related
This is 10KB in my HTML source:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="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AQUDVG9tZGQCBQ8PFgQfAgULfi91c2Vycy9Ub20fBQUgVG9tIG1ha2VzIGdhbWVzIHdpdGggQ29uc3RydWN0IDJkFgJmDw8WBB8IBUlodHRwOi8vd3d3LmdyYXZhdGFyLmNvbS9hdmF0YXIvNTI3MWQzMjgzZGI5NTdlZjNhODY3NjFlZDE1YzE2OTY/cj1wZyZzPTgwHwUFDlRvbSdzIEdyYXZhdGFyZGQCBw8PFgYfBgUQcyBjb21tZW50LXJlcG9ydB8FBRBSZXBvcnQgdGhpcyBwb3N0HwcCAmRkAgkPDxYGHwYFEHMgY29tbWVudC1kZWxldGUfBQUQRGVsZXRlIHRoaXMgcG9zdB8HAgJkZAILDw8WBh8GBQ5zIGNvbW1lbnQtZWRpdB8FBQ5FZGl0IHRoaXMgcG9zdB8HAgJkZAINDw8WBh8GBQ9zIGNvbW1lbnQtcXVvdGUfBQUPUXVvdGUgdGhpcyBwb3N0HwcCAhYCHwMFBSNQb3N0ZAIPDxYCHwEFH1tRVU9URV1yZWdnWy9RVU9URV13ZWYgd2UgZiB3ZmVkAgMPZBYOAgMPDxYEHwYFGWNvbW1lbnQtaGVhZCBjaC1oaWdobGlnaHQfBwICZBYEAgEPFgIfAQVaPGFiYnIgY2xhc3M9InRpbWVhZ28iIHRpdGxlPSIyMDExLTA0LTIzVDE3OjI3OjU1Ljk1NzAwMDAiPjIzIEFwcmlsIDIwMTEgYXQgMTc6Mjc6NTU8L2FiYnI+ZAIDDw8WBh8CBQt+L3VzZXJzL1RvbR8FBR5WaXNpdCB0aGlzIGdhbWUgbWFrZXJzIHByb2ZpbGUfAQUDVG9tZGQCBQ8PFgQfAgULfi91c2Vycy9Ub20fBQUgVG9tIG1ha2VzIGdhbWVzIHdpdGggQ29uc3RydWN0IDJkFgJmDw8WBB8IBUlodHRwOi8vd3d3LmdyYXZhdGFyLmNvbS9hdmF0YXIvNTI3MWQzMjgzZGI5NTdlZjNhODY3NjFlZDE1YzE2OTY/cj1wZyZzPTgwHwUFDlRvbSdzIEdyYXZhdGFyZGQCBw8PFgYfBgUQcyBjb21tZW50LXJlcG9ydB8FBRBSZXBvcnQgdGhpcyBwb3N0HwcCAmRkAgkPDxYGHwYFEHMgY29tbWVudC1kZWxldGUfBQUQRGVsZXRlIHRoaXMgcG9zdB8HAgJkZAILDw8WBh8GBQ5zIGNvbW1lbnQtZWRpdB8FBQ5FZGl0IHRoaXMgcG9zdB8HAgJkZAINDw8WBh8GBQ9zIGNvbW1lbnQtcXVvdGUfBQUPUXVvdGUgdGhpcyBwb3N0HwcCAhYCHwMFBSNQb3N0ZAIPDxYCHwEFdDxkaXYgY2xhc3M9ImNvbW1lbnQtcXVvdGVyIj5Db21tZW50IGJ5IDxzdHJvbmc+VG9tPC9zdHJvbmc+PGJyIC8+PGJyIC8+T2sgbmljZSBvbmUgOi0pIExvdmluZyB0aGlzITwvZGl2Pk5vIHByb2JsZW1vZAIED2QWDgIDDw8WBB8GBRljb21tZW50LWhlYWQgY2gtaGlnaGxpZ2h0HwcCAmQWBAIBDxYCHwEFWjxhYmJyIGNsYXNzPSJ0aW1lYWdvIiB0aXRsZT0iMjAxMS0wNC0yM1QxNzoyNzoyNy45ODcwMDAwIj4yMyBBcHJpbCAyMDExIGF0IDE3OjI3OjI3PC9hYmJyPmQCAw8PFgYfAgULfi91c2Vycy9Ub20fBQUeVmlzaXQgdGhpcyBnYW1lIG1ha2VycyBwcm9maWxlHwEFA1RvbWRkAgUPDxYEHwIFC34vdXNlcnMvVG9tHwUFIFRvbSBtYWtlcyBnYW1lcyB3aXRoIENvbnN0cnVjdCAyZBYCZg8PFgQfCAVJaHR0cDovL3d3dy5ncmF2YXRhci5jb20vYXZhdGFyLzUyNzFkMzI4M2RiOTU3ZWYzYTg2NzYxZWQxNWMxNjk2P3I9cGcmcz04MB8FBQ5Ub20ncyBHcmF2YXRhcmRkAgcPDxYGHwYFEHMgY29tbWVudC1yZXBvcnQfBQUQUmVwb3J0IHRoaXMgcG9zdB8HAgJkZAIJDw8WBh8GBRBzIGNvbW1lbnQtZGVsZXRlHwUFEERlbGV0ZSB0aGlzIHBvc3QfBwICZGQCCw8PFgYfBgUOcyBjb21tZW50LWVkaXQfBQUORWRpdCB0aGlzIHBvc3QfBwICZGQCDQ8PFgYfBgUPcyBjb21tZW50LXF1b3RlHwUFD1F1b3RlIHRoaXMgcG9zdB8HAgIWAh8DBQUjUG9zdGQCDw8WAh8BBXA8ZGl2IGNsYXNzPSJjb21tZW50LXF1b3RlciI+Q29tbWVudCBieSA8c3Ryb25nPlRvbTwvc3Ryb25nPjxiciAvPjxiciAvPk9rIG5pY2Ugb25lIDotKSBMb3ZpbmcgdGhpcyE8L2Rpdj5UaGFua3MhZAIFD2QWDgIDDw8WBB8GBRljb21tZW50LWhlYWQgY2gtaGlnaGxpZ2h0HwcCAmQWBAIBDxYCHwEFWjxhYmJyIGNsYXNzPSJ0aW1lYWdvIiB0aXRsZT0iMjAxMS0wNC0yMlQxNDozOToyMy4xMjAwMDAwIj4yMiBBcHJpbCAyMDExIGF0IDE0OjM5OjIzPC9hYmJyPmQCAw8PFgYfAgULfi91c2Vycy9Ub20fBQUeVmlzaXQgdGhpcyBnYW1lIG1ha2VycyBwcm9maWxlHwEFA1RvbWRkAgUPDxYEHwIFC34vdXNlcnMvVG9tHwUFIFRvbSBtYWtlcyBnYW1lcyB3aXRoIENvbnN0cnVjdCAyZBYCZg8PFgQfCAVJaHR0cDovL3d3dy5ncmF2YXRhci5jb20vYXZhdGFyLzUyNzFkMzI4M2RiOTU3ZWYzYTg2NzYxZWQxNWMxNjk2P3I9cGcmcz04MB8FBQ5Ub20ncyBHcmF2YXRhcmRkAgcPDxYGHwYFEHMgY29tbWVudC1yZXBvcnQfBQUQUmVwb3J0IHRoaXMgcG9zdB8HAgJkZAIJDw8WBh8GBRBzIGNvbW1lbnQtZGVsZXRlHwUFEERlbGV0ZSB0aGlzIHBvc3QfBwICZGQCCw8PFgYfBgUOcyBjb21tZW50LWVkaXQfBQUORWRpdCB0aGlzIHBvc3QfBwICZGQCDQ8PFgYfBgUPcyBjb21tZW50LXF1b3RlHwUFD1F1b3RlIHRoaXMgcG9zdB8HAgIWAh8DBQUjUG9zdGQCDw8WAh8BBR90cmhoIHJ0aCAgcnRocmhoIHRyIGhydCBocnQgcmh0ZAIGD2QWDgIDD2QWBAIBDxYCHwEFWjxhYmJyIGNsYXNzPSJ0aW1lYWdvIiB0aXRsZT0iMjAxMS0wNC0yMlQwMDozOTozNC45NDAwMDAwIj4yMiBBcHJpbCAyMDExIGF0IDAwOjM5OjM0PC9hYmJyPmQCAw8PFgYfAgURfi91c2Vycy9DaGVlc2VCb3kfBQUeVmlzaXQgdGhpcyBnYW1lIG1ha2VycyBwcm9maWxlHwEFCUNoZWVzZUJveWRkAgUPDxYEHwIFEX4vdXNlcnMvQ2hlZXNlQm95HwUFJkNoZWVzZUJveSBtYWtlcyBnYW1lcyB3aXRoIENvbnN0cnVjdCAyZBYCZg8PFgQfCAVJaHR0cDovL3d3dy5ncmF2YXRhci5jb20vYXZhdGFyL2ZjMjE2Nzc4ZjYzOGM4N2FmODZhNjI0MWNhMzZiM2EyP3I9cGcmcz04MB8FBRRDaGVlc2VCb3kncyBHcmF2YXRhcmRkAgcPDxYGHwYFEHMgY29tbWVudC1yZXBvcnQfBQUQUmVwb3J0IHRoaXMgcG9zdB8HAgJkZAIJDw8WBh8GBRBzIGNvbW1lbnQtZGVsZXRlHwUFEERlbGV0ZSB0aGlzIHBvc3QfBwICZGQCCw8PFgYfBgUOcyBjb21tZW50LWVkaXQfBQUORWRpdCB0aGlzIHBvc3QfBwICZGQCDQ8PFgYfBgUPcyBjb21tZW50LXF1b3RlHwUFD1F1b3RlIHRoaXMgcG9zdB8HAgIWAh8DBQUjUG9zdGQCDw8WAh8BBTFMb3ZpbmcgdGhpcyBibG9nIHBvc3QgdGhhbmtzIGZvciBpdCwgKzEhICBHbCBsb2whZAIHD2QWDgIDDw8WBB8GBRljb21tZW50LWhlYWQgY2gtaGlnaGxpZ2h0HwcCAmQWBAIBDxYCHwEFWjxhYmJyIGNsYXNzPSJ0aW1lYWdvIiB0aXRsZT0iMjAxMS0wNC0yMlQwMDoxMzowNC44NTMwMDAwIj4yMiBBcHJpbCAyMDExIGF0IDAwOjEzOjA0PC9hYmJyPmQCAw8PFgYfAgULfi91c2Vycy9Ub20fBQUeVmlzaXQgdGhpcyBnYW1lIG1ha2VycyBwcm9maWxlHwEFA1RvbWRkAgUPDxYEHwIFC34vdXNlcnMvVG9tHwUFIFRvbSBtYWtlcyBnYW1lcyB3aXRoIENvbnN0cnVjdCAyZBYCZg8PFgQfCAVJaHR0cDovL3d3dy5ncmF2YXRhci5jb20vYXZhdGFyLzUyNzFkMzI4M2RiOTU3ZWYzYTg2NzYxZWQxNWMxNjk2P3I9cGcmcz04MB8FBQ5Ub20ncyBHcmF2YXRhcmRkAgcPDxYGHwYFEHMgY29tbWVudC1yZXBvcnQfBQUQUmVwb3J0IHRoaXMgcG9zdB8HAgJkZAIJDw8WBh8GBRBzIGNvbW1lbnQtZGVsZXRlHwUFEERlbGV0ZSB0aGlzIHBvc3QfBwICZGQCCw8PFgYfBgUOcyBjb21tZW50LWVkaXQfBQUORWRpdCB0aGlzIHBvc3QfBwICZGQCDQ8PFgYfBgUPcyBjb21tZW50LXF1b3RlHwUFD1F1b3RlIHRoaXMgcG9zdB8HAgIWAh8DBQUjUG9zdGQCDw8WAh8BBRdlZyBlICBnIGdlIGcgZyBnIGcgZyBlZ2QCCA9kFg4CAw8PFgQfBgUZY29tbWVudC1oZWFkIGNoLWhpZ2hsaWdodB8HAgJkFgQCAQ8WAh8BBVo8YWJiciBjbGFzcz0idGltZWFnbyIgdGl0bGU9IjIwMTEtMDQtMjFUMjM6MzA6NTAuNjMzMDAwMCI+MjEgQXByaWwgMjAxMSBhdCAyMzozMDo1MDwvYWJicj5kAgMPDxYGHwIFC34vdXNlcnMvVG9tHwUFHlZpc2l0IHRoaXMgZ2FtZSBtYWtlcnMgcHJvZmlsZR8BBQNUb21kZAIFDw8WBB8CBQt+L3VzZXJzL1RvbR8FBSBUb20gbWFrZXMgZ2FtZXMgd2l0aCBDb25zdHJ1Y3QgMmQWAmYPDxYEHwgFSWh0dHA6Ly93d3cuZ3JhdmF0YXIuY29tL2F2YXRhci81MjcxZDMyODNkYjk1N2VmM2E4Njc2MWVkMTVjMTY5Nj9yPXBnJnM9ODAfBQUOVG9tJ3MgR3JhdmF0YXJkZAIHDw8WBh8GBRBzIGNvbW1lbnQtcmVwb3J0HwUFEFJlcG9ydCB0aGlzIHBvc3QfBwICZGQCCQ8PFgYfBgUQcyBjb21tZW50LWRlbGV0ZR8FBRBEZWxldGUgdGhpcyBwb3N0HwcCAmRkAgsPDxYGHwYFDnMgY29tbWVudC1lZGl0HwUFDkVkaXQgdGhpcyBwb3N0HwcCAmRkAg0PDxYGHwYFD3MgY29tbWVudC1xdW90ZR8FBQ9RdW90ZSB0aGlzIHBvc3QfBwICFgIfAwUFI1Bvc3RkAg8PFgIfAQUcT2sgbmljZSBvbmUgOi0pIExvdmluZyB0aGlzIWQCCQ9kFg4CAw8PFgQfBgUZY29tbWVudC1oZWFkIGNoLWhpZ2hsaWdodB8HAgJkFgQCAQ8WAh8BBVo8YWJiciBjbGFzcz0idGltZWFnbyIgdGl0bGU9IjIwMTEtMDQtMjBUMDA6MDE6NDcuNjY3MDAwMCI+MjAgQXByaWwgMjAxMSBhdCAwMDowMTo0NzwvYWJicj5kAgMPDxYGHwIFC34vdXNlcnMvVG9tHwUFHlZpc2l0IHRoaXMgZ2FtZSBtYWtlcnMgcHJvZmlsZR8BBQNUb21kZAIFDw8WBB8CBQt+L3VzZXJzL1RvbR8FBSBUb20gbWFrZXMgZ2FtZXMgd2l0aCBDb25zdHJ1Y3QgMmQWAmYPDxYEHwgFSWh0dHA6Ly93d3cuZ3JhdmF0YXIuY29tL2F2YXRhci81MjcxZDMyODNkYjk1N2VmM2E4Njc2MWVkMTVjMTY5Nj9yPXBnJnM9ODAfBQUOVG9tJ3MgR3JhdmF0YXJkZAIHDw8WBh8GBRBzIGNvbW1lbnQtcmVwb3J0HwUFEFJlcG9ydCB0aGlzIHBvc3QfBwICZGQCCQ8PFgYfBgUQcyBjb21tZW50LWRlbGV0ZR8FBRBEZWxldGUgdGhpcyBwb3N0HwcCAmRkAgsPDxYGHwYFDnMgY29tbWVudC1lZGl0HwUFDkVkaXQgdGhpcyBwb3N0HwcCAmRkAg0PDxYGHwYFD3MgY29tbWVudC1xdW90ZR8FBQ9RdW90ZSB0aGlzIHBvc3QfBwICFgIfAwUFI1Bvc3RkAg8PFgIfAQUgcGlsbHV1w7rDuiB0dCB0IGggdGggdGggdGggdGggdGhkAgYPZBYCAgEPDxYCHglNYXhMZW5ndGgC9ANkZAIIDw8WAh8AaGRkZAx0/0RvMYX4SKMMjV5pXc+cjNqDEEepI0JWzIxpxOzG" />
This represents ~50% of the entire size of the page.
Why does it do this, why so long? Can I do anything about it? It's bad for mobile users.
What is this view state anyway and how to mitigate its size
In Asp.net WebForms every control saves its state because HTTP protocol is stateless and Asp.net WebForms pages bypass that by saving every control's state in this Base 64 encoded string. This is the only way for Asp.net framework to know whether some control's value has changed or not. But... This automatically means that static controls that don't get POSTed back to server (like label for instance) don't need to save their state. You can always set their EnableViewState="false".
Unfortunately this can't be set without any other code changes on other controls, that do get POSTed back (every server-side control that renders some sort of an input in HTML). This basically means that setting EnableViewState="false" on page level (within #Page directive) will have consequences that are seen as controls loosing their values, controls not firing certain events etc.
So, the more server-side controls you have the larger it will get (without turning it off on certain controls).
But I wouldn't worry if its size is 10k. That will go back and forth rather fast and painless. You will have problems when it gets much larger. I once worked on a project and we had an issue with a certain page (done by less experienced developer) where view state grew over 1MB. Imagine that. What a slowdown!
How to turn it off completely on page level
When you turn view state off on page level you have to be aware that certain controls that were loaded (or better said data bound) in on of your page's events, will have to be reloaded each time your page gets POSTed back at server. Otherwise they will show up as empty when your page gets back to the client.
Your server controls are filling the ViewState with data they will need on postback. If your page does not postback you can just disable the ViewState for the page.
To disable ViewState for the page you can just add EnableViewState="false" to the #Page directive. Please be aware you should only use this as a solution if you are 100% sure the page does not postback.
You also might want to check this MSDN article to get a better idea of what the ViewState does.
Disable viewstate for static controls, like a gridview.
Check out this question for more info:
If you are concerned about the viewstate on the client side, then think about storing it on the server side. Perhaps in a session variable. Take a look at this article as there is statistical comparison given. Download the solution and check out how to store it on the server side.
An Analysis of Keeping ViewState out of the Page
This article explained it neatly to me in the past: Taking a Bite Out of ASP.NET ViewState.
Basically viewstate's on by default and, depending on which controls you use, it can get out of hand pretty fast. Especially data controls like the gridview are responsible for massive injection of viewstate. You can disable that on a per control basis by setting the EnableViewState property to false. Be careful however as taking out viewstate might also take out functionality of the controls. So do it one by one and test test test.
Another way, and likely better for mobile, is to make use of ASP.NET MVC instead which doesn't have to deal with automatic viewstate injection.
I'm retro-fitting a .aspx page with AJAX functionality (using VB, not C#). The codebehind populates the page with data pulled from a web-service. The page has two panels that are populted (with different data, of course) in this way. On a full page refresh, one or both panels might need to be populated. But populating Panel 2 can take a long time, and I need to be able to update panel 1 without refreshing Panel 2. Hence the need for AJAX (right?)
The solution I've come up with still has the old .aspx page with .aspx.vb codebehind, but introduces a Generic Handler (.ashx) page into the mix. Those first two components do the work on the user's first visit or on a full page refresh, but when AJAX is invoked, the request is handled by the .ashx page.
First question: Is this sound architecture? I haven't found a situation online quite like mine. Originally, I wanted to make the .aspx page into the AJAX handler by having the codebehind implement IHttpRequest, and then providing "ProcessRequest" and "IsReusable" methods, but I found I couldn't separate a regular visit to the page from an AJAX request, so my AJAX handlers took over even on the first visit to the page. Second question: Am I right to think that this approach (making the .aspx page do double-duty as the AJAX handler) will never work? Is it impossible to tell whether we're getting a full-page request or a partial-page (AJAX) request?
If the architecture is good, then I need to dynamically generate a lot of HTML in the .ashx file, right? If that is right, should I send HTML back to the client, or should I encode it in some way? I've heard of JSON encryption, but haven't figured out how to use it yet. So, Third question: Is "context.Response.Write" the only pipeline for sending data back to the client? And, if so, should I send back HTML or some kind of JSON-encoded objects?
Thanks in advance.
It sounds as if the page requires some AJAX functionality added to the UI.
Suggest using an UpdatePanel for each web form element that needs to have AJAXy refresh
functionality. That'll save you from having to refactor a bunch of code, and introduce a whole lot of HTML creation on your .ashx.
It'll be more maintainable over the long run, and require a shorter development cycle.
As pointed out by others, UpdatePanel would be a easier way - but you need to use multiple update panels with UpdateMode property set as conditional. Then you can trigger the update-panel refresh using any button on the page (see AsyncPostBackTrigger) or even using java-script (see this & this). On the server side, you may decide what has triggered the partial post-back and act accordingly by bypassing certain code if not needed.
You can also go with your approach - trick here is to capture the page output using HttpServerUtility.Execute in your ashx and write it back into the response (see this article where this trick has been used to capture user control output). Only limitation with this approach is that you can only simulate GET requests to your page and so you may have to change your page to accept parameters via query string. Personally, I will suggest that you create a user control that accept parameters via method/properties and will generate necessary output and then use the control on your page and in ashx (by dynmaically loading it in a temperory page - see this article).
EDIT: I am using jquery to illustrate how to do it from grid-row-view.
$(document).ready(function() {
$("tr.ajax-grid-row").click(function() {
$("#hidden-field-id").val($(this).find(".row-id").val()); // fill hidden filed
$("#hidden-button-id").click(); // simulate button click
});
});
You can place above script in the head element in markup - it is assuming that you have decorated each grid-row-view with css class "ajax-grid-row" and each row will have hidden field decorated with css class "row-id" to store row identifier or the value that you want to pass to server for that row. You can also use cell (but then you need to use innerHTML to get the value per row). "hidden-field-id" and "hidden-button-id" are client ids for hidden field and submit button - you should use Control.ClientID to get actual control ids if those are server controls.
JSON is not for that purpose, it is to pass objects serialized with a nice light weight notation, is you need to stream dinamically generated html using ashx, response.Write is what you have. You may want to take a look at MVC
Or you could use jquery if it's just html, the simpliest would be the load function, or you can look into Ajax with jquery. Since the ashx can be served as any resource it can be used in the load function.
I agree with #p.campbell and #R0MANARMY here. UpdatePanel could be the easiest approach here.
But then like me, if you don't want to go the UpdatePanel route, I don't see anything wrong with your approach. However, generating the html dynamically (entirely) at the back end is not a route I'll personally prefer (for the maintainence reasons). I'd rather prefer implementing a solution that will keep the design separate from the data.
I have a page which contains a user control. The structure of the page is as shown below:
Incase your not able to see the above image, please check it at http://i54.tinypic.com/2r4id5f.jpg Now, apart from the contents of the UserControl, I'd like to cache the entire page. I tried using the OutputCache attribute in the .aspx page, however it caches the contents of the UserControl as well.
Kindly let me know how will I be able to cache the contents of the page except that of the user control.
Thanks in advance.
I think you can use the asp.net Substitution control to achieve this. Here is a link to ScottGu walking through an example.
The basic idea is that you cache you whole page as per usual, but mark parts for substitution that can be replaced for each request.
I think you are looking for VaryByControl. Also check out this post on fragment caching
Look at using substitutions.
This should help
However, the snag is, since substitution is done outside of the Page lifecycle, you can't render a user control for your substitution. You have to write a method that returns a string for the substitution. But this may work for you.
Have you tried adding the #OutputCache to both the usercontrol and the page but the usercontrol set the varyByParam="qsvalue;postvalue" where qsvalue is a generated query string you make random for every call of the page and postvalue is the same for postback.
The user control will still get cached, but in theory it should never get a chache hit as the qsvalue/postvalue is always different from that cached. It may not scale well - best set duration to the minimum as well, to prevent large numbers of them building up in the cache.
I'm really new to asp.net and have a couple of issues I'm trying to get fixed. I have some programming experience, but it is not asp.net. However, I've been able to follow the code enough to make other changes in the code to fix other issues.
The first is this:
I'm working with a form that has a calculate amount method that gets called when the user inputs a value in an amount text box. The same method gets called when the next control, number of payments, has a value.
So in the two controls:
onTextChanged="ctrlName_textChanged"
Then in the code behind, the textchanged method does:
calculateAmount();
The problem is after the amount is calculated and returns, the focus seems to get reset and the user has to tab all the way back through the form to the place they were.
The textboxes in question are in a panel that starts out hidden and is made visible conditionally.
My apologies if I have not used the proper .net terminology.
It looks like the same issue may be causing my second problem. When the user types in an amount and then tabs and quickly adds the number of payments, you can see the amount get calculated correctly and very shortly displays the proper total in the total amount text box. However, even though it shows for that short time, the tab order again gets reset as well as the total amount value.
I've looked at different methods to try and fix the focus issue.
In the textchanged method, I tried using something like:
Session["myval"] = "someval";
Then tried to check against that in Page_Load with something like:
if(Session["myval"] != null) {
this.NextControl_Name.Focus();
}
but it didn't ever work correctly.
I also tried to set a cookie in that same textchanged method using something like this:
Response.Cookies["myval"].Value = "somevalue";
Then tried to check that in Page_Load using something like the previous if block above but using Request.Cookies["myval"] as the source.
Is there a good reference with some really clear code samples I can look at for this type of implementation?
Thank you in advance,
C.
Sounds like you have a postback problem...
Remember that the web is stateless. This means that when you have a web page rendered out in .NET and you attach an event that executes serverside code... it does an HTTP POST back to the server which is effectively a new page request. The Page_Load method will fire again as well as your bound event. So your onTextChanged event is firing a new request back to the server. This is why you see the focus reset and why when you tab quickly, the value seems to disappear magically.
You can do one of several things, you can implement the UpdatePanel in the AjaxControlToolkit
http://www.asp.net/ajax/ajaxcontroltoolkit/samples/
you can use PageMethods and do your validation with javascript and jQuery (or other js library)
see page method info http://www.geekzilla.co.uk/View30F417D1-8E5B-4C03-99EB-379F167F26B6.htm
Hope this helps
I think I summed up the question in the title. Here is some further elaboration...
I have a web user control that is used in multiple places, sometimes more than once on a given page.
The web user control has a specific set of JavaScript functions (mostly jQuery code) that are containted within *.js files and automatically inserted into page headers.
However, when I want to use the control more than once on a page, the *.js files are included 'n' number of times and, rightly so, the browser gets confused as to which control it's meant to be executing which function on.
What do I need to do in order to resolve this problem? I've been staring at this all day and I'm at a loss.
All comments greatly appreciated.
Jason
If the issue is simply that the same file is being embedded multiple times and causing conflict, look into using RegisterClientScriptInclude. If you use the same identifier for all of your calls to RegisterClientScriptInclude only one instance of that file will be embedded:
http://msdn.microsoft.com/en-us/library/2552td66.aspx
However, if the issue is that your methods are being called but they don't know what controls on the page to operate on then you need to figure out how to provide your JS some context. Define a JavaScript object that represents your control on the client-side, and on the server-side emit the call that will instantiate it with the client IDs of the controls you'll be operating on.
We are using CustomValidator to validate User Control. The control works fine until you drop two instances of the Control on the same page, since they reference the exact same JavaScript functions, only one control works. Work around, we appended JavaScript function name with control id.
Validate_SAPDepartment<% =ControlId %>(oSrc, args) {...}
In codebehind, we assinged ClientValidationFunction
CustomValidator1.ClientValidationFunction = "Validate_SAPDepartment" + this.ControlId
This may not be the right approach but it works.
I've had this situation before. You register a separate JavaScript file with the page using the ScriptManager. You can stream this as a resource file embedded into the dll if you wish.
Then you only call into the functions from your control.
Otherwise a completely separate jquery file may also work.