I need to access the user controls on a web page from a shared function decorated with a WebMethod. That function is being called from jQuery AJAX. When I try I can the error "Cannot refer to an instance of a class from within a shared method or shared member initializer without an explicit instance of the class".
Snippet of the page. The ajax method is calling the ASP.NET shared function from the page code behind. That function is trying to change the value for TextBox1 on the page.
<form id="form1" runat="server">
<asp:TextBox ID="TextBox1" runat="server">Default Value</asp:TextBox>
</form>
<script type="text/javascript">
$(document).ready(function () {
Handsontable.dom.addEvent(vBUTTONPOST2, 'click', function () {
$.ajax({
type: "POST",
url: "test.aspx/TestFunctionShared",
data: somedata,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (MyResponse) {
var vMYDATA;
vMYDATA = MyResponse.d
vMYDATA = JSON.stringify(vMYDATA);
}
});
});
});
</script>
Snippet of the page code behind. The shared function is trying to set the value of the Page's textbox.
Partial Class test
Inherits System.Web.UI.Page
<System.Web.Services.WebMethod()>
Public Shared Function TestFunctionShared() As String
TextBox1.Text = "hello"
End Function
End Class
A web method is only like some sub call, and it is a 100% stand alone routine that you call.
The whole idea behind a web method is the browser page (on your desktop) is not posted back to the server. Since the page is not posted back, then a web method has no use of any controls on the web page.
So, you have to keep in mind the so called "round trip" or what is often called the page life cycle.
Remember, the web server does NOT keep in memory a copy of that web page. Since the web server can process any web page, not just YOUR web page. So, you have to think of the web server as ONE computer. Thus, unlike a desktop program, you have to think of the web page (and code) starting 100% from scratch EACH time you press a button and post-back a page.
If you don't post back the page, then code behind can't modify the controls, since the copy of the browser page and controls are still sitting on the user’s desktop.
So, the web page life cycle works and looks like this:
YOU DO NOT have this:
And you not even have this:
So, when you click on a button, or do a post-back, then you get this:
Our web page is sent up to the server. You now have this:
So NOW your page is sitting on the server.
NOW an instance of the page class is created, and your code behind starts running.
Your code behind can modify controls (even controls to be visible or not), but the page is NOT interacting with the user - ONLY code can MODIFY the web page. So, one change, or MANY changes to the web page can occur, but AS YOU update things like a text box etc., the user does NOT see these changes just yet. So, you can't say run a loop to flash a text box on and off - since the changes are occurring on the server - the client-side browser does not have the web page anymore!!!
So, all the user sees is the browser "spinner" or "wait" icon in the upper left of the browser.
When all, and I mean 100% of the code behind is done running, then and ONLY then is the web page that been processed and changed is sent back to the client-side browser.
VERY important: The server-side class instance and code is TOSSED OUT - DOES NOT exist!!! Your server-side page class is disposed - removed from memory, and the web page code behind does NOT exist anymore. And that means ALL code variables (server side) do NOT exist anymore! They are gone! Tossed out!
So, page travels back to the client side, is re-displayed, JavaScript is loaded, and THEN JavaScript starts running.
Thus this:
So, a web method can't change any controls, since those controls and markup is still sitting on the user's desktop.
So, there are several solutions. Most common is to then have your client-side JavaScript code update the control(s) in question AFTER the web method is called.
Say I have a simple temperature converter. And say we don't want a page post back (that slow full page life cycle).
So, we could drop in 2 text boxes and some markup like this:
<h3>Enter Fahrenheit</h3>
<asp:TextBox ID="txtF" runat="server" ClientIDMode="Static"></asp:TextBox>
<br />
<asp:Button ID="cmdConvert" runat="server" Text="Convert to Celsius"
CssClass="btn"
OnClientClick="myconvert();return false;"
/>
<br />
<h3>Celsius Resultt</h3>
<asp:TextBox ID="txtC" runat="server" ClientIDMode="Static"></asp:TextBox>
<script>
function myconvert() {
var myF = $('#txtF').val()
$.ajax({
url: "WebForm7.aspx/FtoC",
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({F : myF}),
success: function (data) {
$('#txtC').val(data.d);
},
failure: function (rData) {
alert("error " + rData.d);
}
});
}
</script>
So, to "modify" the 2nd text box? I can't use code behind, since we never post the page back to the server. So, we have the web method return the value, and then use client-side JavaScript code to update the results of that web method into the 2nd textbox.
Hence, the server-side code is this:
<WebMethod>
Public Shared Function FtoC(F As String)
Dim Ftemp As Single
Ftemp = Convert.ToSingle(F)
Dim Ctemp As Single
Ctemp = (Ftemp - 32) / 1.8
Return Ctemp.ToString("F2")
End Function
And thus, the result is this:
The other possible suggestion?
Consider using an update panel. An update panel does not do a full-page post back, and you not see a browser "spinner".
And keep in mind that if you use an update panel, then ONLY controls inside of the update panel can be updated by code behind.
So, an update panel is a "half way" solution. Kind of between a full-page post back, and no page post back (a web method).
So, we could use 100% server-side code, but if you try the following test code, note how you do not see a browser "spinner" or wait, and the results look much the same as the first example with a web method.
Keep in mind that an update panel DOES do a round trip, but ONLY part of the page is sent and refreshed. (and page load will still trigger each time).
So, using an update panel? (you have to drop in a Script manger into the page).
Hence, this would work, and no JavaScript code has to be written:
So, drop in an update panel, and then place all the markup and code and buttons you want to become a "ajax" post back.
thus this:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<h3>Enter Fahrenheit</h3>
<asp:TextBox ID="txtF" runat="server" ClientIDMode="Static"></asp:TextBox>
<br />
<br />
<asp:Button ID="cmdConvert" runat="server" Text="Convert to Celsius"
CssClass="btn"
OnClick="cmdConvert_Click" />
<br />
<h3>Celsius Resultt</h3>
<asp:TextBox ID="txtC" runat="server" ClientIDMode="Static"></asp:TextBox>
</ContentTemplate>
</asp:UpdatePanel>
And now our code behind click event becomes server-side code.
Protected Sub cmdConvert_Click(sender As Object, e As EventArgs)
Dim Ftemp As Single
Ftemp = Convert.ToSingle(txtF.Text)
Dim Ctemp As Single
Ctemp = (Ftemp - 32) / 1.8
txtC.Text = Ctemp.ToString("F2")
End Sub
So, from a user point of view, they will not see that a post-back has occurred.
And even the current scroll position of the browser does not change.
So, an update panel can save a LOT of work and eliminate a lot of JavaScript and web methods if you don't want a full-page post back.
A update panel still sends most of Viewstate, and is a "larger" payload then a web method, and they are slower, but for a lot of cases, a update panel allows you to write 100% server code, and the code behind can update any control placed inside of the update panel.
So, a update panel tends to be "less" of a page post back and cycle then a full page post back. However, these so called partial page post backs are certainly larger then a web method.