Force a postback inside a WebMethod - c#

I am using a 3rd party control for GIS map related functions.
I had the need to call a C# Method from within javascript. I chose to use PageMethods like this:
PageMethods.getFeature(x,y)
Works like a charm as long as you convert your method to a [WebMethod]
In this method I am passing in the coordinates of the mouse and it returns me map features. That I will highlight on the map.
From researching I found that you cant directly access the UI from inside a [WebMethod] so I decided to set a session variable and postback. On postback if the session variables exist I would make the necessary UI changes.
My WebMethod looks like this:
[WebMethod(EnableSession = true)]
public static void getFeature(float x, float y)
{...
some code in here.
}
Update
This is my jQUery:
<script>
$(document).ready(function (e) {
$(".MyMap").click(function (e) {
var posX = $(this).position().left;
var posY = $(this).position().top;
PageMethods.getFeature(e.pageX-posX, e.pageY-posY);
});
});
</script>
How do I force a postback inside of a WebMethod. Most of the ways I know to postback don't work.

Special Thanks to #BenRobinson for assisting me in the right direction. Here is what I came up with. I am posting this for other people who may make a similar mistake. The short answer is: **You Cant
My main issue was I was using a [WebMethod] so my c# code could be called from jQuery. This worked perfectly until I needed access to the UI. Well technically a 'WebMethod' is almost like calling a web service. You cant have a remote web service update the UI. What you can do is after your function in jQuery runs that calls the [WebMethod], is have it call a new page (window.location). That location can call the original page (in my case Default.aspx). I passed parameters in the request field that I needed to send to the UI, and I basically put code in that if on load you see a particular request variable then do something... It worked like a charm.
Here's a rough example:
In my jQuery page I did this (to navigate to a new page):
window.location.replace("ZoomAndCenter.aspx?x=" + (e.pageX - posX) + "&y=" + (e.pageY - posY))
Here is what my ZoomAndCenter.aspx looked like:
protected void Page_Load(object sender, EventArgs e)
{
int x = 0;
double y = 0;
x = Int32.Parse(Request["x"].ToString());
y = Double.Parse(Request["y"].ToString());
//Run some more code
Response.Redirect("Default.aspx?Param1=xxxx&Param2=xxxx");
//passed the params in the redirect.
}
Then in the Default.aspx
if(request["param1"] == "something")
{
//do something
}

Related

ASP.NET MVC controller method called via getJson not working on server

Obligatory "This works in my dev environment, but doesn't work on the server."
I have an ASP.NET 5 MVC project, using .NET Core, in which actions taken on a certain view trigger a "getJson" call in my javascript code, which in turn calls a function on the controller to obtain data from the server, in order to update the page without a postback.
When a valid entry is made in a textbox, this function is called in my javascript:
function getCustomerOptions(cn) {
$.getJSON('/Home/GetBillingCustomerByCustNum', { cust: cn }, function (data) {
// handle returned json data
}
}
... which calls function GetBillingCustomerByCustNum in my Home controller:
public async Task<JsonResult> GetBillingCustomerByCustNum(string cust)
{
var data = //[retrieve data from server thru repository function]
return Json(data);
}
In my dev environment, this works great. But after I publish the application to an IIS environment on a Windows Server 2016 machine, this fails. It seems that IIS is trying to call '/Home/GetBillingCustomerByCustNum' as though it were a view or a physical object, and so returns a 404 error.
I have tried altering my getJson controller call -- jquery function "getCustomerOptions" -- by adding
<%= Url.Content("~/") %>
so that the call becomes
$.getJSON('<%= Url.Content("~/") %>/Home/GetBillingCustomerByCustNum', { cust: cn }, function (data) { ...
but that still fails. According to the debugger console, the above url is being translated as
http://localhost/HC_RFQ/Home/%3C%=%20Url.Content(%22~/%22)%20%%3E/Home/GetBillingCustomerByCustNum?cust=[given value]
The only other step I could find suggested I prepare my url with an HTML helper, like so:
var url = '#Url.Content("~/Home/GetBillingCustomerByCustNum/")'
$.getJSON(url, { cust: cn }, function (data) {...
but of course that fails because HTML helpers don't work in separate javascript files. Var url is passed in as literally written.
Finally, I know this is not a case of my javascript files not being linked properly, because I can breakpoint my javascript in the debugger ahead of this failing call, and the breakpoints are hit at runtime.
What else can I try to fix this? Any advice is appreciated.
Have you tried a simple Home/GetBillingCustomerByCustNum, just without the starting /? From how you describe the error in production, that's basically a server issue when composing the final route to the controller.
Dropping the Home/ part works because you're calling that action from a view that resides on the same controller's folder path. Since you're using .NET Core, I suggest using the asp-action and asp-controller tag helpers as they let the server decide what's the actual route to the desired methods, even if you're POSTing or GETing without an actual postbacks. For example, this is what I do using javascript to call my methods on a form:
<form asp-controller="myController" asp-action="myAction">
and this is how I get my js code to retrive the corresponding url
let form = $(this).parents('form')[0];
let url = form.getAttribute('action');
the form doesn't have an actual submit button, so that the calls are all made from javascript.

Get Page control in a Method triggered by AJAX call

I call a method in a separate Class file that needs to update a label.
[WebMethod] //needed for the AJAX call
public static void MyClick(int postid, int userid) //must be static
{
Page page = new Page();
//Page page = HttpContext.Current.Handler as Page //Pass the Page but don't work
MyClass.MyMethod(postid, userid, page);
}
The method MyClick() is called from an asp.aspx file (With MasterPage), to a separate MyClass.cs file.
I am not being able to get the Control (Label) with FindControl(). My guess is the "Page" is not being passed correctly. For what i've seen in debug, "page" comes with many exceptions.
((Label)page.FindControl("ContentPlaceHolder1_lbl)).Text = "foo";
This is the sequence:
1) User clicks sort of a "Like" dynamically-created LinkButton
2) There is a JS listener that on click changes to "Dislike" (example) and does an AJAX POST to aspx page method MyClick() with parameters (postid, userid).
3) MyClick() calls MyMethod(postid, userid) that is in MyClass.cs
4) MyMethod() does some SQL (was working) and updates the label (AJAX call not working since MyMethod() tries to set label to "foo").
You're not passing the current page, you're creating a new one:
Page page = new Page();
You could just pass a reference to the current page:
MyClass.MyMethod(postid, userid, this);
(Though in order to do that your page method shouldn't be static. In fact, in order to reference anything on the page instance that method shouldn't be static. See edit below)
However, in general it's best practice not to have other components rely on your page elements. Only the page's code should know/care about the UI elements it owns.
Instead of having the method set the value, have the method compute and return the value and then have the page set it. Something like this:
var result = MyClass.MyMethod(postid, userid);
myLabel.Text = result;
That way the external component isn't tightly coupled to this specific page, can be re-used by other pages, etc.
Edit: What you're trying to do physically won't work in the framework you're using. AJAX-invoked web methods are static for a reason. They don't maintain page state. So in the context of that web method there is no page and there is no label. The AJAX call is a simple service which accepts values and returns a response.
So even if you could update a label server-side, that's not going to do anything client-side. Your client-side code needs to update the markup in the browser. To do that, the AJAX call should simply respond with the new value and the JavaScript code should use that returned value to update the page. Something like this:
[WebMethod]
public static string MyClick(int postid, int userid)
{
return MyClass.MyMethod(postid, userid);
}
As in the earlier part of this answer, that external component should simply calculate and respond with the new value. It should not be coupled to the page. This web method should result in the client-side code receiving the updated value. Then, however you manage that client-side (you have no client-side code in the question), you would update the page markup with that resulting value.

I have looked at calling c# through ajax, my implementation doesnt hit the c# method when I put a break point

My javascript to invoke the method in my c# class, the ajax call does get into success method but it does hit the c# method when I put in the break point. I tried changing the shoppingcart.aspx to shoppingcart.aspx.cs but still doesn’t hit the c# method.
<script type="text/javascript">
$('.removeCart').click(function (e) {
$.ajax({
type:"POST",
url: "ShoppingCart.aspx/deleteSelectedProduct/",
success: function () {
console.log("ITS GOING THROUH",e.target.dataset.removename);
},
error: function () {
}
});
});
</script>
my c# code
public void deleteSelectedProduct()
{
}
To troubleshoot
You should remove method name and put url of page as following
url: "ShoppingCart.aspx",
and put a break point on Page_load event if it hits the break point that means your url is fine now you can put complete url with method name.
url: "ShoppingCart.aspx/deleteSelectedProduct/",
Now you can check whats wrong with your method following are possible solutions
Your method deleteSelectedProduct should be static method
You'll need [WebMethod] decoration above your function deleteSelectedProduct
You'll need [WebMethod] decoration above your function in the aspx page.
I think you are missing starting / only. Correct the url like below:
url: "/ShoppingCart.aspx/deleteSelectedProduct/",
Give it try and let me know if it doesn't work.
The method you are trying to access using ajax call should be decorated with WebMethod attribute to enable ajax calling(#Dominic already suggested that, I am just describing it as a solution). It should be something like:
[System.Web.Services.WebMethod]
public void deleteSelectedProduct()
{
//implementation code
}
Or Include System.Web.Services as namespaces on top of the page and used directly WebMethod.
Cheers!!
You have to decorate the C# function with the WebMethod which will be in System.Web.Services.WebMethod.

Execute an ASP.net method from JavaScript method

I have a javascript method looks like this
JSMethod(JS_para_1,JS_para_2)
{
......
,,,,,
}
and I have an ASP.NET method like this
ASP_Net_Method(ASP_Para_1,ASP_Para_2)
{
....
,,,
}
Now I want to call this ASP_Net_Method from my JSMethod by passing some parameters over there..
Just to be clear:
Your javascript is executed by the user's browser on the user's laptop
Your ASP.NET method is executed on your server
So, what you probably want to do is to send a message from the browser to the server saying "Hey, run this method and give me the result back".
If you are doing traditional ASP.NET development (not ASP.NET MVC), I think the normal approach would be to create an ASPX page which, when requested, executes the method you want executed. Then, in your javascript you just need to request this page. To do this, you can use jQuery (either jQuery ajax, jQuery get or jQuery post).
You will need to download the jQuery library and include it in your page for this to work.
Give it a go and if you can't get it to work, come back for more specific advice.
EDIT: You can also take a look at ASP.NET AJAX. The home page has a lot of tutorials and videos.
What you really want to do is execute server-side code (sometimes called "Code-behind", which was the term I used when googling this.) from javascript.
This post shows several options. The better ones are toward the bottom.
http://forums.asp.net/t/1059213.aspx
Basically, every function that fires a server side event uses a javascript method called __doPostBack and here is an example of what you want to do.
Ajax's PageMethods is very useful for this if you don't want to do a full postback and just need to call 1 method.
First I decorate a method in my aspx.cs file like so:
[System.Web.Services.WebMethod]
public static string getVersions(string filePath)
{ ...
return myString;
}
Notice the "static" too. Then in javascript I can call this like:
PageMethods.getVersions(_hfFilePath.value, LoadVersionsCallback);
You can have as many parameters as you need of different data types. The last parameter is the JavaScript function that gets called when the call returns. Looks something like:
function LoadVersionsCallback(result) {
...
// I make a drop down list box out of the results:
parts = result.split('|');
for (var i = 0; i < parts.length; i++) {
_ddl.options[_ddl.options.length] =
new Option(parts[i].replace(/~/g, ", "), parts[i]);
}
...
}
Finally, you must have the script managers property "EnablePageMethods" set to "true".
<ajaxToolkit:ToolkitScriptManager ID="ScriptManager1"
runat="server" EnablePageMethods="true"
EnablePartialRendering="true"
OnAsyncPostBackError="ScriptManager1_AsyncPostBackError">
</ajaxToolkit:ToolkitScriptManager>
So from JavaScript you can call a static function on your page's behind code.

MVC, Jquery, and Ajax to display object based on dropdown

I'm trying to design a view to accept donations, sell memberships, or sell tickets to events.
I have a dropdown list that displays "Make a donation", "Purchase membership", and the subsequent options are populated from the IList<Event> Model passed from the controller. I use javascript to determine which panel (membership, donation, or event) should be displayed based on the selection.
The problem I'm having is that once an event is selected, I need to be able to dynamically populate the Event panel with the properties of the selected event (without, of course, having to put the user through a browser refresh). I was told by someone that I should be able to use Ajax to accomplish this. Supposedly I could go to my server/home/GetEventById action to do this. However, I haven't been able to find any examples or any tutorials that would help me accomplish this.
Could anybody shed some light on this for me by means of how to go about this, or provide examples or tutorials that would help me?
Here is a code example of fetching some content by calling a controller method through ajax, and then populating a jQuery dialog with it. Hopefully this helps point you in the right direction.
The controller method:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetItemsForJson()
{
var items = Repository.GetItems();
var result = Json(items);
return result;
}
And the jQuery to make it happen:
$('#dialog_link').click(function () {
$.getJSON("/Items/GetItemsForJson/", getItems);
});
function getItems(items) {
$("#itemlist").text("");
$.each(items, function (i, item) {
$("#itemlist").append("<li>" + item.Id + item.Name + "</li>");
});
}
Your question is a bit too broad. I assume you already implemented your Action in controller so we concentrate only on client side scripting.
Following should within $.ready:
$("#ddlSelectEvent").change(function() { // this will fire when drop down list is changed
var selection = $(this).attr("selected"); // text representation of selected value
$(".panels").hide();
$("#panel_" + selection).show(); // Assume the panel naming will be panel_MakeDonation and those...
// Now is time for ajax - load html directly
$.get("server/home/geteventbyId",
{id: "12345"},
function (data) { // callback when data is loaded
$("#panel_" + selection).html(data);
}
);
});
Above codes assume you populate content of panel with html. You might use JSON or other types depending on how you implement it.
http://docs.jquery.com/Ajax/jQuery.get#urldatacallbacktype
I'm not sure how MVC changes this, but here is how I do a callback with Ajax:
In the onchange event of the dropdownlist box you would call a java function that uses Ajax's PageMethod, something like this:
PageMethods.getVersions(LoadVersionsCallback);
The method you are calling in your .aspx.cs file has to be static, it can take parameters and looks something like:
[System.Web.Services.WebMethod]
public static string getVersions() {
StringBuilder sb = new StringBuilder();
... etc.
return sb.ToString();
}
The javascript function that you specified when you called the method will run when the method completes. It will be passed the results.
function LoadVersionsCallback(result) {
// do something with the results - I load a dropdown list box.
...etc.
}

Categories