How to call non static method from AJAX? - asp.net

Here is my code behind I am calling from AJAX...
[WebMethod]
[ScriptMethod]
public static string save(string parameter)
{
country_master obj_country = new country_master();
obj_country.Country_Name = Page.Request.Params["name"].ToString().Trim();
obj_country.saved();
return "";
}
Here I am not able to access parameters passed from the page via Page.Request.
string name = HttpContext.Current.Request.QueryString["name"].Trim();
return "error";
after writing the first line, return statement does not return anything to the AJAX.
Please Help me how to do that.
Thanks...

To get the current context you can use HttpContext.Current, which is a static property.
Once you have that you can access things like session or profile and get information about the state of the site
HttpContext.Current.Session etc..
This link may help you : Call Server Side via AJAX without a Static Method
The reason behind restricting the web method to be static is to avoid it access the controls of the instance page.

Yo could use the HttpContext.Current static class, however you can skip that if you declare on your method the parameters you want to use and just pass the parameters with your AJAX call
You should pass parameters directly to the method.
I have several working examples on my Github repository, feel free to browse the code.
As a summary, to call a PageMethod:
Note: how using AJAX the jobID PageMethod parameter is being passed along with the request and how is used inside the PageMethod transparently
AJAX call
$.ajax({
type: 'POST',
url: '<%: this.ResolveClientUrl("~/Topics/JQuery/Ajax/PageMethods_JQueryAJAX.aspx/GetEmployees") %>',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: '{"jobID" : ' + jobID +'}',
async: false,
cache: false,
success: function (data) {
$('#employees').find('option').remove();
$.each(data.d, function (i, item) {
$('<option />').val(item.EmployeeID).text(item.FirstName).appendTo('#employees');
});
},
error: function (xhr) {
alert(xhr.responseText);
}
});
Page Method
[WebMethod]
public static List<EmployeeModel> GetEmployees(int jobID)
{
var ctx = new PubsDataContext();
return (from e in ctx.employee
where e.job_id == jobID
orderby e.fname
select new EmployeeModel
{
EmployeeID = e.emp_id,
FirstName = e.fname
}).ToList();
}

Related

Action page in asp.net

How do i create a page like an action page in php, in C# ?To be specific I only require a page that contains only methods that handle various operations and return result.
How do i solve the above scenario ?
Create a class, then inside the class create your methods to construct the logic behind your application.
Then reference this class with the using keyword in your web pages and use the methods you created wherever you like.
Read about HttpHandlers.
For example, you want to have a method that returns a json string in a web forms application.
Add a new item to your project of type "Generic Handler". This will create a new .ashx file. The main method of any class that implements IHttpHandler is ProcessRequest.
public void ProcessRequest (HttpContext context) {
if(String.IsNullOrEmpty(context.Request["day"]))
{
context.Response.End();
}
string json = "";
byte[] bytes = getByteArray();
json = JsonConvert.SerializeObject(bytes);
context.Response.ContentType = "text/json";
context.Response.Write(json);
}
Change the url in your AJAX call and that should do it. The JavaScript would look like this , where GetFileHandler.ashx is the name of the IHttpHandler you just created:
$.ajax(
{
type: "POST",
async: true,
url: 'Handlers/GetFileHandler.ashx',
data: "Day=" + $.toJSON(day),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
console.log("SUCCESS:" + msg);
},
error: function (msg) {
console.log("error:" + msg);
}
});
Read more here for more details.

AJAX call returns page HTML / doesn't hit Page Method is ASP.Net (no MVC or Json)

I am updating a tool for my current company that provides basic product layout documents depending on choices picked. Recently it appears a bot of some sort has been hitting the toolbox periodically, and after some discussion with the company we built the toolbox for we have decided to add the ReCaptcha tool to the page.
The way the toolbox was setup is ASP.net without the use of Json or MVC (the toolbox is a fair few years old, built long before I joined the team). Adding the ReCaptcha tool was not an issue, I did it without a plugin using a window.onload function and using their instructions. This was all done on the options.aspx page, the code for the ReCaptcha call is in the options.aspx.cs page.
To reach this code I am attempting to do an AJAX call where the form would normally be submitted.
The issue: Each AJAX call returns the HTML of the page, and the Page Method (VerifyReCaptcha) does not trigger when I have a break point in it. I need it to call the method which will do all of the listing, then simply pass back a string that simply says if it was a success or not. It doesn't seem to matter what dataType or contentType I enter (if any), or if I run it as POST or GET.
Here is the code of the button that calls the function for the ajax call.
<input type="button" id="DownloadLayoutButton" value="Download Layout" class="navigationButton" style="width: 200px; height: 24px;" />
Here is the function that is called.
$("#DownloadLayoutButton").click(function () {
$.ajax(
{
url: "options.aspx/VerifyReCaptcha",
dataType: "text",
data: {
challenge: Recaptcha.get_challenge(),
response: Recaptcha.get_response()
},
type: "POST",
success: function (result) {
if (result == "Success") {
alert("Success!");
else
alert("ReCaptcha entry was incorrect!");
},
error: function (request, status, error) {
alert("Error!");
}
});
});
This code never seems to hit the VerifyReCaptcha() method that is on the options.aspx.cs page, the method is as follows. As stated I have tested and confirmed that this function works on its own. Previously I had it returning a boolean value but since ajax can't work with booleans, I changed it to return "Success" or "Failure" depending on the result.
[WebMethod]
public static string VerifyReCaptcha(string challenge, string response)
{
try
{
string PRIVATE_KEY = "MY_KEY_HERE";
string remoteip = HttpContext.Current.Request.UserHostAddress;
WebRequest request = WebRequest.Create("http://www.google.com/recaptcha/api/verify");
byte[] dataBytes = System.Text.Encoding.UTF8.GetBytes(String.Format("privatekey={0}&remoteip={1}&challenge={2}&response={3}", PRIVATE_KEY, remoteip, challenge, response));
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = dataBytes.Length;
request.GetRequestStream().Write(dataBytes, 0, dataBytes.Length);
String resultString = String.Empty;
String errorString = String.Empty;
using (StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream()))
{
resultString = sr.ReadLine();
errorString = sr.ReadLine();
}
Boolean b;
b = Boolean.TryParse(resultString, out b) && b;
if (b)
return "Success";
else
return "Failure";
}
catch (Exception)
{
return "Failure";
}
}
The aspx page is using the following sources.
<script type="text/javascript" src="JS/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="JS/jquery-validate/jquery.validate.js"></script>
<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
Your ASP.NET AJAX Page Method needs to be static.
You have:
public virtual string VerifyReCaptcha()
It needs to be:
public static virtual string VerifyReCaptcha()
Note: Read Why do ASP.NET AJAX page methods have to be static? for more information.
As I understand it, asp.net WebMethods expect posted data in JSON.
In your JavaScript jQuery Ajax call use dataType: "json" rather than dataType: "text".
I also add contentType: "application/json; charset=utf-8" as another option.
The WebMethod is not called if the doesn't find the correctly formatted data it expects.

Response.Write() in WebService

I want to return JSON data back to the client, in my web service method. One way is to create SoapExtension and use it as attribute on my web method, etc. Another way is to simply add [ScriptService] attribute to the web service, and let .NET framework return the result as {"d": "something"} JSON, back to the user (d here being something out of my control). However, I want to return something like:
{"message": "action was successful!"}
The simplest approach could be writing a web method like:
[WebMethod]
public static void StopSite(int siteId)
{
HttpResponse response = HttpContext.Current.Response;
try
{
// Doing something here
response.Write("{{\"message\": \"action was successful!\"}}");
}
catch (Exception ex)
{
response.StatusCode = 500;
response.Write("{{\"message\": \"action failed!\"}}");
}
}
This way, what I'll get at client is:
{ "message": "action was successful!"} { "d": null}
Which means that ASP.NET is appending its success result to my JSON result. If on the other hand I flush the response after writing the success message, (like response.Flush();), the exception happens that says:
Server cannot clear headers after HTTP headers have been sent.
So, what to do to just get my JSON result, without changing the approach?
This works for me:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void ReturnExactValueFromWebMethod(string AuthCode)
{
string r = "return my exact response without ASP.NET added junk";
HttpContext.Current.Response.BufferOutput = true;
HttpContext.Current.Response.Write(r);
HttpContext.Current.Response.Flush();
}
Why don't you return an object and then in your client you can call as response.d?
I don't know how you are calling your Web Service but I made an example making some assumptions:
I made this example using jquery ajax
function Test(a) {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "TestRW.asmx/HelloWorld",
data: "{'id':" + a + "}",
dataType: "json",
success: function (response) {
alert(JSON.stringify(response.d));
}
});
}
And your code could be like this (you need to allow the web service to be called from script first: '[System.Web.Script.Services.ScriptService]'):
[WebMethod]
public object HelloWorld(int id)
{
Dictionary<string, string> dic = new Dictionary<string, string>();
dic.Add("message","success");
return dic;
}
In this example I used dictionary but you could use any object with a field "message" for example.
I'm sorry if I missunderstood what you meant but I don't really understand why you want to do a 'response.write' thing.
Hope I've helped at least. :)

Pass JSON to MVC 3 Action

I am trying to submit JSON to a MVC action. What I want is to take the JSON object and then access it's data. The number of JSON fields will vary each time so I need a solution that will handle all cases.
This is my POST to my action, address could have 3 fields or 20 it will vary on each post.
Update: I'll go into a little more detail. I'm trying to use the LinkedIn API, I'll be sent a JSON which will look like the JSON at the end of this page : link. I need to create an Action which will accept this JSON which will vary for every person.
var address =
{
Address: "123 rd",
City: "Far Away",
State: "Over There"
};
$.ajaxSetup({ cache: false });
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/Account/GetDetails/",
data: JSON.stringify(address),
dataType: "json",
success: function () {
alert("Success from JS");
}
});
This is my action in MVC, I need to be apply to take whatever JSON object is passed and access its fields.
[HttpPost]
public ActionResult GetDetails(object address)
{
//address object comes in as null
#ViewBag.Successs = true;
return View();
}
I don't believe nobody saying this so I will try. Have your code like this
public class Personal
{
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
//other properties here
}
[HttpPost]
public ActionResult GetDetails(Personal address)
{
//Should be able to get it.
#ViewBag.Successs = true;
return View();
}
In general, you can add those possible properties into the class Personal (or whatever you can name it). But according to linkedin API, you will need a tool to generate the data class due to its complexity. I think xsd.exe can help if you can get xsd file for that (or you can even generate xsd file from xml)
Remove data: JSON.stringify(address) with data: address
Action method
[HttpPost]
public ActionResult GetDetails(string Address, string City, string State, string PropName)
{
//access variable here
}
As you have said your data object may contain 20 props, to avoid creating 20 parameters, you can use formscollection like below
[HttpPost]
public ActionResult GetDetails(FormCollection address)
{
string city= address["city"] ;
string anotherPro=address["prop"];
}
Not sure if this will work (never done this myself), but you could try the following signature:
public ActionResult LinkedIn(dynamic address)
I'm actually quite interested myself to see what will happen then. Or, as suggested in the comment by Kristof Claes, use a FormCollection.
Second, when things like this happen, always check whether the browser actually sends the data you expected to the server. IE9 and Chrome support this out of the box, otherwise you can use a tool like Fiddler.
EDIT: Just tried for myself with a dynamic parameter and that doesn't work.. The runtime type of the parameter is object so everything you submitted is lost. You'd better
use FormCollection.
I believe you can use a FormCollection for this.
public ActionResult LinkedIn(FormCollection address)
{
var street = address["street"];
...
return View();
}
Might just be a typo, but you are calling GetDetails ActionResult, but yet your code is LinkedIn ?
You need to wrap your JSON object in the name of parameter you are expecting in your action method. Something like this:
var data = { address: { address: '123 Test Way', city: 'Parts Unknown', state: 'TX' } };
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/Account/GetDetails/",
data: JSON.stringify(data),
dataType: "json",
success: function () {
alert("Success from JS");
}
Then in your action method, do this:
public ActionResult GetDetails(dynamic address) {}
My take is all the answers are sort of right.
As your don't know the number of things you're sending, use formcollection on the server. But also remove the stringfy from the ajax call. These means the data will be sent using www-encoding.
If you wnat to send n address objects, change the mvc action parameter to an array of address objects and use stringfy.
This is how I do it. I have a MyProject.Model.Entities and I serialize them in by using [ParamSerializationFilter] attribute on the given action method.
Full code here: https://gist.github.com/3b18a58922fdd8d5a963
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!Enum.GetNames(typeof(AllowedMethods)).Any(n => n == filterContext.HttpContext.Request.HttpMethod))
throw new InvalidOperationException("Invalid Request: HttpMethod");
foreach (var param in filterContext.ActionDescriptor.GetParameters())
{
if (ModelTypes.Contains(param.ParameterType))
{
if ((filterContext.HttpContext.Request.ContentType ?? string.Empty) == ("application/json"))
{
filterContext.ActionParameters[param.ParameterName] =
JsonSerializer.DeserializeFromStream(param.ParameterType, filterContext.HttpContext.Request.InputStream);
}
else if (filterContext.HttpContext.Request.ContentType.Contains("xml"))
{
filterContext.ActionParameters[param.ParameterName] =
XmlSerializer.DeserializeFromStream(param.ParameterType, filterContext.HttpContext.Request.InputStream);
}
}
}
}
You're doing too much work! You can pass the JSON Literal directly to the server and access the elements via the action method parameters, like this:
var address =
{
Address: "123 rd",
City: "Far Away",
State: "Over There"
};
$.ajaxSetup({ cache: false });
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/Account/GetDetails/",
data: address,
dataType: "json",
success: function () {
alert("Success from JS");
}
});
[HttpPost]
public ActionResult LinkedIn(string Address, string City, string State)
{
// now you have everything you want as params
#ViewBag.Successs = true;
return View();
}
Note: This will only work if your action params are named the exact same as your JSON Literal attributes.

Sending a complex object as parameter to Asp.Net PageMethod

I am trying to send an object created in JavaScript to an ASP.NET PageMethod. This object mirrors the properties of an existing custom business object, so i was hoping that i could pass a single object instead of a parameter for each property. I am getting an error "Unknown web method SavePart when attempting to use this method.
Javascript:
function() {
var pt = { Id: 1, Onhand: 20, LowPoint: 30, __type: 'Custom.Objects.Part'};
$.ajax({
type: 'POST',
url: 'partlist.aspx/SavePart',
data: JSON.stringify(pt),
contentType: 'application/json; charset: utf-8;'
dataType: 'json',
success: function(results) { alert('Success!'); }
});
}
Code Behind:
<WebMethod()> _
Public Shared Function SavePart(pt as Custom.Objects.Part) as Boolean
Dim repo as new PartRepository()
return repo.Save(pt)
End Function
I am using another PageMethod which just accepts an int, and this works fine.
I ended up solving my problem by sending the object this way through the jQuery ajax command:
data: '{"pt":' + JSON.stringify(pt) + '}'
this serialized the object automatically and returned it to my WebMethod. When i tried sending the object as is, i got an error saying "invalid JSON primitive".
You are attempting to pass a string to the method. You will need to accept the string, and deserialize it with fx. JavascriptSerializer or JSON.NET
I know this is incredibly old, but its not very intuitive when you're using this to figure out what the issues are. You are very close but I wanted to add a bit more to this in case someone else later wants to do the same thing. This works with nested objects as well, the one thing I can say is CASE matters in your JS variables that map to .NET POCOs on the page method.
Your "answer" is where I will start with. And as in the comments below it, yes you have to pass the object wrapped in its page method variable name.
Ill say it again, this is CASE-Sensitive, and can trip you up not just on the object's name but its properties as well. So to combat this I usually create my POCO object in .NET then copy that to the page so I know the names, capitalization and all are correct.
Something like this:
POCO:
Public Class CustomObject
Public Property Id as integer
Public Property ReqDate as DateTime
Public Property Message as string
End Sub
Now with a defined POCO for page method, replicate that "model" exactly as it is for the JS/AJAX to post with, being vigilant about case-sensitivity.
function ParseAndPostData()
{
var data = { custobj: {
Id: 1,
ReqDate: "04/12/2018",
Message:"Hello!"
}
};
//Stringify the data so it goes through page method parser
var postdata = JSON.stringify(data);
$.ajax({
type: 'POST',
url: '/BasePath/SomePage.aspx/SomeMethod',
data: postdata,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (msg) {
var parsedACData = JSON.parse(msg.d);
alert(parsedACData);
},
error: function (msg) {
alert(msg);
}
});
}
Page Method (Note custobj in the parameters):
<WebMethod()> _
Public Shared Function PostCustomObject(custobj as CustomObject) as String
return custobj.Message
End Function

Resources