Using knockout I am trying to send data, from my UI to the controller. This is the javascript used to send my ajax request(PUT)
var model = new Object();
model.StudentID = "";
model.ActiveProgram = "";
model.ProgramDesc = self.programData();
model.Cohorts = self.associationData();
model.LoadIntent = self.loadIntentData();
model.Francophone = self.frenchData();
model.Gender = self.genderData();
$.ajax({
url: putStudentRegRequirementsUrl,
type: "PUT",
contentType: jsonContentType,
dataType: "json",
data: JSON.stringify(model),
//jsonData:model,
success: function (data) {
$('#notificationHost').notificationCenter('addNotification', { message: "Updated.", type: "info" });
},
error: function (jqXHR, textStatus, errorThrown) {
if (jqXHR.status != 0)
{
$('#notificationHost').notificationCenter('addNotification', { message: "Unable to update registration requirement.", type: "error"});
}
}
});
But when I debug it to see my controller, the string comming in is blank. This is my controller
[HttpPut]
public async Task<JsonResult> UpdateRegistrationRequirementAsync(string regRequirementJson)
{
try
{
var regRequirementModel = JsonConvert.DeserializeObject<RegistrationRequirement>(regRequirementJson);
var response = await ServiceClient.L09PutRegistrationRequirementAsync(CurrentUser.PersonId, regRequirementModel);
return Json(response);
}
catch( Exception ex)
{
Logger.Debug(ex, "Error updating Registration Requirement for user failed.");
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json("Error updating Registration Requirement.");
}
}
Action will parse parameters from client by its name, so you need to pass parameter with name regRequirementJson contains your json. So change this line
data: JSON.stringify(model)
to
data: { regRequirementJson: JSON.stringify(model) }
and remove contentType: jsonContentType.
Or you can try another way. Since ASP.NET can deserialize json by itself you can keep your js code as is and update your controller to
[HttpPut]
public async Task<JsonResult> UpdateRegistrationRequirementAsync(RegistrationRequirement regRequirementModel )
{
try
{
var response = await ServiceClient.L09PutRegistrationRequirementAsync(CurrentUser.PersonId, regRequirementModel);
return Json(response);
}
catch( Exception ex)
{
Logger.Debug(ex, "Error updating Registration Requirement for user failed.");
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json("Error updating Registration Requirement.");
}
Since you are sending a "RegistrationRequirement" object then in your controller you can do it this way :
[HttpPut]
public async Task<JsonResult> UpdateRegistrationRequirementAsync(RegistrationRequirement registrationRequirement)
{
try
{
var response = await ServiceClient.L09PutRegistrationRequirementAsync(CurrentUser.PersonId, registrationRequirement);
return Json(response);
}
catch( Exception ex)
{
Logger.Debug(ex, "Error updating Registration Requirement for user failed.");
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json("Error updating Registration Requirement.");
}
}
Related
I am having a strange issue that is up above my level, I tried to troubleshoot the issue without luck.
I am developing a simple MVC application and I am using ajax to send data from a view to controller. For some reason, the controller only recognized the fist parameters and the rest are just nulls. I even tried to put fixed strings instead of variables but they still appear as null from the controller???
The view:
$.ajax({
type: "POST",
url: "../Home/AddItem",
data: "{ItemModel: 'ttt1', ItemName: 'ttt2'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
console.log(JSON.stringify(data));
if (data.Success == "Success") {
alert("Item has been added.");
} else {
alert("We were not able to create the offer");
}
},
error: function (exception) {
console.log(exception);
}
});
On the Home controller, I have the below action:
[HttpPost]
public JsonResult AddItem(string ItemModel, string ItemName)//ItemName is always null??
{
try
{
_DB.Database.ExecuteSqlCommand(#"INSERT INTO ITEMS(iModel, iName) VALUES ({0}, {1})", ItemModel, ItemName);
return Json(new { Success = "Success" });
}
catch (Exception ex)
{
throw ex;
}
}
You are not sending the data correctly.
The code indicates JSON but is sending just a single string. If you inspect ItemModel, I am certain it will contain the string data sent from the client.
Create a JavaScript object and then stringify that as the body of the request.
var payload = { ItemModel: 'ttt1', ItemName: 'ttt2' }; //<-- create object
$.ajax({
type: "POST",
url: "../Home/AddItem",
data: JSON.stringify(payload), //<-- properly format for request
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
console.log(JSON.stringify(data));
if (data.Success == "Success") {
alert("Item has been added.");
} else {
alert("We were not able to create the offer");
}
},
error: function (exception) {
console.log(exception);
}
});
The model binder should then be able to differentiate the desired parameters.
Ideally when expecting data in the body of a request it is better to use a model
public class Item {
public string ItemModel { get; set; }
public string ItemName { get; set; }
}
And have the action explicitly look for it in the body of the request using the FromBody attribute
[HttpPost]
public JsonResult AddItem([FromBody]Item item) {
if(ModelState.IsValid) {
try {
var sql = #"INSERT INTO ITEMS(iModel, iName) VALUES ({0}, {1})";
_DB.Database.ExecuteSqlCommand(sql, item.ItemModel, item.ItemName);
return Json(new { Success = "Success" });
} catch (Exception ex) {
throw ex;
}
}
return Json(new { Success = "BadRequest" });
}
I am trying to submit a form via ajax like this:
$(document).ready(function () {
$("#form").submit(function (e) {
e.preventDefault();
var token = $('input[name="__RequestVerificationToken"]', this).val();
var form_data = $(this).serialize();
$.ajax({
url: "#Url.Action("SaveRole", #ViewContext.RouteData.Values["controller"].ToString())",
method: "POST",
data: form_data,
contentType: "application/json",
success: function (result) {
console.log(result);
},
error: function (error) {
console.log(error);
}
});
return false;
console.log(form_data);
});
});
This contacts this controller:
[HttpPost]
[ValidateAjax]
[ValidateAntiForgeryToken]
public ActionResult SaveRole(SaveRolesDetailsViewModel Input)
{
//var role = rolesData.GetByName(Input);
var result = this.Json(new
{
Output = Input
}, JsonRequestBehavior.DenyGet);
return result;
}
Right now, I'm getting errors that my RequestVerificationToken field is not being submitted but I'm not sure how I can combine it with my form data. By default, when I serialize my form data, it already sends this token but for some reason my controller still fails it.
Also, how do I use the modelstates to show my form validations? Right now they are returned as json objects.
EDIT:
AjaxValidate Attribute:
public class ValidateAjax : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest())
return;
var modelState = filterContext.Controller.ViewData.ModelState;
if (!modelState.IsValid)
{
var errorModel =
from x in modelState.Keys
where modelState[x].Errors.Count > 0
select new
{
key = x,
errors = modelState[x].Errors.
Select(y => y.ErrorMessage).
ToArray()
};
filterContext.Result = new JsonResult()
{
Data = errorModel
};
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
}
}
}
When I submit an empty form, this is what is returned:
0:{key: "RoleName", errors: ["The Role Name field is required."]}
When you use the jQuery .serialize() method, it generates query string format (i.e. ..&name=value&..., which needs to be sent using the default contentType - i.e 'application/x-www-form-urlencoded; charset=UTF-8'.
Remove the contentType: "application/json", from the ajax options.
In addition, your var token = $('input[name="__RequestVerificationToken"]', this).val(); line of code is not necessary - the token is included when you use .serialize()
$("#form").submit(function (e) {
e.preventDefault();
// Add the following if you have enabled client side validation
if (!$(this).valid()) {
return;
}
var form_data = $(this).serialize();
$.ajax({
url: "#Url.Action("SaveRole")",
method: "POST",
data: form_data,
success: function (result) {
... // see notes below
},
error: function (error) {
console.log(error);
}
});
// return false; not necessary since you have used e.preventDefault()
console.log(form_data);
});
To return ModelState errors, remove your ValidateAjaxAttribute - returning a BadRequest is not appropriate (which is intended to indicate that the server could not understand the request due to invalid syntax).
Instead modify the POST method to return a JsonResult that includes the errors (note there is no need to return the model)
public ActionResult SaveRole(SaveRolesDetailsViewModel Input)
{
if (ModelState.IsValid)
{
return Json(new { success = true });
}
else
{
var errors = ModelState.Keys.Where(k => ModelState[k].Errors.Count > 0).Select(k => new { propertyName = k, errorMessage = ModelState[k].Errors[0].ErrorMessage });
return Json(new { success = false, errors = errors });
}
}
Then in the success callback, if there are errors, loop through them and find the corresponding <span> element generated by your #Html.ValidationMessageFor() and update its contents and class names
success: function (result) {
if (result.success) {
return;
}
$.each(result.errors, function(index, item) {
// Get message placeholder
var element = $('[data-valmsg-for="' + item.propertyName + '"]');
// Update message
element.append($('<span></span>').text(item.errorMessage));
// Update class names
element.removeClass('field-validation-valid').addClass('field-validation-error');
$('#' + item.propertyName).removeClass('valid').addClass('input-validation-error');
});
},
$("#modelchange").change(function() {
$.ajax({
type: 'POST',
url: '#Url.Action("GetStore")',
dataType: 'json',
data: {
Id: $("#modelchange").val()
},
success: function(storeName) {
$('#storeName').text("Store : " + storeName);
},
error: function(ex) {
alert('Failed to load store Value');
}
});
return false;
});
API
[HttpPost]
public string GetStore(int Id)
{
string storeName = db.AddInktoStores.Single(a => a.InkId == Id)).Store.StoreName;
return storeName;
}
Above mentioned is a controller and JSON in my javascript.
I am trying to get Store Name but I keep getting throw into my error: function
Please Help!
Try to return data as:
[HttpPost]
public JsonResult GetStore(int Id)
{
string storeName = db.AddInktoStores.Single(a => a.InkId == Id)).Store.StoreName;
return Json(storeName);
}
I am making a simple ajax call to the web api service that serves an authentication routine.
My problem is the ajax call can make a request to the service but errors out once the service returns a boolean value.
WHAT I WANT:
All i want to do is check if the returned boolean is true or false. If true i want to redirect the user to another page.
Could somebody please help me out on this?
JQUERY CODE:
<script type="text/javascript">
$(document).ready(function () {
$('#submitButton').click(function () {
var name = $(userNameTextBox).val);
var pass = $(passwordTextBox).val();
if (name.length == 0 || pass.length == 0) {
alert("Please enter your credentials");
}
else {
$.ajax({
url: "http://localhost:50503/api/Authentication/Authenticate",
data: { userName: name, passWord: pass },
cache: false,
type: 'GET',
dataType: 'json',
success: function (msg) {
alert(msg);
},
error: function (msg) {
alert("Error Message: "+msg);
}
});
}//end of else
});
});
</script>
Here is my webapi service
public class AuthenticationController : ApiController
{
[HttpGet]
[Route("api/Authentication/Authenticate")]
public bool Authenticate(string userName,string passWord)
{
if (userName.ToLower().Equals("username") && passWord.ToLower().Equals("password"))
{
return true;
}
else
{
return false;
}
}
}
You can try replace your ajax call by this maybe, remove the dataType:
var request = $.ajax({
url: "http://localhost:50503/api/Authentication/Authenticate",
cache: false,
type: 'POST',
data: { userName: userName, passWord: passWord }
});
request.done(function (msg) {
//check the boolean and redirect user to another page.
if(msg) window.location.href = "http://nextpage.com";
});
i also change the method to POST. More appropriate in your case.
If all else fails, put a debugger breakpoint (e.g., via the debugger directive in your error callback to $.ajax and run your code in the browser's debugger (i.e. Chrome dev tools). Then, after the breakpoint is hit, you should be able to determine (by walking the stack) why the error callback is invoked.
My Test
I've tried to reproduce your case, and for me it doesn't fail. I've defined a test controller in the following way:
using System.Web.Http;
namespace Test
{
public class TestController : ApiController
{
[HttpGet]
public bool Authenticate(string username, string password)
{
return username == "user" && password == "pass";
}
}
}
And I make an AJAX call to it from JavaScript like so:
$.ajax({url: 'http://localhost:59900/api/test', type: 'get', dataType: 'json', cache: false, data: { userName: 'user', passWord: 'pass' }}).done(function () {console.log("Success", arguments);}).fail(function () { console.log("Error", arguments); });
The AJAX call invokes the success callback (done) with true as its result, so no issues at all.
Parser Error
It appears that jQuery can't parse the JSON sent from Web API (true). To return valid JSON, return an object of the following type from your controller:
public class Result
{
public bool Result { get;set; }
}
This should result in the following JSON being sent to your client:
{ "Result": true }
Updated controller:
namespace Test
{
public class TestController : ApiController
{
[HttpGet]
public Result Authenticate(string username, string password)
{
return new Result { Result = username == "user" && password == "pass" };
}
}
}
Try to use (worked for me, check responseJSON.Message of first parameter object):
$.post(url, jsonData).
done(function (data) {}).
fail(function (xhr, status, err) {
alert("Error " + err + ". " + xhr.responseJSON.Message);
});
I have an ajax call to my controller, which in turn calls a service which returns true or false. I cannot seem to figure out why this always triggers my success function when it returns from controller to view.
Controller
[HttpGet]
public JsonResult TagUnit(int id, string selectedItem)
{
try
{
var result = UnitClient.TagUnit(id, selectedItem);
if (!result)
{
throw new InvalidOperationException();
}
return Json(new {success = true}, JsonRequestBehavior.AllowGet);
}
catch (Exception e)
{
return Json(new {success = false}, JsonRequestBehavior.AllowGet);
}
}
Cshtml - Javascript - Ajax
.on("select2-selecting", function (e) {
var url = '#Url.Content("~/UnitDetails/TagUnit/" + Model.ViewUnitContract.Id)';
var id = e.val;
var tagName = e.object.text;
console.log(id + " : " + tagName);
$.ajax({
url: url,
data: { selectedItem: tagName },
type: 'GET',
dataType: 'json',
success: function () {
alert('Success');
},
error: function () {
alert('Error');
}
});
}).select2('val', ['1', '2']);
What am I missing here?
You should validate server result data in success method.
$.ajax({
url: url,
data: { selectedItem: tagName },
type: 'GET',
dataType: 'json',
success: function (data) {
if (data != null && data.success) {
alert('Success');
} else {
alert('Error');
}
},
error: function () {
alert('Error');
}
});
Error method calls if on the server occurred 500 error or server is not avaliable, etc.
I think that if you throw an exception, it will still return with a success status code. So what I have done is create an ajax call error handler attribute that can be attached to your MVC methods. It will capture uncaught exceptions, set an error status code and give a generic error message (and also log to Elmah). The attribute is below
public class HandleJsonErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
var serviceException = filterContext.Exception as Exception;
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
filterContext.Result = new JsonResult
{
Data = new
{
errorMessage = "Generic error message",
errorType = 0
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
var kayttaja = (Kayttaja.TKayttajantiedot)filterContext.HttpContext.Session["userKayttajanTiedot"];
Global.HandleApplicationError(serviceException, kayttaja);
filterContext.ExceptionHandled = true;
// Log to elmah
//Elmah.ErrorSignal.FromCurrentContext().Raise(filterContext.Exception);
}
}
Then decorate your action methods that should only be called by Ajax with: [Campus.Attribuutit.HandleJsonError]
The important line for triggering the error handler in the ajax call object is HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError
Don't know if I understand your question properly.
success function in Ajax will execute if the request is successful. And error function will execute if the request fails. You have to check what the server returns inside of the success function.
http://api.jquery.com/jQuery.ajax/