I’m submitting a form post using Angularjs (1.2.20) to Microsoft ASP.Net MVC 4:
public ActionResult Save2(FormCollection customer)
{
//TODO: Do some stuffs...
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
However, the FormCollection is empty. I know that the data is being sent because if I change it to the following code below (using strongly type CustomerVm), it works as expected.
public ActionResult Save1(CustomerVm customer)
{
//TODO: Do some stuffs...
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
I’m using FormCollection so that I can add ASP.Net anti-forgery token in the data (instead of headers). Below is my custom javascript code. Also you can find the entire code (Visual Studio) here
You need to send the request with a content-type of application/x-www-form-urlencoded and encode the request body as such. This is a good start but it's sending the data as JSON.
var data = JSON.stringify(customer);
// FormCollection
$http({
method: 'POST',
url: '/Home/Save2',
//dataType: 'json',
contentType: 'application/x-www-form-urlencoded; charset-UTF-8',
//contentType: 'application/json; charset-UTF-8',
data: data
});
Turning the object into a URL encoded form is actually pretty complex. Thankfully, Ben Nadel has already created a transformRequestAsFormPost service to do this via a request transformer. You can give it a try by adding in his code and making this change to yours...
myApp.factory('customerSvc', function ($http, transformRequestAsFormPost) {
return {
// ...
save2: function (customer, antiForgeryToken) {
$http({
method: 'POST',
url: '/Home/Save2',
transformRequest: transformRequestAsFormPost,
data: data
});
}
};
});
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 have a method which Is accesed using Get
[HttpGet]
[AdminAuthorization]
public ActionResult MakeReservation(ReservationModel m)
{
return PartialView(m);
}
here Ajax Code:
$.ajax({
url: "/DeviceUsage/MakeReservation",
type: "GET",
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: JSON.stringify({ data: Ids }),
error: function (data) {
alert("Dodanie nie powiodło się Jeden lub wiecej numerów seryjnych nie są unikalne " + data);
},
success: function (data) {
$('#ProperModal.modal-body').html(data);
$("#Modal").modal('show');
//if (data === "sukces") {
}
});
If I change method description and ajax type to POST function works. How should I modify this code to make it work wiht GET calls?
You need to use JsonRequestBehavior.AllowGet in your controller. For more information you could read this answer on SO
And I think it is good practise to return Json (not PartialView) in your action (for ajax). If you want to return PartialView, you could use this technique
You don't need to explictly tell the HttpGet, By Default, it takes it as HttpGet, but if you put HttpPost attribute, then it does not work on Get Requests.
Same is the case for Jquery ajax, if you don't tell it, its get or post request, it by default makes a get request to server
Remove contentType and dataType: 'json' (this indicates you are returning json, but your code returns a partial view). And Remove JSON.stringify as jQuery accept your JS object directly. Haven't tested it, but it should work.
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.
All the examples of json I can find online only show how to submit json arrays w/ the jquery command $.ajax(). I'm submitting some data from a custom user control as a json array. I was wondering if it's possible to submit a json array as a regular post request to the server (like a normal form) so the browser renders the page returned.
Controller:
[JsonFilter(Param = "record", JsonDataType = typeof(TitleViewModel))]
public ActionResult SaveTitle(TitleViewModel record)
{
// save the title.
return RedirectToAction("Index", new { titleId = tid });
}
Javascript:
function SaveTitle() {
var titledata = GetData();
$.ajax({
url: "/Listing/SaveTitle",
type: "POST",
data: titledata,
contentType: "application/json; charset=utf-8",
});
}
Which is called from a save button. Everything works fine but the browser stays on the page after submitting. I was thinking of returning some kind of custom xml from the server and do javascript redirect but it seems like a very hacky way of doing things. Any help would be greatly appreciated.
This is an old question but this might be useful for anyone finding it --
You could return a JsonResult with your new titleId from the web page
public ActionResult SaveTitle(TitleViewModel record) {
string tId = //save the title
return Json(tId)
}
and then on your ajax request add a success function:
function SaveTitle() {
var titledata = GetData();
$.ajax({
url: "/Listing/SaveTitle",
type: "POST",
data: titledata,
contentType: "application/json; charset=utf-8",
success: function(data) { window.location = "/Listing/Index?titleId=" + data; }
});
}
That would redirect the page after a successful ajax request.
I just saw that you mentioned this at the end of your post but I think it is an easy and quick way of getting around the issue.
Phil Haack has a nice post discussing this scenario and shows the usage of a custom value provider instead of an action filter.
I don't understand why you would want to post Json if you're wanting to do a full page post. Why not just post normal form variables from the Html form element?