Pass data to server side from Javascript code - c#

I'm trying to send data from client-side to server-side (asp.net c#), if you really want to know, I want to send the window.name property.
First I thought about having a asp:HiddenField and on the OnSubmit event have some JS write the value in the hidden field. The only problem is that I can access the hidden field value (according to this) only from PreLoad event to PreRenderComplete event. The project that I'm working on has a lot of code in the OnInit event, and unfortunately I cannot move it and I need to use the window.name value here.
The other ideas that I have is to add a custom HTTP Header windowId or on the OnSubmit event have a JS that appends a parameter to the document.location.href.
I managed to write to the header from JS with the XMLHttpRequest setRequestHeader, but, maybe I did something wrong in my implementation, this generates 2 requests, the first one is the normal, expected one(clicking a button/link ...) and the second is from the XMLHttpRequest. I find this behavior very unnatural. Do you have any sugestions? (see code snippet below). I do not what to use AJAX.
var oReq = new window.XMLHttpRequest;
oReq.open('POST', document.location, false);
oReq.setRequestHeader("windowId", window.name);
oReq.send(null);
For the OnSubmit hook idea, i haven't spent to much time on it, but i think I have to append the # character before i append my windowId parameter with it's value, so that the page doesn't reload. I might be wrong about this. Any way, I have to remove this from the URL after I take the value, so that the user doesn't see the nasty URL. Do you have any sugestions?
Ok so what are your ideas?
Thank you for reading all my blabbering, and thank you, in advance, for you answers.

I would recommend the <asp:HiddenField /> (e.g., <asp:HiddenField ID="hfWindowName" runat="server" />. In OnInit you can still access its value by using Request.Form:
string windowName = Request.Form(hfWindowName.UniqueID);

Related

asp:HiddenField being cached server-side somewhere?

I have two ASPX pages; they use the same DLL and class, so the first line of each file looks like:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="CustomPage.aspx.cs" Inherits="CustomPageCode.CustomPage" %>
(maybe this is bad form to have two *.aspx pages sharing the same codebehind, but I don't want to have two separate classes with identical code)
I'm 'configuring' each page through a hidden field --
Page1.aspx has the line:
<asp:HiddenField ID="DepartmentName" value="DepartmentOne" runat="server" />
and Page2.aspx has the line:
<asp:HiddenField ID="DepartmentName" value="DepartmentTwo" runat="server" />
My CodeBehind reads DepartmentName.Value to do a bunch of codebehind things, like SQL queries, based on the value of the HiddenField specific to each department, and also Javascript reads that value to do department-specific things as well. I'm doing it this way to simplify configuring each page -- the way the page is configured is right there in the ASPX page and the same value is visible to both ASPX and Javascript.
However, if either page does a POST event -- now DepartmentName.Value ONLY returns the value from the page that did the POST for any page with the same codebehind. Page1.ASPX, even though the asp:HiddenField value in the source is still clearly "DepartmentOne", if Page2.ASPX did the POST, DepartmentName.Value will be "DepartmentTwo" regardless of which page is opened.
The funky thing is: if I open the same page in Chrome, Page One will still have Page Two's DepartmentName.Value, even if the POST event never occurred in Chrome; clearing the IE cache doesn't fix it either. This is definitely something happening on the server side, getting cached somewhere. An IIS reset resolves it.
Google has told me that ASP.NET caches a bunch of things from a POST event but doesn't exactly say how it's handled, or how to enable/disable it, or which of the many cache locations it is located in, and many examples look like I'd have to specifically tell it to start caching things in a persistent way. The closest thing I've found is ModelState.Clear(); in a !IsPostBack at the beginning of the Page_Load, but that doesn't resolve it, I'm not using MVC in my code as far as I know.
So, my question is, how do I force that the GET uses the hidden value in the source code, and not some cached value from an old POST event?
It's probably ViewState, but I'd have to see more of your code for this to be more than a wild guess. I do see this:
I don't want to have two separate classes with identical code)
Yep, that's a good thing. But it sounds like maybe you have too much code in the page class itself that should be moved to a separate utility class, where two separate pages can now share that same utility code. Alternatively, you want a single Department.aspx page that takes a URL argument, like this: /Department.aspx?deptid=Department1 or /Department.aspx?deptID=Department2
Then key off of the url argument, rather than a hidden field. If you don't like the ugly URL, you can use routing to get prettier URLs like this: /Departments/Department1 or /Departmennts/Department2
I discovered my problem:
After wrestling with ViewState, it turns out my problem wasn't hidden fields being cached, it was what was being done with the hidden fields.
At the beginning of my class, I have a variable:
public static Dictionary<string, string> ThisDictionary = new Dictionary<string, string>();
that my code uses ThisDictionary.Add() to add values from ASPX hidden fields to -- but I never declared ThisDictionary as 'new' in my actual function, so every time I added an element to the Dictionary of hidden fields, it was persistent across multiple pages using the same class.
So, when I load my values from what I think is the hidden field, the codebehind is reading the hidden field correctly, but when it takes action in C#, it is using the data in the Dictionary with a bunch of other pages' data in it, hence the appearance that hidden field values are being cached somewhere.
By adding a statement to declare it as a new Dictionary<string,string>() at the beginning of my Page_Load function, it now wipes the dictionary clean with each page load and now it's behaving how I would expect, containing only values from the hidden fields on the particular page.
(I acknowledge what I should probably do is have a separate class with these variables in it, rather than lumping it all into the main ASPX class that gets called when the page loads. Something for the next version)

WebBrowser and javascript

I am working with a website that has javascript that does some changes on the page load. However, when I load the page and handle the DocumentCompleted event, this change isn't there. If I then continue paste the DocumentCompleted event, I can see the change happen. However I need this change to happen during DocumentCompleted so I can check some things.
Is there an other event I can subscribe to, or a way to cause the webBrowser to do all the javscript on page?
Edit: This is what I am talking about.
I loaded a sample page just to show you, and clicked the submit button with all fields empty to generate an the error.
Here is the result:
http://s8.postimage.org/zfv6stcar/sfsdfsdfds.jpg
Now if I take the HTML at that precise moment from that WebBrowser control, and render it somewhere else, those errors go away. The same thing happens when the server sends back those errors. If I handle the DocumentCompleted event and take the html, it isnt there. But after the event, it shows up in the control.
Hope you understand, it's hard to explain.
The problem seems to be that the DocumentCompleted event is being fired before the javascript. You should do some reading on how client side/server side things function.
One option is to make a separate method for the DocumentCompleted event and call it form the javascript after it has been completed. This would get the sequencing of these events working properly, but is not very ideal.
Alternatively, you could call the javascript code at the beginning of your DocumentCompleted event. The link below gives a pretty good explanation of how to go about that.
http://forums.asp.net/t/1117189.aspx/1
Personally, I would avoid using javascript and do the validation on the client side .NET, but I don't know enough about the website to really say.
EDIT:
This should be the script you are looking for. Alternatively here is a thread related to your issue. Sorry I don't have the exact code as I don't have a project to test this on.
http://msdn.microsoft.com/en-us/library/system.web.ui.clientscriptmanager.registerstartupscript.aspx
Calling JavaScript Function From CodeBehind
RE-EDIT:
What is happening on the link you provided in the comments, is that each textbox is calling some javascript as well as the submit button. The best way to examine this is using the "Inspect Element" in the right-click menu on Google Chrome. For example, doing this on the textbox would show that it is registered with a few events:
onfocus="$('f_tip_Username').style.display = 'inline'"
onblur="$('f_tip_Username').style.display = 'none'"
onchange="$('f_err_Username').style.display = 'none'"
The first the element with the ID 'f_tip_Username', sets the display style of that element to inline (visible).
The submit button calls the following:
onclick="return o_edit_profile_form.validate()"
Doing a find on "o_edit_profile_form" in the source code, you can find the exact javascript location that is being called. Enjoy!
FINAL EDIT (hopefully?):
Follow these steps: go to your site, right click and go view source. Do a find for "f_tip_Username". This is the ID of one of the div tags being used. The third entry of it, should be a "div tag" that is used under the first textbox to warn of "min 3 characters".
You'll notice above that in the code is a input type "text" with the Name "Username". Notice the three events it has registered in it:
onfocus="$('f_tip_Username').style.display = 'inline'"
onblur="$('f_tip_Username').style.display = 'none'"
onchange="$('f_err_Username').style.display = 'none'"
These either hide or make visible, the div tag we found (f_tip_username) and also a separate div tag (f_err_Username) which is the error message div tag. Let me know if you are not able to find these in the source. Follow the steps I provided and you will find it in the "view source" OR in the DocumentText.

calling a javascript function in C#

Hi i wanted to show or hide duplicate records according to query. So, I need to know how to call the javascript function from C# codebehind.
<a onclick="Grid1.insertRecord(); return false;" id="a2" href="javascript:">Save</a>
When I click save i need to show a popup which i have written in javascript.
if (!exist)//exists is the query
{
System.Web.UI.Control my = FindControl("a2");
a2.Attributes.Add("onclick", "retrun HideDuplicate()");
This line returns an error saying "a2 doesnot exist in current context."
Why not use an asp.net LinkButton? It has a server side Click event and is accessible from c# code-behind.
The basic <a> tag is not turned into a control by asp.net unless you add a runat="server" to it. Its then turned into a HtmlGenericControl.
<a onclick="Grid1.insertRecord(); return false;" id="a2" href="#" runat="server">Save</a>
This might work for you - its not clear if you have more than one of these links on the page (such as in a row of a gridview?) or if its just on there once.
Also the way you have used javascript is not following best practices but thats a discussion for another day :)
MSDN documentation for programatic creation of client side callbacks without postback with an example where the code behind is in C# might give a good overview of how it is supposed to work in general.
In your case, the corresponding code-behind should implement the interface 'ICallbackEventHandler' and the two methods it describes. In addition, you would need two more client side Javascript functions to prepare and handle the callback, besides the executor/invoker (in your case, a 'save' method). However one of the additional two Javascript functions could be registered in the codebehind, as the example shows.

Run javascript function after Server-Side validation is complete

Ok, I've got a lightbox with a small form (2 fields) in it, inside an UpdatePanel, and I want to close this lightbox (must be done via javascript) when the 'Save' button is pressed.
However, there is a need to have a server-side CustomValidator on the page, and I only want to close the lightbox if this returns as valid.
Does anyone know a way to trigger javascript (or jQuery) code from a server-side validator?
You can add a little snippet of code using the ScriptManager to execute after the response comes back to the UpdatePanel.
if (Page.IsValid){
ScriptManager.RegisterStartupScript(
customValidator1,
typeof(MyPageClass),
"closeBox",
"myLightBoxVariableOnThePage.close()",
true);
}
When that server side validator runs, it will send a whole new page to the browser. Anything that was shown in the browser before was destroyed, including any state kept in your javascript. If new page bears a strong resemblance to the old page, you should consider this a happy coincidence.
Therefore, the thing to do here is rather than executing a javascript function, have your CustomValidator make the correct changes to the page on success so that it's rendered to the browser correctly in the first place.

user control event handler lost on postback

I have a menu usercontrol called LeftMenu that has a bulletedlist of linkitems. It's on the ascx page as such:
<asp:BulletedList ID="PublisherList" DisplayMode="LinkButton" OnClick="PublisherList_Click" cssClass="Menu" runat="server"></asp:BulletedList>
I databind the list in the page_load under if(!isPostBack)
I'm having an issue on a page that loads the control. When the page first loads, the event handler fires. However, when the page posts back it no longer fires and in IE8, when I'm debugging, I get "Microsoft JScript runtime error: Object expected" in Visual Studio pointing at "__doPostBack('LeftMenu$PublisherList','0')." In FF I don't get the error, but nothing happens. I'm not loading the control dynamically, it's loaded on the aspx page using:
<%# Register TagPrefix="Standards" TagName="LeftMenu" Src="LeftMenu.ascx" %>
<Standards:LeftMenu ID="LeftMenu" runat="server"/>
Any ideas of where I'm losing the event handler?
I just realized this is happening on another user control I have as well. A text box and a button and I'm using the default button to make sure pressing the enter key uses that button. .Net converts that in the html to:
<div id="SearchBarInclude_SearchBar" onkeypress="javascript:return WebForm_FireDefaultButton(event, 'SearchBarInclude_QuickSearchButton')">
so as soon as i enter a key in the box I get a javascript error at the line saying "object expected." It seems like the two issues are related.
Edit Again: I think I need to clarify. It's not that I'm clicking on the menu item and it can't find the selected item on postback. I have this search page with the left navigation on it and then the main content of the page is something that causes a postback. Everything is fine with this postback. Once that page has been posted back, now if I click on the bulleted list in the left navigation I get a javascript error and it fails. The page_init for the LeftMenu control is never called.
It sounds like you might be losing the click because you are not DataBinding the list on PostBack. Therefore, the post back is trying to refer to a control (a specific bulleted list item) that does not exist.
You should try binding the list again on PostBack just to see if that fixes your issue. BUT, what should REALLY happen is that the LeftMenu and the BulletedList should store their information into ViewState so that you can ensure that the data that was shown to the user on their initial page load is the same data that the PostBack is processing and working with.
If you have EnableViewState=true for your UserControl and all controls within it, everything should work fine. With ViewState enabled, ASP will reinflate your controls from ViewState after Init has fired. This means that the postback event arg (which points to an index in your control list) will still find the control in that list position. Otherwise the list is empty on postback.
However, ViewState is the work of the devil and was designed simply to foster the illusion that you are working in a stateful environment. It is okay to use it for small amounts of data but typically not advisable for templated controls like repeaters and lists because you have no idea how much data is going to be created in ViewState.
If you are dealing with static, or relatively static data, store it in the application cache and rebind your lists in Page.Init every time (note that it has to be in Init because post-init is when ASP rebinds from ViewState; if you get in there first, your data will be used instead).
If you are dealing with volatile data, you have a problem because the data you rebind must be exactly the same as the original page request, otherwise the postback events will be firing against the wrong rows. In that case you need to either store your initial data in Session or you simply store the list of rows ids (in a hidden variable or Session) and you recreate the data to bind against from the ids each time.
An even better solution is to not use postback events at all. Try to turn all your events into GETs that have an ID on the query string. You can still create the list using binding the first time through the page (as you are currently doing), and you can even GET the same page with a new ID.
If you need to keep state on the same page but need to respond to the user changing a radio button selection (or something else), think about using Ajax calls to update the screen. You also do that with an ID that you pass to the Ajax call.
In general, the more you move from using stateful ASP, the lighter and more responsive your pages will become. You will also be in a better position to move to stateless MVC if necessary. You will also save lots of time lost to debugging obscure problems because ViewState is not available when you need it to be.
The best analysis of ViewState I've read is in the link below. If you fully understand how it works, you can continue to use it without necessarily incurring the costs.
http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/truly-understanding-viewstate.aspx
It's possible that this might be javascript related, and that a script that is loading earlier in the page is throwing an error and causing the page to not be loaded properly.
Are your usercontrols loading any javascript onto the page? Can you check for javascript errors on the initial load of the page?
I moved the code into an existing project we have and for some strange reason, I stopped getting the javascript errors and instead got:
"Invalid postback or callback argument. Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%# Page EnableEventValidation="true" %> in a page.
For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation."
I haven't quite figured out where I'm supposed to put the register event validation with a user control, but in the mean time I just set enableeventvalidation=false and it seems to work now.
It looks like the doPostBack function is missing since its arguments are literals so they couldn't be the cause. Is that one of your own functions or did you mean to call the ASP __doPostBack function?
Have a look at the Firefox error console or allow script debugging in IE and see exactly what object can't be found. Even better, download Firebug and debug it.
I had a similar issue. It turned out that Akamai was modifying the user-agent string because an setting was being applied that was not needed.
This meant that some .NET controls did not render __doPostBack code properly. This issue has been blogged here.

Categories