I'm trying to make an AJAX request on a Razor Page, calling a method contained in separate class file (NOT in the pagemodel for the page - as I eventually want to make the same request from multiple different pages).
Unfortunately, the request fails. I think it may have to do with the syntax I've used, or perhaps the class I'm trying to call being of the wrong type. Note that the request DOES work if I change the url to a method in the pagemodel (no other changes required).
I'm fairly new to ASP.NET Core Razor Pages, and AJAX requests, so if there's a fundamental misunderstanding here, let me know.
AJAX Request Code (jQuery):
$(document).ready(function () {
$.ajax({
dataType: 'json',
url: '/Tools/Redirect?handler=AccessRedirect',
type: 'GET',
success: function (data) {
alert("Request Success, Data = " + data);
},
error: function () {
alert("Request Failed");
}
});
})
(I've also tried url: /Tools/Redirect/AccessRedirect using a method simply called AccessRedirect, with the [HttpGet] attribute, but that didn't work either)
C# Class Code (File is Redirect.cs in folder Tools):
public class Redirect
{
public JsonResult OnGetAccessRedirect()
{
return new JsonResult("test");
}
}
Any help is greatly appreciated. Thanks.
Your fundamental misunderstanding is that Razor Pages requests must target a handler method in a PageModel class. You can't map URLs to arbitrary methods in class files. Handler methods must be in a class that derives from PageModel, and they must follow certain conventions.
You can read more about handler methods in Razor Pages here: https://www.learnrazorpages.com/razor-pages/handler-methods
If you have code that you want to centralise, you can put that in a C# class, and then call the method in your handler method
Related
I have a ViewComponent called WatchList. It's being called in a page under a route named Request.
This is what the URL typically looks like:
And this is how I'm setting up the ViewComponent:
#await Component.InvokeAsync("WatchList", new { requestId = Model.RequestInput?.RequestId })
I'm attempting to make an AJAX POST from the ViewComponent:
$.ajax({
type: "POST",
url: "Request/WatchList?handler=GetMyself",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
But I'm running into a "XML Parsing Error: no root element found" error.
Location: http://localhost:12227/.../.../Request/WatchList?handler=GetMyself
I can't tell if I'm getting the route wrong, or if I can't call ViewComponent methods from AJAX.
Here is my structure:
Any ideas what I'm doing wrong here?
As Chris said , you can't use AJAX from the ViewComponent page to get into a method in the view component class.But you could try the following workaround which maybe you want , use the retrun ViewComponent(" ViewComponentName",new{ paramater1,paramater2...}); in a PageHandler to call the InvokeAsync method in the ViewComponent Class.
my stuff works fine with Fiddler and I get desired result. But when i do it on web page thru JQuery AJAx, it says "Not Found". I am struggling since sometime but couldn't get around.
My Controller method is like this
[Route("AddDonors/")]
[HttpPost]
public dynamic addDonors(localDonor localDonor)
{
return localDonor;
}
This is how i am calling from web page
var userInput = { 'FullName': 'Lakshman', 'Mobile': '9924210053' };
$.ajax({
type: "POST",
url: "/AddDonors",
data: userInput,
error: function (result) {
alert(result);
},
datatype: "json"
});
this is the model class
public class localDonor
{
public String FullName { get; set; }
public String Mobile { get; set; }
}
API registering and other settings are just fine since this works in fiddler.
Please help. Thanks.
I strongly suspect that the url in your AJAX request is to blame (404 - Not Found) the request can't be routed to a controller for processing.
Without knowing what your full controller looks like and if you have a RoutePrefixAttribute on this specific controller I can't say what the url should be.
I would suggest you monitor network traffic in your browser developer tools (press F12) and compare the request url for your failing POST request to those of your successful requests in Fiddler
If your webpage is created in ASP.Net MVC as part of the same web project you may want to generate the url server side in future see Construct url in view for Web Api with attribute routing. The #Url helper is only available within your .cshtml files though so you will not be able you shift your JavaScript code to a separate .js file.
i was able to solve the issue by changing the url to url: "AddDonors",
Try to put [WebMethod] attribute.
[Route("AddDonors/")]
[HttpPost]
[WebMethod]
public dynamic addDonors(localDonor localDonor)
{
return localDonor;
}
Hope this works!
Try this for your POST data
var userInput = JSON.stringify({ 'FullName': 'Lakshman', 'Mobile': '9924210053' }),
I had the same error.
As you are using ASP.NET, try making all AJAX calls using the #Url.Action helper.I don't know why, but in some situations in ASP.NET passing the URL as a String doesn't work.And try passing your data like the code belowYour modified code should look something like this:
$.ajax({
type: "POST",
url: "#Url.Action("AddDonors", "ControllerName")",
data: { localDonor: userInput },
error: function (result) {
alert(result);
},
datatype: "json"
});
It makes me in trouble when I write jQuery Ajax calls for each task in my whole application. I write jQuery Ajax calls to update the interface after a specific event, such as updating a dropdown list when another dropdown list selection changes.
I need the fastest way to handle Ajax requests across my application and to avoid code repetition.
// code sample to ajax request which I used
function onChange(bookid) {
$.ajax({
type: "GET",
url: '#Url.Action("books","subject")',
data : { bookid: bookid},
dataType: "json",
success: function (result) {
alert('success');
//do whatever you want
},
error: function(result){
}
});
};
If you are looking for an approach that would simplify these kind of ajax call to update interface after specific events, using asp.net mvc 4, I would suggest that you look into the awesome awesome set of helpers.
Be assured that it's a very easy to learn set of helpers.
I encourage to go to the Live demo and play with it for a while. You will rapidly realize its great potential.
Then an example with master - slave dropdown list (first element on the default demo page).
Here is the code that goes into the view:
Cascading using binding to Parent:<br />
<%:Html.Awe().AjaxDropdown("Category")
.Url(Url.Action("GetCategories","Home")) %>
<%:Html.Awe().AjaxDropdown("ChildMeal")
.Url(Url.Action("GetMeals","Home"))
.Parent("Category") %>
The first dropdown is an ÀjaxDropDownnamedCategory. It is filled by executing an action method calledGetCategoriesfound on a controller calledHomeController` (in this example these are meals categories).
Note that Awesome uses some conventions in certains cases. For example if we had limited the first AjaxDropDown declaration to <%:Html.Awe().AjaxDropdown("Category")%>then the Awesome will assume that we would fill the dropdown from an action method called GetItems and it would expect to find it on a controller called CategoryAjaxDropDownController. But since we have specified the url with the corresponding action, it would look for the specified action method on a controller called SPECIFIED_NAME+Controller (in this example HomeController)
The second's name is ChildMeal, it's parent is the Category ajax drop down and it is filled when the selected element is changed in the Category drop down, and when that happens it is filled by executing the GetMeals action method from the HomeController controller.
Here is the code for the action methods in the HomeController
public ActionResult GetCategories(int? v)
{
var items = Db.Categories
.Select(o => new SelectableItem(o.Id, o.Name, v == o.Id));// value, text, selected
return Json(items);
}
public ActionResult GetMeals(int? v, int? parent)
{
var items = Db.Meals.Where(o => o.Category.Id == parent)
.Select(o => new SelectableItem(o.Id, o.Name, v == o.Id));// key, text, selected
return Json(items);
}
As you can see from the return object the JSON handling complexity is managed by Awesome and it all becomes transparent to the developer (you just have to invoke Json(items) to have it done.
The Db object provides the datas. You may use a class that inherits from System.Data.Entity.DbContextin order to load datas from a database.
You have many other similar components (such as the AjaxRadioList, the AjaxCheckBoxList, the AjaxList, the AutoComplete component, ...) among many very interesting rich components.
I suggest that you go to the live demo, play with it, see the various examples and the source codes, then you try to create your first awesome project.
well jQUery's ajax call's about as fast as your going to get - there is not a lot of overhead on the client side at all .
as far as extra code .. for each call:
function onChange(bookid) {
$.ajax({
type: "GET", // not needed - default GET
url: '#Url.Action("books","subject")',
data : { bookid: bookid},
dataType: "json", // not needed - jQuery will guess
success: function (result) {
alert('success');
//do whatever you want
},
error: function(result){ // not needed if you're leaving empty
}
});
};
could be
$.get('#Url.Action("books" , "subject")' , { bookid: bookid}, function(result){
alert(result);
});
I have a code like below
View:
$("form").live('submit', function () {
var formData = $(this).toObject();
$.ajax({
url: "../Home/Index",
type: "POST",
dataType: "json",
data: formData,
success: function (data) {<<Some handling>>
}
Controller:
public JsonResult Index(Task task)
{
//operations on the task object like getting data from task and setting to it.
}
Task is a model here.
Here when the form is submitted, the form object is directly sent to the controller and the controller is receiving it as a model.
How this conversion takes place? I have added a file component to the form now
<input type="file" name = "file" id="file"/>
and added the file attribute to model Task.
public HttpPostedFileBase file{ get; set; }
But I am getting null for the file in the controller. But all other values are coming well.
Please help me out. Please let me know if you need any additional info to understand my question correctly.
Normally it's the model binder that is responsible for converting the request values into a model.
But in your case you seem to be attempting to send a file using AJAX. This is not supported. The reason for that is because jQuery's ajax method doesn't support that. You could use HTML5 File API if the client browser supports it because the XHR2 object allows you to asynchronously upload files to the server. Here's an example:
$(document).on('submit', 'form', function () {
var xhr = new XMLHttpRequest();
xhr.open(this.method, this.action);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText); // handle response.
}
};
xhr.send(new FormData(this));
return false;
}
Also notice that I have used the .on() method to subscribe to the submit event instead of .live() which is obsolete and has been removed in jQuery 1.9.
If on the other hand you need to support legacy browsers you could use a plugin such as Fine Uploader or jQuery form to achieve this task. What those plugins do is detect the capabilities of your browser and if it supports XHR2 it will use it, and if it doesn't it will use a different technique (such as hidden iframes, flash, ...).
You can not file upload using jquery ajax post directly. You should you some plug-in for this.
May be you can use this plug-in
This question will show you a start point for using this plug in.
Also, I learned it from #DarinDimitov suggestions, too :)
I have a method called getPersonInfo and it's header looks like this:
[WebMethod]
public static Hashtable getPersonInfo(int personID)
{
}
The problem I am having is that this method cannot access my asp.net controls. So of course I remove the "static" keyword. But then my ajax calls fail since it's not a static method any more. Any suggestions?
EDIT: After reading and searching for a bit, I've realized that it won't work. What I am asking is if there is another way of maybe getting the final result, as for now I'm unsure of how to do that.
This is fundamentally impossible.
AJAX methods do not run the page lifecycle, so the controls don't actually exist on the server.
Instead, you need to manipulate the page on the client.
You need to pass the values of controls to the getPersonInfo method from client side. For ex: if its JQuery ajax call, additional parameters can be passed using "data" property. Ofcourse, again the getPersonInfo method signature needs to be modified accordingly.
$.ajax({
url: 'adduser.aspx/getPersonInfo',
data: { personID: $('txtPersonId').val() }, //pass additional parameters here
type: "POST",
success: function (template) {
alert('success'); },
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert('error');
}
});