Given a simple round tripping scenario, how can I return JSON data to a browser and then accept updates from the browser via JSON that ModelBinds to a type w/ 3 properties: Int32, DateTime, TimeSpan?
Server Code (Controller)
public class Product
{
public int Id { get; set; }
public DateTime Start { get; set; }
public TimeSpan Duration { get; set; }
}
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult data()
{
return Json(
new Product {
Id = 1, Start = DateTime.Now,
Duration = TimeSpan.FromMinutes(30)}
开发者_JAVA技巧 , JsonRequestBehavior.AllowGet);
}
[HttpPost]
public void data(Product product)
{
//product is not bound; modelbinder fails on DateTime and TimeSpan
Console.WriteLine("Data: " + product);
}
Errors from Immediate Window
ModelState["Start"].Errors[0]
{System.Web.Mvc.ModelError}
ErrorMessage: "The value '/Date(1302295231115)/' is not valid for Start."
Exception: null
ModelState["Duration"].Errors[0]
{System.Web.Mvc.ModelError}
ErrorMessage: "The Duration field is required."
Exception: null
Client Code (getData and changeData are bound to 2 different buttons)
<script type='text/javascript'>
var myData;
function getData(event)
{
$.getJSON('/home/data', function (data)
{
myData=data;
console.dir(data);
});
}
function changeData(event)
{
var postData = JSON.stringify(myData);
$.ajax({
url: '/home/data',
type: "POST",
data: postData,
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function () {
console.log('success!');
},
error: function () {
console.log('fail!');
}
});
}
$(document).ready(function ()
{
$('#get').click(getData);
$('#post').click(changeData);
}
</script>
<body>
<button id="get" onclick="return(false);">get</button>
<button id="post" onclick="return(false);">post</button>
</body>
Update March 2012
Looks like the upcoming Microsoft WebAPI will serialize to ISO8601 thanks to Scott Hanselman and James Newton-King
There's an issue with the way dates are handled. The JavaScriptSerializer uses the following format when dealing with dates: /Date(1302296382818)/
which unfortunately makes little sense to jQuery when parsing the GET JSON response so you don't get a real date on the client side but string. So you need a shameless hack in order to convert this string to a real date:
myData.Start = new Date(parseInt(data.Start.substr(6)));
And here's the full story of the hack:
Model:
public class Product
{
public int Id { get; set; }
public DateTime Start { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Data()
{
var product = new Product
{
Id = 1,
Start = DateTime.Now,
};
return Json(product, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public ActionResult Data(Product product)
{
return Json(product);
}
}
View:
<script type="text/javascript">
var myData;
function getData(event) {
$.getJSON('/home/data', function (data) {
myData = data;
myData.Start = new Date(parseInt(data.Start.substr(6)));
});
return false;
}
function changeData(event)
{
var postData = JSON.stringify(myData);
$.ajax({
url: '/home/data',
type: 'POST',
data: postData,
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function (result) {
console.log(result);
}
});
return false;
}
$(function () {
$('#get').click(getData);
$('#post').click(changeData);
});
</script>
<button id="get">get</button>
<button id="post">post</button>
Leaving the TimeSpan
case as an exercise to the reader as it will require another shameless hack and I am tired of hacks :-)
精彩评论