开发者

In an MVC 3 Application, how do I do a simple AJAX/JSON round trip of DateTimes and TimeSpans?

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 :-)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜