I am trying to validate the content of an excel file in a mvc controller. I have some simple html input with a javascript script that retrieves the content of the file in JSON format. I then proceed to call an action that has to validate the JSON. If it is valid it should redirect to the home page. If not valid it should cancel the action and display an alert containing feedback. Here is the action:
public IActionResult Upload()
{
string json = Request.Form["xlx_json"].ToString(); //Text area containing json
try
{
List<WarehouseOrderModel> orders = JsonConvert.DeserializeObject<List<WarehouseOrderModel>>(json, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
});
string validation_results = RequestBodyValidator.Validate(orders);
if (string.IsNullOrEmpty(validation_results))
return RedirectToAction("Index", "WarehouseOrders");
else
// invalid in this case
} catch
{
// invalid in this case
}
}
I have already tried everything from this question, I just can't seem to make it work. I would appreciate your help. Thanks in advance.
You can Use Ajax and in controller use Ok and BadRequest result for your validation then you can check in Ajax if error happend show alert and if successed redirect it to where you want.
in client:
$.ajax({
url: url,
data: $('input[name="xlx_json"]').val(),
cache: false,
success: function (result) {
window.location.href = "your url";
},
error: function (xhr, status, error) {
// Display a generic error for now.
//alert("AJAX Error!");
}
});
in backend:
public IActionResult Upload()
{
string json = Request.Form["xlx_json"].ToString(); //Text area containing json
try
{
List<WarehouseOrderModel> orders = JsonConvert.DeserializeObject<List<WarehouseOrderModel>>(json, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
});
string validation_results = RequestBodyValidator.Validate(orders);
if (string.IsNullOrEmpty(validation_results))
return OK();
else
return BadRequest();
} catch
{
return BadRequest();
}
}
Related
const [payload, setPayload] = useState({
Email: null,
Password: null
});
const handleSubmit = async (e) => {
e.preventDefault();
var json = JSON.stringify(payload);
try {
const { data } = await axios.post(
"https://localhost:5001/api/User/Login",
{
json
}
);
console.log(data);
ctxDispatch({ type: "USER_LOGIN", payload: data });
localStorage.setItem("userInfo", JSON.stringify(data));
toast.success("Login Successful");
navigate("/");
} catch (err) {
toast.error(getError(err));
}
};
[AllowAnonymous]
[HttpPost("Login")]
public async Task<ActionResult<UserDTO>> Login([FromBody] LoginDTO loginDTO)
{
//LoginDTO loginDTO = Newtonsoft.Json.JsonConvert.DeserializeObject<LoginDTO>(input);
var pwd = Encrypt.ConvertToEncrypt(loginDTO.Password);
User currentUser = await _context.user.FirstOrDefaultAsync(user =>
user.Email.ToLower() == loginDTO.Email.ToLower()
&&`enter code here`
user.Password == pwd);
}
public class LoginDTO
{
public string Email { get; set; }
public string Password { get; set; }
}
When I post this string to my backend it attempts to parse my string but fails at the first char {. When i send this string wrapped in quotes through swagger it passes with no issues. When i send this string through postman with no quotes wrapped around the string I get the same exact error as i get when posting through my frontend.
fix the action input parameters, you don't need to deserialize it , it will be deserialized by MVC
public async Task< ....([FromBody] LoginDTO loginDto)
and since you are sending a json string, add content type to axios
axios.post('..your url', json, {
headers: {
// Overwrite Axios's automatically set Content-Type
'Content-Type': 'application/json'
}
});
The intention of the code:
The intention of this code is to accept data passed to it through the scope and place in an array to be passed to a Login controller (Server Side) via AJAX.
The Problem
The AJAX code does not seem as if it is successfully contacting the serverside action.
I have tried moving the action from the login controller to the home controller: No success.
I have tried following the guidelines of those who previously ran into this issue: No success.
I have tried hardcoding the URL to the action: No success.
Below is the AJAX Call:
login: function (username, password) {
var cred = { "uname": username, "pass": password };
var response = $http({
method: "POST",
url: '#(Url.Action("CheckUser","Login"))',
data: JSON.stringify({ model: cred }),
contentType: 'application/json; charset=utf-8',
dataType: "JSON",
success: function (msg) {
if (msg) {
console.log("success: " + msg);
}
},
error: function (msg) {
if (msg) {
console.log("Error:" + msg);
}
},
failure: function (msg) {
if (msg) {
console.log("fail: " + msg);
}
}
});
Next the action code:
namespace test4.Controllers
{
public class LoginController : Controller
{
// GET: Login
public ActionResult Login()
{
return View();
}
public class UserCred
{
public string Uname { get; set; }
public string Pass { get; set; }
}
[HttpPost]
public ActionResult CheckUser(UserCred umodel)
{
Console.WriteLine("I am here");
if (!ModelState.IsValid)
{
return Content("0");
}
string uname = umodel.Uname;
string pword = umodel.Pass;
using (localtestEntities entity = new localtestEntities()) {
var user = entity.users.Where(u => u.uname == uname).FirstOrDefault();
if (user != null) {
if (pword == user.pw) {
Session["LoginID"] = user.id;
Session["Username"] = user.fname + ' ' + user.lname;
return Content(user.id.ToString());
} else {
return Content("0");
}
} else {
return Content("0");
}
}
/* Begin Assigning values */
} //End Check User
}
}
The intended result is to pass back to the client side code whether the comparison of strings passed and what is in the database matches.
A couple things:
$Http({... is not an actual ajax function. I would recommend using $.post() for [HttpPost] and $.get() for [HttpGet]. You can review this in detail from jQuery's documentation here: https://api.jquery.com/jquery.post/
That URL will not work. You can't access razor helper methods inside of JS. As is, you're literally passing #(Url.Action("CheckUser","Login")) into your url so it would look something like localhost:3000/#(Url.Action("CheckUser","Login")) which obviously is not a legit route. You're going to have to get that URL to your ajax function a different way. Some options:
1) In the header of your .cshtml file, do something like:
<script>
$(() => {
const url = `#Url.Action("CheckUser","Login")`;
//Pass that into your JS code via a constructor parameter if your JS
//is a class or by function parameter if your JS code is a function.
const myJSClassNameHere = new myJSClassHere(url);
});
</script>
2) you can just hard code the url into the ajax call. This is a viable option if you don't anticipate the url to change and/or if your standards allow it.
I am learning ASP.net MVC - 5 and I am stuck at one problem. So I need to open a URL after successful Ajax Post Request. But I also want to pass one value to the new URL's Controller Action. Below is what I have till now.
AJAX CALL
$.ajax({
url: URL,
type: 'POST',
data: data,
success: function (result) {
if (result == true) {
int TEMPVAR = 2;
DisplayError('Save Successful', 'Success', function () {
window.location.href = '/Settings/Customize/'; });
},
error: function (error) {
}
});
Controller Action
[AuthorizeSettings]
public ActionResult Customize()
{
//I want to be able to access TEMPVAR value here
// code removed for brevity
return View(configData);
}
Question: How to pass the TEMPVAR data to the Customize Action
Points:
I know there are some ways to pass data. TempData,Viewbag,SessionVariable, Embedding the TEMP value in URL Request, Anonymous Objects, ViewData, Static variable for the class, Global Variable, JSON. But I am totally confused how to pass data. I am newbiew please guide me here.
EDIT:
AJAX CALL
$.ajax({
url: URL,
type: 'POST',
data: data,
success: function (result) {
if (result == true) {
int TEMPVAR = 2;
DisplayError('Save Successful', 'Success', function () {
window.location.href = '/Settings/Customize/'; });
TEMPDATA["value"] = TEMPVAR;
},
error: function (error) {
}
});
Based on comments, you want to send data from SaveStyles to Customize. If so, you can use TempData -
public class PersistController : Controller
{
[HttpPost]
public ActionResult SaveStyles()
{
TempData["Status"] = true;
TempData["Val"] = 4;
return Json(true);
}
}
public class SettingsController : Controller
{
public ActionResult Customize()
{
bool status = Convert.ToBoolean(TempData["Status"]);
int val = Convert.ToInt32(TempData["Val"]);
return View();
}
}
I'm trying out AngularJS in combination with NET Core. Currently trying to parse a "string username", "string password" and "bool rememberMe", but both strings are null no matter what I do. I've even tried parsing a constant value as seen below, the parameter "test", but even that doesn't work. I've confirmed in Fiddler that the script is in fact parsing the value, so the controller basically just can't "fetch it".
Below is my AngularJS loginController code.
var login = angular.module('login', []);
login.controller('LoginController',
[
'$scope', '$http', '$window', function ($scope, $http, $window) {
$scope.submit = function () {
var data = { test: ':D' };
$http({
method: 'POST',
url: '/admin',
data: data
}).then(function success(response) {
alert(response.data.test);
});
}
}
]);
Below is the code for my ActionResult meant to fetch the value being posted to it.
[HttpPost]
public IActionResult Index(string test)
{
return Json(new
{
test,
bla = "BLA"
});
//if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
//{
// if (UserSystem.Login(username, password, rememberMe, HttpContext))
// {
// HttpContext.Response.StatusCode = (int)HttpStatusCode.Accepted;
// return Json(new
// {
// returnUrl = "/admin/dashboard"
// });
// }
//}
//HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
//return Json(new
//{
// error = "Username and/or password do not match"
//});
}
I've also tried specifying the Content-Type, but also without luck. Either way, in Fiddler the request always seems to per default be application/json.
I hope someone can help me. Thanks!
The solution was to request an object in the controller, rather than "string username", "string password" and "bool rememberMe".
The controller now looks like this:
public class LoginModel
{
public string Username { get; set; }
public string Password { get; set; }
public bool RememberMe { get; set; }
}
[HttpPost]
public IActionResult Index([FromBody]LoginModel model)
{
if (!string.IsNullOrEmpty(model.Username) && !string.IsNullOrEmpty(model.Password))
{
if (UserSystem.Login(model.Username, model.Password, model.RememberMe, HttpContext))
{
HttpContext.Response.StatusCode = (int)HttpStatusCode.Accepted;
return Json(new
{
returnUrl = "/admin/dashboard"
});
}
}
HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return Json(new
{
error = "Username and/or password do not match"
});
}
And the AngularJS controller now looks like this:
var login = angular.module('login', []);
login.controller('LoginController',
[
'$scope', '$http', '$window', function ($scope, $http, $window) {
$scope.submit = function () {
var data = {
username: $scope.username,
password: $scope.password,
rememberMe: $scope.rememberMe
};
$http({
method: 'POST',
url: '/admin',
data: data
}).then(function success(response) {
$window.location.href = response.data.returnUrl;
}, function fail(response) {
swal('Error!', response.data.error, 'error');
});
}
}
]);
I've looked at various questions and answers, however I am only partially successful.
The View is passing this JSON:
{JsonInput: [["208-01", "003158"]], JobNumber: "test"}
$.ajax({
type: "POST",
url: "/Dash/SavePickups",
contentType: 'application/json',
dataType: "json",
data: JSON.stringify({
JsonInput: final,
JobNumber:"test"
}),
The Json String above is sent to the controller at /Dash/SavePickups
[System.Web.Http.Route("Dash/SavePickups/{JsonInput}")]
public JsonResult SavePickups(object[][] JsonInput)
{
var FailResult = new { Success = "False", Message = "Error" };
var SuccessResult = new { Success = "True", Message = "Pickups Scheduled Successfully." };
return Json(SuccessResult, JsonRequestBehavior.AllowGet);
}
Only part of the JSON string is passed to the JsonInput.
In Debug I see the JsonInput Object, with the Obj array 208-01 and 003158.
Why isn't JobNumber included, I can see in chrome Network POST its part of the JSON string sent to the controller..
Continuing maccettura's answer - Your issue is with deserializing the JSON into an object. Your given JSON is formatted as
{ JsonInput : ["1234","5667"], JobNo : "Test" }
Which has one possible data structure of
List<string> , String
which will not deserialize into a 'sqaure' object such as
object [][]
I'd recommend making a model for your json that looks like this:
public class SavePickupsModel
{
public List<string> JsonInput {get; set;}
public string JobNo {get; set; }
}
Then use that model as input into your method:
[HttpPost]
[System.Web.Http.Route("Dash/SavePickups/{JsonInput}")]
public JsonResult SavePickups(SavePickupsModel JsonInput)
{
var FailResult = new { Success = "False", Message = "Error" };
var SuccessResult = new { Success = "True", Message = "Pickups Scheduled Successfully." };
return Json(SuccessResult, JsonRequestBehavior.AllowGet);
}
I would start by tagging your controller with the [HttpPost] attribute
[HttpPost]
[System.Web.Http.Route("Dash/SavePickups/{JsonInput}")]
public JsonResult SavePickups(object[][] JsonInput)
{
}
I would also point out that your parameter for the action (object[][] JsonInput) does not look right to me. You will likely find that the json does not deserialize to that object type.