I feel completely stupid facing this issue.
I have simple C# code in MVC application where I need to evaluate string as valid int and another string as valid DateTime. Everything works fine when calling application from Chrome, Opera, Firefox. But when calling applicatin from IE or Edge (on multiple PCs) the evaluation fails.
My code:
if(!int.TryParse(s, out i))
{
// something
}
I've tried using CultureInfo and NumberFormatInfo with no efect.
The string value is niether null nor empty and contains int value in text format.
The same behavior is with evaluating string as DateTime.
Really don't know where is the problem...
Thanks for help.
Whole code:
1.Controller
[HttpGet]
[Route("RatingDetail/{ratingID:int}/{time}/{value:int}")]
public JsonResult RatingDetail(int ratingID, string time, int value)
{
try
{
using (var context = new SenzorikaEntities())
{
var rd = new RatingDB();
// URL must not contain ':', so we are sending time
// in format 0_00_00 instead of 0:00:00.
// So we have to replace back...
time = time.Replace('_', ':');
// This line fails when browsing in IE
// and yes sould by .TryParse, I know
var timeDB = DateTime.Parse(System.DateTime.Now.ToShortDateString() + " " + time);
var detialID = rd.InsertRatingDetail(context, ratingID, timeDB, value);
return Json(detialID, JsonRequestBehavior.AllowGet);
}
}
catch (Exception ex)
{
ErrorLog.LogError(ex, "Error when saving values.");
throw;
}
}
Javascript
function saveRating(percent, time) {
// model ID
var rid = $("#RatingID").val();
var timeConvert = time.replace(':', '_').replace(':', '_');
}
$.ajax(
{
statusCode: {
500: showError('some error text'),
200: showError('')
},
url: '/RatingDetail/' + rid + '/' + timeConvert + '/' + percent,
async: true,
type: 'GET',
dataType: 'json',
success:
function (response) {
if (response == undefined || response == "0")
showError('some error text');
},
error:
function (response) {
showError(");
}
});
One more interesting point. I tracked the page by Fiddler. The GET request (called by AJAX) in Google appears normal:/RatingDetail/69/0_00_01/4
But in Edge: /RatingDetail/70/%E2%80%8E0%E2%80%8E_%E2%80%8E00%E2%80%8E_%E2%80%8E05/9
The URL is decoded back in controller automaticaly, but may be somehow numbers are no longer numbers...
I found the culprite...
I made an array form the string I needed to evaluate as int and I saw that response from IE or Edge had more chars then response from Chrome/Opera/Firefox.
Response from IE had added quotation marks chars.
You can see at pictures.
The input string was 0:00:10 for IE and 0:00:12 for Chrome.
Response from Chrome - everything OK:
Response from IE/Edge - added quotation marks chars
As you see, I can't make timespan (or datetime) format from string that contains extra quotation marks. But this was not visible when debugging until I made a char array...
So I had to make workaround and clear the extra quotation mark chars.
public static string IEHackforTime(string time)
{
string newTime = "";
var arr = time.ToCharArray();
foreach( var c in arr)
{
if (Char.IsNumber(c) || c==':' )
{
newTime += c.ToString(); // No need of StringBuilder, array is small enough
}
}
return newTime;
}
I have a form that is generated via jquery:
$.get("/api/get/getListItems", function (data) {
var table = "";
table += "<table>";
$.each(data, function (y, z) {
console.log(z);
table += '<tr>';
$.each(this, function (k, v) {
table += '<td><input type="text" name="' + k + '" id="' + k + '" value="' + v + '" /></td>';
});
table += '<td><input type="checkbox" name="selected" id="selected" /></td>';
table += '</tr>';
});
table += '<tr><td><input type="submit" id="submit" name="submit" value="Save To Database" /></td></tr>';
table += '</table>';
$('#form').html(table);
});
and it generates this HTML (10 rows of input fields, 7 columns and 1 checkbox): http://jsfiddle.net/8zpr2fkL/1/
and I am submitting the form when the submit button is clicked:
$("#form").submit(function (event) {
$.post("/api/update/", $("#form").serialize(), alert('success'));
});
Now I am passing the data to my ASP.NET API Controller:
[HttpPost]
public dynamic Post([FromBody]CellModel cells)
{
UpdateClass jobs = new UpdateClass();
return jobs;
}
and here is my CellModel class:
public class CellModel
{
public uint scheduleTaskID { get; set; }
public string task { get; set; }
public string baselineDate { get; set; }
public string scheduledDate { get; set; }
public string actualDate { get; set; }
public string finishedDate { get; set; }
public bool selected { get; set; }
public override string ToString()
{
return scheduleTaskID.ToString();
}
}
My Problem is when I hit submit to submit the data and put a breakpoint on the controller method, cells count is 0, is there something I am missing here? I am trying to pass all the data in the input text to controller. Nothing is getting passed to my controller. What am I doing wrong?
This is data im trying to pass via jquery $('#form').serialize():
scheduleTaskID=194&task=Permit&baselineDate=6%2F23%2F2005+8%3A00%3A00+AM&scheduledDate=6%2F23%2F2005+8%3A00%3A00+AM&actualDate=6%2F23%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=195&task=Office+Files&baselineDate=7%2F13%2F2005+8%3A00%3A00+AM&scheduledDate=7%2F13%2F2005+8%3A00%3A00+AM&actualDate=7%2F13%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=196&task=Foundation&baselineDate=7%2F27%2F2005+8%3A00%3A00+AM&scheduledDate=7%2F27%2F2005+8%3A00%3A00+AM&actualDate=8%2F13%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=197&task=Framing&baselineDate=8%2F5%2F2005+8%3A00%3A00+AM&scheduledDate=8%2F5%2F2005+8%3A00%3A00+AM&actualDate=8%2F23%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=198&task=Finishes+Exterior&baselineDate=8%2F26%2F2005+8%3A00%3A00+AM&scheduledDate=8%2F26%2F2005+8%3A00%3A00+AM&actualDate=9%2F14%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=199&task=Drywall&baselineDate=9%2F2%2F2005+8%3A00%3A00+AM&scheduledDate=9%2F2%2F2005+8%3A00%3A00+AM&actualDate=9%2F16%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=200&task=Flooring&baselineDate=9%2F1%2F2005+8%3A00%3A00+AM&scheduledDate=9%2F1%2F2005+8%3A00%3A00+AM&actualDate=9%2F20%2F2005+8%3A00%3A00+AM&finishedDate=&scheduleTaskID=201&task=General+Finish&baselineDate=9%2F12%2F2005+8%3A00%3A00+AM&scheduledDate=9%2F12%2F2005+8%3A00%3A00+AM&actualDate=&finishedDate=&scheduleTaskID=202&task=Final+PDI&baselineDate=10%2F11%2F2005+8%3A00%3A00+AM&scheduledDate=10%2F11%2F2005+8%3A00%3A00+AM&actualDate=&finishedDate=&scheduleTaskID=203&task=Permit&baselineDate=4%2F6%2F2005+8%3A00%3A00+AM&scheduledDate=4%2F6%2F2005+8%3A00%3A00+AM&actualDate=4%2F6%2F2005+8%3A00%3A00+AM&finishedDate=
UPDATE
I have changed:
$("#form").submit(function (event) {
$.post("/api/update/", $("#form").serialize(), alert('success'));
});
to
$("#form").submit(function (event) {
var array = [];
$('#form > table > tbody > tr').each(function (elem) {
var item = {};
item.scheduleTaskID = $(this).find("td > #scheduleTaskID").val();
item.task = $(this).find("td > #task").val();
item.baselineDate = $(this).find("td > #baselineDate").val();
item.scheduledDate = $(this).find("td > #scheduledDate").val();
item.actualDate = $(this).find("td > #actualDate").val();
item.finishedDate = $(this).find("td > #finishedDate").val();
item.selected = $(this).find("td > #selected").val();
array.push(item);
});
console.log(JSON.stringify(array));
$.post("/api/update/", JSON.stringify(array), alert('success'), 'json');
});
in my console log my data looks like this:
[{"scheduleTaskID":"203","task":"Permit","baselineDate":"4/6/2005 8:00:00 AM","scheduledDate":"4/6/2005 8:00:00 AM","actualDate":"4/6/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"195","task":"Office Files","baselineDate":"7/13/2005 8:00:00 AM","scheduledDate":"7/13/2005 8:00:00 AM","actualDate":"7/13/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"196","task":"Foundation","baselineDate":"7/27/2005 8:00:00 AM","scheduledDate":"7/27/2005 8:00:00 AM","actualDate":"8/13/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"197","task":"Framing","baselineDate":"8/5/2005 8:00:00 AM","scheduledDate":"8/5/2005 8:00:00 AM","actualDate":"8/23/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"198","task":"Finishes Exterior","baselineDate":"8/26/2005 8:00:00 AM","scheduledDate":"8/26/2005 8:00:00 AM","actualDate":"9/14/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"199","task":"Drywall","baselineDate":"9/2/2005 8:00:00 AM","scheduledDate":"9/2/2005 8:00:00 AM","actualDate":"9/16/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"200","task":"Flooring","baselineDate":"9/1/2005 8:00:00 AM","scheduledDate":"9/1/2005 8:00:00 AM","actualDate":"9/20/2005 8:00:00 AM","finishedDate":"","selected":"on"},{"scheduleTaskID":"201","task":"General Finish","baselineDate":"9/12/2005 8:00:00 AM","scheduledDate":"9/12/2005 8:00:00 AM","actualDate":"","finishedDate":"","selected":"on"},{"scheduleTaskID":"202","task":"Final PDI","baselineDate":"10/11/2005 8:00:00 AM","scheduledDate":"10/11/2005 8:00:00 AM","actualDate":"","finishedDate":"","selected":"on"},{"scheduleTaskID":"203","task":"Permit","baselineDate":"4/6/2005 8:00:00 AM","scheduledDate":"4/6/2005 8:00:00 AM","actualDate":"4/6/2005 8:00:00 AM","finishedDate":"","selected":"on"},{}]
and in my ASP.NET API Controller, I changed my method to this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
public class UpdateController : ApiController
{
[HttpPost]
public dynamic Post(List<CellModel> cells)
{
UpdateClass jobs = new UpdateClass();
//jobs.PostScheduledTasks(cells);
return cells;
}
}
}
I put a breakpoint at the start of the method Post and when it hits the breakpoint, it says cells Count = 0..I see network call, only if i put a return false after my post call and the response is empty [] Why is the data not passing to my controller, is it because the form is being generated by jquery?
UPDATE
Still no solution, I looked at my network call this AM and the Status Code is 301:
Don't use $.post
use ajax post and set the content type to
"application/json; charset=utf-8"
var data = JSON.stringify(array);
$.ajax({
url:"/api/update/",
type:"POST",
data:data,
contentType:"application/json; charset=utf-8",
dataType:"json",
success: function(data){
console.log(data);
}
});
the problem is that you need to say to the webserver you are sending json and is not possible with $.post
This is really normal, and I have been struggling with this too (and sometimes I still forget), here you can see that you have to use $.ajax
Jquery - How to make $.post() use contentType=application/json?
While you got an alternative approach by #dariogriffo, i want to give you a full solution using your initial approach with $.post.
Your initial approach with form serialization was correct, so the following code is correct:
$("#form").submit(function (event) {
$.post("/api/update/", $("#form").serialize(), alert('success'));
});
However, this wasn't working because your dynamic form is not following the naming conventions for input fields expected by the ASP.NET MVC Default model binder, and as a consequence your serialized form was not something the default model binder was capable of binding to your cells model. That is why you were not getting any cells in the controller when doing a POST.
To clarify what that means, ASP.NET expects each input field that corresponds to a model property to have the following name format if you are posting to a regular MVC 5 Controller:
actionattributename[index].propertyname
If you are posting to a Web API 2 controller it should be:
[index].propertyname
Since your action attribute is named cells and it has a property scheduledTaskID, and you are posting to a WebAPI controller one of your inputs would look like:
<input type="text" name="[0].scheduleTaskID" id="scheduleTaskID" value="194">
There are a couple more rules involved in structuring a form to make it bindable. You can find a nice blog post about it here:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
If you followed that form convention you would be able to Post your serialized form to your controller expecting a List<CellModel> cells without having to use the JSON approach, which is much more expensive as suggested in the other answers.
Below is a fiddle with an example form structured correctly by Web API 2 default binder rules:
http://jsfiddle.net/8zpr2fkL/12/
You can try to $.post this form using $.post to your web api controller and it should work like a charm!
I know, this is already solved using .ajax instead of .post. I thought of sharing this , as i have solved this using .post. As mentioned above, since it posts with content type Content-Type:application/x-www-form-urlencoded; charset=UTF-8, parameter cells in post method will contain count = 0.
To solve this, you have to manually capture request object and get post data and then do deserialize and get object as List<CellModel>. I have used all posted code by OP, and just modified post method as shown in following, and it worked.
[HttpPost]
public dynamic Post(List<CellModel> cells)
{
string content = string.Empty;
if (HttpContext.Current.Request.InputStream.CanSeek)
{
HttpContext.Current.Request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
}
using (System.IO.StreamReader reader = new System.IO.StreamReader(HttpContext.Current.Request.InputStream))
{
content = reader.ReadToEnd();
}
if (!string.IsNullOrEmpty(content))
{
// Deserialize and operate over cells.
try
{
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject(content, typeof(List<CellModel>));
}
catch (Exception ex)
{
return ex;
}
}
return cells;
}
Here is what i get while debugging.
when passing an object which contains a date from C# to AngularJS
the value of the date appears as "/Date(1408482000000)/" and not as a valid date.
my angular code:
$scope.GetLastCompletedAction = function () {
$http.post('Default.aspx/GetLastCompletedAction', {}).success(function (data, status, headers, config) {
$scope.objects = JSON.parse(data.d);
}).error(function (data, status, headers, config) {
$scope.status = status;
console.log(status);
});
}
objects is a list of objects.
every object contains a field named startDate which appears invalid.
thanks,
Nadav
you can use a funcion like this
$scope.formatDate = function (jsonDate)
{
var milli = jsonDate.replace(/\/Date\((-?\d+)\)\//, '$1');
var date = new Date(parseInt(milli));
return date;
}
I had this problem before and it is the Date object in javascript that does not consider that date valid.
If you pass to the Date constructor only the number which is inside /Date(*)/, you will see it will work. It did for me.
Hope I helped :)
I have attempted to modify one of my api controller to allow for the creation of multiple reservations by allowing one of the parameters to be passed in as a pipe delimited string. The method and class can be seen here:
public class ReservationsController : ApiController
{
public HttpResponseMessage PostReservation(string eRaiderUserName, string SpaceNumbers)
{
char[] delimiter = { '|' };
string[] spaces = SpaceNumbers.Split(delimiter);
bool saved = true;
foreach(string space in spaces)
{
var reservation = new Reservation { eRaiderUserName=eRaiderUserName, SpaceNumber=Convert.ToInt32(space) };
if (true)
{
reservation.Game = db.Games.FirstOrDefault(g => g.ID == AppSettings.CurrentGameID);
db.Reservations.Add(reservation);
db.SaveChanges();
//HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, reservation);
//response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = reservation.ID }));
//return response;
}
else
{
saved = false;
//return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
db.SaveChanges();
if (saved)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = 1 }));
return response;
} else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
}
I have a form that posts what I think should be the right information, but I keep getting this error:
{"$id":"1","Message":"No HTTP resource was found that matches the request URI 'http://localhost:58463/api/Reservations'.","MessageDetail":"No action was found on the controller 'Reservations' that matches the request."}
The (modified) save method in the api is still definitely a work in progress. But what is keeping this from finding the web api controller? Here is the firebug output:
As pointed out, the problem is that a POST action can only transfer the data posted in the body to a single object (for technical reasons).
That means that you can get data from the route data, from the querystring, and from the body, with the following limitations:
data from querystring or route data must be single values (i.e. they cannnot be classes), in any number
you can have only one parameter of the action with data coming from the request body, but this can be a complex class
you can make any combination of this, i.e. a single or complex param coming from the body, and any number of single parameters coming from the route data or the querystring.
So, the most generic way to solve your problem (i.e. that can be easyly applied to other classes where you need to pass complex data, even more complex than this case) is this:
First, make a class which has properties for all the needed data,in your case:
public class ReservationData
{
public string eRaiderUserName { get; set; }
public string SpaceNumbers { get; set; }
}
Second, use this class as the type of the received parameter in your action:
public HttpResponseMessage PostReservation(ReservationData reservationData)
With this code the formatter can map all the data in the request body to a single parameter in the action. You can use JSON or formdata formats, like the generated by jQuery.
NOTE: the property names must case-sensitively match the name of the posted parameters.
This is because you send x-www-form-urlencoded data to controller, to handle this data you must use [FromBody] before parameter like
public HttpResponseMessage Post([FromBody] string name) { ... }
but this approach has a lot of limitation:
1) There can be only one parameter marked [FromBody] attribute (it can be complex type)
2) The data must be encoded as =value not as key=value .
You can read it here description and how make it work here example .
If it possible i recommend you to send Json data to controller, without this limitation.
Web API has limited support to map POST form variables to simple parameters of a Web API method. Web API does not deal with multiple posted content values, you can only post a single content value to a Web API Action method.
public HttpResponseMessage PostReservation(string eRaiderUserName, string SpaceNumbers)
{ //...}
and you are trying to call using jQuery:
$.ajax({ url: 'api/reservations', type: 'POST', data: { ... }, dataType: 'json', success: function (data) {alert(data);} });
Unfortunately, Web API can’t handle this request and you’ll get error. But if you pass parameters using query string, It’ll work:
$.ajax({ url: 'api/reservations?eRaiderUserName=2012&SpaceNumbers=test', type: 'POST', dataType: 'json', success: function (data) { alert(data); } });
But it’s not good solution and not applicable for complex objects. So here are the different ways to do it.
Using Model Binding (Preferred)
Using Custom Parameter Binding
FormDataCollection
Query String
Scenario:
I know this is a simple datetime conversion, but i'm new to backend and conversions. So please help: I use mvc with ajax to pass the date from kendocalender to scheduler to save it in database:
Here is my code:
controller.cs
public int insertnote(string model,DateTime kendodate)
{
tblDailyNotes Dnote = new tblDailyNotes();
int noteid = 0;
//note.RealDate=Convert.ToString(
Dnote.Note = model;
Dnote.RealDate = kendodate;
noteid = _scheduler.InsertDailynote(Dnote);
return noteid;
}
index.cshtml
$("#dailynotes").change(function () {
debugger;
alert("Changed");
var dailynotes = $('#dailynotes').val();
var calendar = $("#SchedulerCalendar2").data("kendoCalendar");
var cal = calendar.value(new Date());
alert(cal);
$.ajax({
![enter image description here][1]
type: "POST",
url: window.location.pathname + "Scheduler/insertnote",
data: {model:dailynotes, kendodate: cal }
})
.success(function (result) {
alert("note saved successfully");
});
});
Question:
this is the cal alert
How do I convert this output from kendocalendar to "2013-09-01 13:27:14.480"(yyyy-mm-dd hh-mm-ss.sss) this format using jquery to save it in database through controller function. Please help.
you can convert string to DateTime by DateTime.Parse
take a look at this
I agree with user2675751's solution. However, I would recomend using Datetime.TryParse() as this will not throw an exception and return a bool to indicate success or failure. This point is covered in the link user2675751 has provided. It is generally best not to trust data coming from the client.