EDIT 2
I was able to solve the problem. There was nothing wrong with the Javascript or Controller code. The problem came from a .dll file. In the controller method I build a new TextInfo object from the TextModel object. The TextInfo object comes from a .dll that's build from the API. This .dll however had multiple instances with different build dates in the File System. Seems like the old version wasn't removed properly but it was the one the compiler used. This created a 500 Internal Server Error telling me that a Method wasn't available.
EDIT 1
I'm fairly certain my problem stems from a property in my model not being set correctly but I'm not sure why. I had 1 instance where I was able to debug though furhter into the code but I'm clueless as to why or how that happened. Will update later once I find more answers.
I am having trouble accessing the controller action from my ajax call and it honestly makes no sense to me as to why I'm unable to start the code. The issue seems to be with the CurrentPageNumber. When I comment out this variable from both c# and javascript, I am able to hit the breakpoint in the controller. But when I uncomment that variable I can't hit the breakpoint. The error I'm getting is 500 Internal Server Error. To me that sounds like the JSON keys aren't the same as the Controller parameters, but as you can see below that isn't the case (unless if I turned blind). Any idea what the problem could be? Prehaps I'm looking in the wrong direction?
tl;dr Controller ActionResult not started when CurrentPageNumber is in the parameter and key list (uncommented), but it does start when it isn't (commented out).
I am trying to reach the following ActionResult.
public ActionResult SavePageInfo(List<TextModel> TextObjects, string ImageSource, int CurrentPageNumber)
I do this with the help of the following AJAX call
var json = JSON.stringify({ TextObjects: textObjects, ImageSource: imageSource, CurrentPageNumber: pageNumber });
$.ajax({
url: "/NextprintPhotobook/SavePageInfo",
type: "POST",
data: json,
dataType: "json",
contentType: 'application/json; charset=utf-8',
success: function (data) {
console.log(data.message);
alert(data.message);
}
})
The JSON that's produced looks like this (as you can see all values are set):
"{"TextObjects":[{"text":"Test","x":50,"y":50,"fillColor":"#77DD44","fontFamily":"arial","fontStyle":"normal","fontSize":"18pt","fontWeight":"normal","textAlignment":"start","angle":0}],
"ImageSource":"http://localhost:22223/api/file/getfile?name=04.jpg&collectionId=4103&version=1&size=original",
"CurrentPageNumber":1}"
TextModel is as follows:
public class TextModel
{
public string text
{
get; set;
}
public int x
{
get; set;
}
public int y
{
get; set;
}
// Same properties as in the JSON.
}
Why are you not using a single object as parameter (a wrapper class for all those params)? (usually this is how it is done, unless you want to add some params in the query string also)
this is not the answer... well (i just want to put it here so its easier to read)
try this:
var data = {
TextObjects: JSON.stringify(textObjects),
ImageSource: imageSource
CurrentPageNumber: pageNumber
}
$.ajax({
url: "/NextprintPhotobook/SavePageInfo",
type: "POST",
data: data,
dataType: "json",
contentType: 'application/json; charset=utf-8',
success: function (res) {
console.log(res.message);
alert(res.message);
}
});
Related
I am using MVC 5 with jQuery and am having difficulties with posting the anti forgery token using Ajax. i have looked on SO at various fixes, but nothing appears to work.
I have the following code within my view.
#using (Html.BeginForm("None", "None", FormMethod.Post, new { #id = "js-form" }))
{
#Html.AntiForgeryToken()
....
other code
....
<button class="button-primary button expand js-button-search" type="button">Search</button>
}
Then using jQuery I have added an event handler to the button above by selecting the element via the class: js-button-search. The main Ajax call is as per below
$.ajax({
url: url,
method: 'POST',
dataType: "json",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(_self.JsonData),
success: function (result) {
// Success code
},
error: function (jqXHR, textStatus, errorThrown) {
// Failure code
}
});
Where my confusion is, is around the data parameter. I have an object which is populated on demand that contains a large amount of elements that can be used for searching.
The object takes the form of (shortened as we current have over 40 search fields):
_self.JsonData = { "searchData": {"DocIdFrom" : "426737", "DocIdTo" : "753675", "DocIdTypeSearch" : "between", "DocDateFrom" : "06/02/2017", "DocDateTo" : "", "DocDateTypeSearch" : "greater than", .....
etc...
}}
As you can see, the data is parsed using JSON.stringify. All of this work as long as the [ValidateAntiForgeryToken] attribute is commented out on the controller function.
Controller as follows:
[HttpPost]
//[ValidateAntiForgeryToken]
public JsonResult GetSearchResultsJson(SearchCriteria searchCriteria, int? page)
{
// code in here
}
When I uncomment the anti forgery attribute, the page stops working.
Now i know about the need to pass the token across with the post and have tried the following without success:
how-can-i-supply-an-antiforgerytoken-when-posting-json-data-using-ajax
asp-net-mvc-5-ajax-request-on-edit-page-error-requestverificationtoken-is-not
The main difference between what I have appears to be a complex object, but i think that is a red herring as Stringify converts the object into a string.
Sorry, forgot to add. Fiddler return the following message when the [ValidateAntiForgeryToken] is enabled
[Fiddler] ReadResponse() failed: The server did not return a complete response for this request. Server returned 0 bytes.
I would like to thank Stephen Muecke for providing the solution to the problem.
Firstly my Json object was converted to the following:
var data = { "__RequestVerificationToken":$('[name=__RequestVerificationToken]').val(),
"searchData":
{
"DocIdFrom" : "426737",
"DocIdTo" : "753675",
..............
etc
}
}
Then, I removed the contentType parameter from the Ajax call and stopped stingifying the Json data.
This has had the desired effect and now i can call the MVC controller using the [ValidateAntiForgeryToken] attribute.
You might pass RequestVerificationToken (AntiForgeryToken) on Ajax call by using one of the methods below:
Method I: When using serialize() or FormData() methods, it is not necessary to add the token to the data parameters separately (it will be included id the formdata parameter):
//Send the values of all form controls within the <form> tags including the token:
var formdata = $('#frmCreate').serialize();
//or
var formdata = new FormData($('#frmCreate').get(0));
Method II:
var token = $('[name=__RequestVerificationToken]').val();
$.post(url, { comment: comment, IssueID: postId, __RequestVerificationToken: token },
function (data) { … })
Then you can use the Controller as shown below:
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult AddComment(string comment, int IssueID){
//...
}
I have asked a few questions here without any workable answers. I may have been on the wrong track or asked it all wrong. Basically, what I am trying to do is load up a VAR in the page:
var testModel = #Html.Raw(JSON.Encode(Model))
Then manipulate the testModel properties, which reflect the original model, with jQuery and JavaScript, then post it back to a controller method with an AJAX request:
$.ajax({
datatype: 'json',
data: testModel // ?? or some other way?
// etc
});
The controller:
public ActionResult PostModel (ModelName model) // or JsonResult
{
//do things
return Json(model); // or return View?
}
Any help would be appreciated.
I have tried what others have suggested below, and still the transaction never makes it to the controller method. Why not?
Ajax type Specifies the type of request. (GET or POST) DETAILS
$.ajax({
type: 'POST',//or GET
dataType: 'json',
data: testModel // ?? or some other way?
// etc
});
typerepresents the type of request you're making not the type of data you're going to get back. dataType is what you should have there and POST in the type field.
$.ajax({
type: 'POST',
dataType: 'json',
data: testModel // ?? or some other way?
// etc
});
Basically you are posting the data through javascript so on success you need a Json object to parse
so you need to return Json(model):
public ActionResult PostModel (ModelName model) // or JsonResult
{
//do things
return Json(model);
}
and your JS as:
$.ajax({
type: 'POST',
url: '{somecontroller}/{someaction}',
cache: false,
contentType: 'application/json; charset=utf-8',
data:testModel,
success: function (object) {
$.each(object, function (key, val) {
//do your stuff here
})
})
Where the key will be your Model Property name and val will be its value respectively
Now to remove your confusion "When to return View?"
There are three ways to pass information from a controller to a view in ASP.NET MVC. We use Html helpers to generate html fields and bind them with models to Get/Post the data values from view to controller
As a strongly typed model object. (for specific model)
As a dynamic type (using #model dynamic)
Using the ViewBag
Now when you are using the html helpers you can return view with the object model passed with it, which will automatically populate the data in your view as:
Strongly typed model object
<%# Page Title="#" Language="VB" MasterPageFile="#" Inherits="System.Web.Mvc.ViewPage(Of somemodel)" %>
Render view as
Return View("your View Path", modelObject)
Here's what I did to make this approach work:
In the page (.cshtml):
function SendJsonData() {
localModel.itemNumber = $("#txtItemNumber").val();
// etc for the rest of the fields
$.ajax({
url: '#Url.Action("PostModel", "ItemControl")',
data: JSON.stringify(localModel),
dataType: 'json',
cache: false,
type: 'POST',
contentType: 'application/json, charset=utf-8',
success: function(data) {
//do stuff
},
error: function () {
alert('error');
}
});
Then in the controller:
[HttpPost]
public JsonResult PostModel(ItemModel localModel)
{
//do stuff with data model
return Json(localModel);
}
This worked fine and seems to me to be the way to go for most applications using MVC4 and above. This way the entire model is in the page and can be readily manipulated with jQuery and JavaScript then sent to the controller for processing. This can even be a large complex model, I've tried it. No more post backs and page flicker and rewriting...
I get the following error "Web Service method name is not valid" when i try to call webmethod from javascript
System.InvalidOperationException: SaveBOAT Web Service method name is not valid.
at System.Web.Services.Protocols.HttpServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)
HTML Code :
<asp:LinkButton runat="server" ID="lnkAddBoat" OnClientClick="javascript:AddMyBoat(); return false;"></asp:LinkButton>
JS Code :
function AddMyBoat() {
var b = document.getElementById('HdnControlId').value;
jQuery.ajax({
type: "GET",
url: "/AllService.asmx/SaveBOAT",
data: { Pid: b },
contentType: "application/text",
dataType: "text",
success: function(dd) {
alert('Success' + dd);
},
error: function(dd) {
alert('There is error' + dd.responseText);
}
});
}
C# Code (Web method in AllService.asmx file)
[WebMethod]
public static string SaveBOAT(int Pid)
{
// My Code is here
//I can put anythng here
SessionManager.MemberID = Pid;
return "";
}
I tried all solutions found on Stack Overflow and ASP.NET site.but none of them worked for me.
It was a silly mistake.
remove Static keyword from method declaration.
[WebMethod]
public string SaveBOAT(string Pid)
{
SessionManager.MemberID = Pid;
return "";
}
In my case I had copied another asmx file, but not changed the class property to the name of the new class in the asmx file itself (Right click on asmx file -> View Markup)
In my case the error was that the Web Service method was declared "private" instead of "public"
Try using this, I think datatype should be JSON
jQuery.ajax({
type: "POST", // or GET
url: "/AllService.asmx/SaveBOAT",
data: { Pid: b },
contentType: "application/json; charset=utf-8",
dataType: "json"
success: function(dd) {
alert('Success' + dd);
},
error: function(dd) {
alert('There is error' + dd.responseText);
}
});
And in C# Code change Pid to string
[WebMethod]
public static string SaveBOAT(string Pid)
{
SessionManager.MemberID = Pid;
return "";
}
I too faced the similar issue. The solution includes checking everything related to ensuring all name, parameters are passed correctly as many have responded. Make sure that the web method name that we are calling in UI page is spelled correctly, the data, data types are correct and etc. In my case, I misspelled the web method name in my ajax call. It works fine once I found and corrected the name correctly.
For Ex: In .asmx class file, this is the method name "IsLeaseMentorExistWithTheSameName" but when I called from UI this is how I called:
var varURL = <%=Page.ResolveUrl("~/Main/BuildCriteria.asmx") %> + '/IsLeaseMentorExistWithSameName';
Notice that the word "The" is missing. That was a mistake and I corrected and so it worked fine.
As Sundar Rajan states, check the parameters are also correct. My instance of this error was because I had failed to pass any parameters (as a body in a POST request) and the asmx web method was expecting a named parameter, because of this the binding logic failed to match up the request to the method name, even though the name itself is actually correct.
[WebMethod]
public object MyWebMethod(object parameter)
If there is no parameter in the body of the request then you will get this error.
Did U add ServiceReference Class. Check this once. Based on your comment I can tell what to do
I had this issue because my soap method had a List<string> parameter. Couldn't figure out a way to make it work with the array parameter; so just converted the parameter to a &-delimited string (e.g. val1&val2&val3) and converted the parameter to an array in the service method.
In my case, one of the WebService receiving parameters was called aId. When I called it from javascript, I was sending the correct Id value, but the name of the sent variable was incorrectly called bId. So I just had to rename the WebService call, keep the correct value like before, and just change the variable name.
I'm attempting to call a web service via AJAX in a WebForms application.
My script looks something like this:
$.post('UpdateServer.asmx/ProcessItem',
'itemId=' + $(this).text(),
function (result) {
alert(result);
});
My web service looks something like this.
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class UpdateServer : System.Web.Services.WebService
{
[WebMethod]
public string ProcessItem(int itemId)
{
return new JavaScriptSerializer().Serialize(
new { Success = true, Message = "Here I am!" });
}
}
The web method is called as expected and with the expected argument. However, the argument passed to my success function (last parameter to $.post()) is of type document and does not contain the Success and Message members that I'm expecting.
What's are the magic words so that I can get back the object I'm expecting?
EDIT
On closer inspection, I can find the data I'm looking for as follows:
result.childNodes[0].childNodes[0].data:
"{"Success":true,"Message":"Server successfully updated!"}"
The reason you're seeing that odd structure of nodes that end with JSON is because you're not calling the service the necessary way to coax JSON out of ASMX ScriptServices and then returning a JSON string anyway. So, the end result is that you're returning an XML document that contains a single value of that JSON string.
The two specific problems you're running into right now are that you're manually JSON serializing your return value and you're not calling the service with a Content-Type of application/json (.NET needs that to switch to JSON serializing the response).
Once you fixed those issues, you'd also run into an "invalid JSON primitive" error due to the data parameter being URL encoded instead of a valid JSON string.
To get it working, do this on the server-side:
[ScriptService]
public class UpdateServer : System.Web.Services.WebService
{
[WebMethod]
public object ProcessItem(int itemId)
{
return new { Success = true, Message = "Here I am!" };
}
}
You could also create a data transfer object (aka ViewModel) to return instead of using an anonymous type and object, if you want.
To successfully get raw JSON out of that, do this on the client-side:
$.ajax({
url: 'UpdateServer.asmx/ProcessItem',
type: 'post',
contentType: 'application/json',
data: '{"itemId":' + $(this).text() + '}',
success: function(result) {
// This will be { d: { Success: true, Message: "Here I am!" } }.
console.log(result);
}
});
If you have a few minutes, read through the posts in the communication section of jQuery for the ASP.NET developer. You'll find a lot of that information helpful as you continue down this path.
Note: The links that helmus left were relevant. Nothing has fundamentally changed between 2.0 and present with regards to using ASMX ScriptServices to communicate via JSON. If you're interested in the truly cutting edge approach to this problem in .NET, ASP.NET Web API is the way to go.
Add this attribute to your ProcessItem method:
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
Be more explicit in your $.post call.
$.ajax({
type:'post',
url:'UpdateServer.asmx/ProcessItem',
data: {'itemId':$(this).text()}
}).done(function (result) {
alert(result);
});
Earlier today I posted another post where #Darin Dimitrov helped me great, however once again I'm stucked...
My javascript calls the AddWebsite ActionResult which does it job as it should, however the error function in the $.ajax() is always firing since
return PartialView(ListPartialView, MapUserToViewModel);
isn't valid JSON.
I've come across examples where people use something like
RenderPartialViewToString(partialview, model);
and throws it into a JSON object... but it's just too "hackish" if you ask me.. isn't there an easier way to accomplish this?
... And the code:
// DashboardController.cs
[HttpPost]
public ActionResult AddWebsite(CreateWebsiteViewModel website)
{
if (!ModelState.IsValid)
{
throw new HttpException(400, "Client-side validation failed.");
}
if (string.IsNullOrWhiteSpace(website.URL))
{
throw new ArgumentNullException("URL", "The URL cannot be empty nor contain only whitespaces.");
}
using (_session.BeginTransaction())
{
_session.Query(new AddWebsite(_contextProvider.GetUserSession.UserId, website.URL));
_session.Transaction.Commit();
}
return PartialView(ListPartialView, MapUserToViewModel);
}
// MyJs.js
$("#testform").live('submit', function () {
var test = { URL: $("#URL").val() };
$.ajax({
url: "/Dashboard/AddWebsite",
type: "POST",
data: JSON.stringify(test),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (data) {
alert("TRIG");
$("#content").html(data);
},
error: function () {
alert("Error");
}
});
return false;
});
Thanks in advance!
In your particular instance I think the problem is with your javascript code. You are specifying the dataType (which is what the function expects to parse in the response) as json. Based on the Action you posted you should have html as the dataType and it should solve your problem. There's nothing wrong with doing that (you don't have to use JSON for everything).
Simple data
Why are you setting dataType and contentType in the first place? Since your object test is very simple you can just provide it as is and it will be consumed by Asp.net MVC without any problems and you will return your partial view.
Complex data
If your object would be more complex then you could use a different jQuery plugin that will make it possible to send complex JSON objects without strigification.