I'm unable to post JSON object in the body of my HTTP message.
I have even tried this
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
but it still didn't work
Here is my code:
<!DOCTYPE html>
<html lang="en">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="formCtrl">
<form novalidate>
type:<br>
<input type="number" ng-model="config.type"><br>
Id:<br>
<input type="text" ng-model="config.Id">
<br><br>
<button ng-click="submit()">Submit</button>
</form>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('formCtrl', function($scope,$http) {
$scope.config = {type:0, Id:"786"};
$scope.submit = function() {
var data = $scope.config;
//$http.post("http://localhost:8612/api/values/", data);
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "http://localhost:8612/api/values/", true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.send(JSON.stringify(data));
alert("Done");
};
});
</script>
</body>
</html>
I am getting an error that is my object is empty in this method
// POST api/values
[HttpPost]
public IActionResult Post([FromBody]object c)
So the deserialization is failing probably. having the request model as object type is wrong; instead you should define a proper request model and use that rather like
public class ApiRequestModel
{
// define all your required properties client going to send
}
[HttpPost]
public IActionResult Post([FromBody] ApiRequestModel c)
Related
My textbook says that "TempData gets destroyed immediately after it’s used in subsequent HTTP request", so I write a simple test to verify
below is my code:
// SimpleForm.cshtml is just a simple view that uses a form to send post request to ReceiveForm action method
//Result.cshtml is just a simple view that products an output
public class HomeController : Controller
{
public ViewResult Index() => View("SimpleForm");
[HttpPost]
public RedirectToActionResult ReceiveForm(string name, string city)
{
TempData["name"] = name;
TempData["city"] = city;
return RedirectToAction(nameof(Transfer));
}
public RedirectToActionResult Transfer()
{
string name = TempData["name"] as string;
string city = TempData["city"] as string;
return RedirectToAction(nameof(Data));
}
public ViewResult Data()
{
string name = TempData["name"] as string;
string city = TempData["city"] as string;
return View("Result", $"{name} lives in {city}");
}
}
so when the application runs, it goes to Index() action method first, I fill up the form with name and city and press submit button, then it goes to ReceiveForm() action method, which setup TempData and redirect to Transfer() action method.
In the Transfer() action method, I read TempData, so TempData should get destroyed and unavailable to read in the next http request according to the textbook.
But in the Data(), I find that I can still read TempData, see the screenshot below:
and I checked the chrome dev tool, there was one post request and two get requests, which is all good and correct. so when does TempData actually get destroyed ?
additional code:
SimpleForm.cshtml:
#{ Layout = null; }
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Controllers and Actions</title>
<link rel="stylesheet" asp-href-include="lib/bootstrap/dist/css/*.min.css" />
</head>
<body class="m-1 p-1">
<form method="post" asp-action="ReceiveForm">
<div class="form-group">
<label for="name">Name:</label>
<input class="form-control" name="name" />
</div>
<div class="form-group">
<label for="name">City:</label>
<input class="form-control" name="city" />
</div>
<button class="btn btn-primary center-block" type="submit">Submit</button>
</form>
</body>
</html>
Result.cshtml:
#model string
#{ Layout = null; }
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Controllers and Actions</title>
<link rel="stylesheet" asp-href-include="lib/bootstrap/dist/css/*.min.css" />
</head>
<body class="m-1 p-1">
Model Data: #Model
</body>
</html>
For your scenario, this is caused by RedirectToActionResult. For RedirectToActionResult, which is IKeepTempDataResult.
public class RedirectToActionResult : ActionResult, IKeepTempDataResult
SaveTempDataFilter is filter that saves temp data. It will call SaveTempData.
private static void SaveTempData(
IActionResult result,
ITempDataDictionaryFactory factory,
IList<IFilterMetadata> filters,
HttpContext httpContext)
{
var tempData = factory.GetTempData(httpContext);
for (var i = 0; i < filters.Count; i++)
{
if (filters[i] is ISaveTempDataCallback callback)
{
callback.OnTempDataSaving(tempData);
}
}
if (result is IKeepTempDataResult)
{
tempData.Keep();
}
tempData.Save();
}
For SaveTempData, it will check whether IActionResult result is IKeepTempDataResult. If it is, it will keep the tempData.
If you want to avoid keep tempData between request, you could change RedirectToAction to LocalRedirect like
public IActionResult Transfer()
{
string name = TempData["name"] as string;
string city = TempData["city"] as string;
return LocalRedirect("~/Home/Data");
//return RedirectToAction(nameof(Data));
}
Here is my current setup to upload a file to my webapp:
HTML:
<iframe name="myframe" id="frame1" class="hidden"></iframe>
<form target="myframe" method="post" enctype="multipart/form-data" action="/api/User/collection">
<input type="file" name="file" />
<input type="submit" value="Upload" />
</form>
Controller:
// POST api/user/collection
[HttpPost("collection")]
public ActionResult<IResponse> SetCollection(IFormFile file)
{
var collection = fileDeflator.UnzipAndGetCollection(file);
if (collection == null)
return BadRequest(new BaseResponse("The collection file is invalid."));
return base.SetUserCollection(collection);
}
It's working, except that there is no feedback at all for the client.
I would prefer that the JSON returned by the server be caught in a javascript callback on the web page (not the iframe) and be parsed to refresh a section on the page.
Is that possible with the nature of form submit ?
I ended with something working as I wanted with the helpful resources that Amy provided.
Here is the solution:
<form id="formSendCollection">
<input type="file" id="fileCollection" name="fileCollection" />
<span onclick="submitCollection();" class="button is-primary">Submit</span>
</form>
function submitCollection() {
var fdata = new FormData();
var fileCollection = document.getElementById('fileCollection').files[0];
fdata.append("fileCollection", fileCollection);
sendAjax('/api/User/Collection', fdata, function (body) {
vueApp.modelUser.collection = JSON.parse(body);
});
}
function sendAjax(url, body, callback) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === XMLHttpRequest.DONE) {
callback(xmlhttp.responseText);
}
};
xmlhttp.open('POST', url, true);
xmlhttp.send(body);
}
i want to send my data from view to controller using ajax but I can't send the data to controller.
Thanks for your help.
That's my View code,
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>SignUp</title>
<link href="../../css/bootstrap.min.css" rel="stylesheet">
<link href="../../css/signin.css" rel="stylesheet">
<script type="text/javascript" src="../../js/jquery-1.11.0.min.js"></script>
<script type="text/javascript">
$(document).on("click", "#btnSignUp", function () {
var tcNo = document.getElementById('inputTcn').value;
var nameSurname = document.getElementById("Name").value;
var eMail = document.getElementById('Email').value;
var number = document.getElementById("PhoneNumber").value;
var secretQuestionAnswer = document.getElementById("inputSecretQuestionAnswer").value;
var password = document.getElementById('inputPassword').value;
var passwordVerify = document.getElementById("passwordVerify").value;
//var stateValue = document.getElementById("viewStates").value;
$.ajax({
type: 'POST',
url: '/Home/SignUp',
dataType: 'json',
data: {
'tcNo': tcNo,
'nameSurname': nameSurname,
'eMail': eMail,
'number': number,
'secretQuestionAnswer': secretQuestionAnswer,
'password': password,
'passwordVerify': passwordVerify,
'stateValue': stateValue
},
success: function (msg) {
alert("bsg");
},
error: function (msg) {
alert("2");
}
});
});
</script>
</head>
<body>
<div class="container">
<form class="form-signin">
<h2 class="form-signin-heading"></h2>
<input id="inputTcn" class="form-control" placeholder="T.C. NO GİRİNİZ" required="" autofocus="">
<input id="Name" class="form-control" placeholder="ADINIZI SOYADINIZI GİRİNİZ" required="">
<input id="Email" class="form-control" placeholder="E-MAIL GİRİNİZ" required="">
<input id="PhoneNumber" class="form-control" placeholder="GSM NUMARANIZI GİRİNİZ" required="">
<input id="inputSecretQuestionAnswer" class="form-control" placeholder="ÖZEL SORUNUZUN CEVABINI GİRİN">
<input type="password" id="inputPassword" class="form-control" placeholder="ŞİFRENİZİ GİRİNİZ" required="">
<input type="password" id="passwordVerify" class="form-control" placeholder="ŞİFRENİZİ TEKRAR GİRİNİZ" required="">
#Html.DropDownList("viewStates")
<a id="btnSignUp" class="btn btn-lg btn-primary btn-block btn-danger">KAYIT OL</a>
</form>
</div>
</body>
</html>
and here that's my Controller,
[HttpPost]
public ActionResult SignUp(string tcNo, string nameSurname, string eMail, string number,
string secretQuestionAnswer, string password, string passwordVerify, string stateValue)
{
return View();
}
and I add data to my Dropdownlist at here,
[HttpGet]
public ActionResult SignUp()
{
var database = new KargoDB();
List<SelectListItem> stateList = (from s in database.States
select new SelectListItem
{
Text = s.Description,
Value = (s.State_id).ToString()
}).ToList();
ViewBag.viewStates = stateList;
return View();
}
500 error code means Internal server error. That means your server side code is crashing in the HttpPost Signup method.
If you open the network tab of your browser,and click on the response of the request you made, you will be able to see the response (Exception details returned by asp.net mvc). That will help you to identify the issue.
In your HttpPost action method, you called return View() ,which is going to return the Signup.cshtml razor view. But in the signup view, similar to our GET action, It is going to look for ViewBag.viewStates to render the state dropdown. But we did not set that in our HttpPost Signup method. So it will end up with a null reference exception when razor tries to render the view.
Remember, Http is stateless. One request does not have no idea what happened in the previous request. That means, the request for HttpPost action does not have any idea of the ViewBag items you set in the previous request(GET request).
Typically, for action methods which serves ajax posts, It is good to return a JSON response.
So instead of return View(), return a json structure.
[HttpPost]
public ActionResult SignUp(string tcNo, string nameSurname, string eMail,
string number,string secretQuestionAnswer, string password,
string passwordVerify, string stateValue)
{
return Json(new {status = "success"});
}
This is going to return a json structure like
{"status" : "success"}
And you can read that in your success event handler
success: function (msg) {
console.log(msg);
if(msg.status==="success")
{
alert("Saved");
}
}
Also, looks like you have a lot of parameters being posted to the Signup method, instead of writing so many params, you should use a view model.
Here is an example on how to do that.
Instead of returning a view from the controller return a JSON result and parse the result and bind it to the dropdown.
Since you are trying to retrieve data from the HTTPGet controller, you should be using the HTTP method of Get.
[HttpGet]
public JSONResult SignUp()
{
return Json(resultset, JsonRequestBehavior.AllowGet);
}
success: function (msg) {
// parse msg and bind to dropdown
},
Try using JSON.NET
For a detailed read
As mentioned above, http 500 is because of an exception in .Net code.Are you getting this in development. If so give the details of exception. You may attached to W3Wp.exe if you are doing it in some different way.
If this is hosted in dev / QA servers, use remote debugging mechanism. In production look at windows eventviewer. Sometimes you will see what is the exception. Once the exception is visible, just google or post it here.
http://www.codeproject.com/Articles/38132/Remote-IIS-Debugging-Debug-your-ASP-NET-Applicatio
I can't seem to get anything displayed in my div which has the attribute "ng-view".
Here is my controller;
(function () {
var app = angular.module("userViewer", []);
var MainController = function ($scope, $location) {
console.log("Main controller");
$scope.search = function () {
console.log("User ID: " + $scope.userid);
//Right Route Here
};
};
app.controller("MainController", MainController);
}());
Here is my app.js:
(function() {
var app = angular.module("userViewer", ['ngRoute']);
console.log("Test route");
app.config(function($routeProvider) {
$routeProvider.when("/main", {
templateUrl: "html/main.html",
controller: "MainController"
})
.otherwise({ redirectTo: "/main" });
});
}());
My master template:
<!DOCTYPE html>
<html ng-app="userViewer" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
#Scripts.Render("~/bundles/angular")
</head>
<body>
#RenderBody()
</body>
</html>
My angular SPA main page html body:
<h2>Header</h2>
<div ng-view>
</div>
My main.html
<div>
<form name="searchUser" ng-submit="search()">
<input type="search" required ng-model="userid" placeholder="User ID to find" />
<input type="submit" value="Search" />
</form>
</div>
My console.log within app.js "Test route prints but when I navigate to URL/#/main nothing is shown.
Just the word "Header" and the main.html view is not loaded atall.
There is also no errors displayed in the console.
Can anyone give me some advice?
In your controller you are doing this
var app = angular.module("userViewer", []);
When you put the [] in there you are creating a new module. Try
var app = angular.module("userViewer");
to reference your existing one.
(function() {
var app = angular.module("userViewer", ['ngRoute']);
console.log("Test route");
app.config(function($routeProvider) {
$routeProvider.when("/main", {
templateUrl: "/html/main.html", <-- try to locate the view starting from the root path of the app
controller: "MainController"
})
.otherwise({ redirectTo: "/main" });
});
}());
try to define your controller as:
angular.module('userViewer').controller('MainController', ['$scope', '$location', function ($scope, $location) {
//your code here
}]);
change app.js to
(function () {
var MainController = function ($scope, $location) {
console.log("Main controller");
$scope.search = function () {
console.log("User ID: " + $scope.userid);
//Right Route Here
};
};
app.controller("MainController", MainController);
}());
public void Post([FromBody]DateTime value)
{
// do something
}
value should be always in yyyy-MM-dd format
I believe that when you want to validate more than just the fact that the type matches but that the data passed in as a primitive from the body of the request matches some desired format that validation must be done in the action method if it is not done at the client level. This is one attempt that I came up with that seemed to provide the desired behavior.
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<script src="~/Scripts/jquery-2.1.4.js"></script>
<script src="~/Scripts/bootstrap.js"></script>
<link href="~/Content/bootstrap.css" rel="stylesheet" />
<link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
<script src="~/Scripts/question2ClientController.js"></script>
</head>
<body>
<div>
<button id="submit" class="btn btn-primary">submit</button>
<input id="mydate" type="text" size="10" />
</div>
</body>
</html>
contents on the question3bclientcontroller.js file
var request = function (event) {
var ajaxOptions = {};
ajaxOptions.url = "/api/question3api";
ajaxOptions.type = "POST";
ajaxOptions.data = {'' : '' + event.data.val()};
ajaxOptions.success = function (result) {
console.log(result);
};
ajaxOptions.error = function (jqXHR) {
console.log("found error");
console.log(jqXHR);
};
$.ajax(ajaxOptions);
}
$(function () {
var date = $("#mydate");
$('#submit').click(date, request);
})
Api Controller Action Method
public IHttpActionResult PostDate([FromBody]string dateString)
{
try
{
DateTime myDate = DateTime.ParseExact(dateString, "yyyy-MM-dd", CultureInfo.InvariantCulture);
return Ok(HttpStatusCode.NoContent);
}
catch (Exception e)
{
return BadRequest("Unable to parse value in post to DateTimeString");
}
}