PDA

View Full Version : [FIXED] Problem in 4.1.x with MS dates in JSON POST to .NET WCF web service



marc.fearby
21 Nov 2012, 6:24 PM
In 4.0.7 my JSON dates (when calling store.sync() on a grid with a column set to dateFormat: 'MS') would POST in this format:

"field_name":"\/Date(1338182969227)\/"

but since 4.1.x they're now sending like this:

"field_name":"\\/Date(1338182969227)\\/"

so my .NET WCF web service is giving me 400 Bad Request errors because it can't deserialise the dates. Any idea why it's trying to escape the backslash rather than just leaving the solitary backslash to escape the forward slash (I presume that's what's going on)?

Back in the 4.0.7 days I had to do the following to get the store to respect the dateFormat in the model when calling sync(), but whether I have this or not, the date format sent to the server is still the same in 4.1.x (so I guess this workaround is now redundant):

Ext.JSON.encodeDate = function (o) {
var MS = Ext.Date.format(o, 'MS');
return '"' + MS + '"';
};

mitchellsimoens
22 Nov 2012, 5:56 AM
We have a bug reported for Sencha Touch so I am opening one for Ext JS.

marc.fearby
22 Nov 2012, 3:25 PM
Thanks. So far none of our users have noticed the side-effect of this particular bug, so I'm OK for now. I look forward to its resolution, though :-)

xjpmauricio
22 Dec 2012, 4:49 PM
I have the same problem! any override available?


Thanks. So far none of our users have noticed the side-effect of this particular bug, so I'm OK for now. I look forward to its resolution, though :-)

mankz
22 Dec 2012, 8:29 PM
I reported this months ago, it's reported as fixed but it's not. http://www.sencha.com/forum/showthread.php?241314-4.1.1-ASP.NET-date-encoding&

Still open in 4.2 beta:


Ext.define('foo', {
extend : 'Ext.data.Model',
fields : [{
name : 'd', type : 'date', dateFormat: 'MS'
}],
proxy : {
api : { create : 'foo.js'}, type : 'ajax'
}
});
var f = new foo({ d : new Date() });

f.save();


Sends:



{"d":"\\/Date(1356236973618)\\/"}

xjpmauricio
23 Dec 2012, 7:08 AM
I found a solution for this problem; this is the original method on Ext.data.writer.Writer:


writeValue: function(data, field, record){
var name = field[this.nameProperty] || field.name,
dateFormat = this.dateFormat || field.dateWriteFormat || field.dateFormat,
value = record.get(field.name);

if (field.serialize) {
data[name] = field.serialize(value, record);
} else if (field.type === Ext.data.Types.DATE && dateFormat && Ext.isDate(value)) {
data[name] = Ext.Date.format(value, dateFormat);
} else {
data[name] = value;
}
}

...i created an override wich looks like this:


Ext.override(Ext.data.writer.Writer, {
writeValue: function(data, field, record){
var name = field[this.nameProperty] || field.name,
dateFormat = this.dateFormat || field.dateWriteFormat || field.dateFormat,
value = record.get(field.name);

if (field.serialize) {
data[name] = field.serialize(value, record);
} else {
data[name] = value;
}
}
});





I haven't add the time to look up into this but the problem is here:

data[name] = Ext.Date.format(value, dateFormat);


Please remember that this solution has not been tested and that this problem
might only be related to Microsoft web services or MVC related projects. I really don't know.
We might need a extjs guru here to shed some light on the subject.


For the meanwhile, I'm happy that I can move on with my project with this working solution...

Animal
11 Jan 2013, 8:01 PM
The problem is that string



'{"propName": "\/blah"}'


is not valid JSON and cannot be produced by a valid JSON producer.

MS web services consume invalid JSON which a standards compliant producer will not produce. It's quite clever really because it means that that sequence of characters can only ever be a date because no valid JSON object can look like that. Unfortunately, it means that you can never use the browser's native JSON object!

For example, using the browser's native JSON object will not produce that.

Type the following into the console command line on a modern browser:



obj = {prop: '\\/foo'};


That creates an object having a string property which looks the way you want: "\/foo"

But then when you serialize that object into a JSON string using the browser's correct implementation:



JSON.stringify(obj)


See what it produces.

The workaround is to specify a null serialize method on your date field:



{
type: 'date',
format: 'MS',
serialize: Ext.identityFn // An Ext-supplied fn which returns the arg unchanged
}


That allows the Ext.data.Writer to pass the date unformatted for serialization into JSON.

And use the following override to make Ext's JSON object do what you want:



Ext.JSON.encodeDate = function (o) {
return '"' + Ext.Date.format(o, 'MS') + '"';
};


This ticket will be closed.

mraming
6 Mar 2013, 5:58 AM
I don't agree with the analysis of the last post.
If you have ExtJS itself write a date in MS format and subsequently parse it, you'll notice that it fails as well.
If you use fiddler to see what WCF is sending over the wire for a date, you'll see that it's in the following format:

{"dateOfBirth":"\/Date(84578400000+0200)\/"}

That is perfectly legal JSON/JavaScript. It's simply escaping the forward slash which is valid (though deprecated - see also Mozilla's JavaScript guide (https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals#Escaping_characters)). However, if you look at what ExtJS (using version 4.1.3.548) sends back on a sync() call using fiddler, you'll see this

{"dateOfBirth":"\\/Date(132361200000)\\/"}

That's still 'legal' JSON/JavaScript, but it now means something different: It's a single, escaped backslash followed by a single forward slash. Not quite the same and WCF (rightly) barks when parsing this.
I believe the problem lies with the Ext.Date.formatFunctions.MS function and the following override resolves the issue:

Ext.Date.formatFunctions.MS = function () { return '/Date(' + this.getTime() + Ext.Date.getGMTOffset(this) + ')/'; };

If you now look at what ExtJS is sending using fiddler, you'll see this:

{"dateOfBirth":"/Date(132361200000+0100)/"}

This is still legal JSON/JavaScript, but also in the correct format. The forward slash is simply not escaped and indeed, WCF will parse/interpret this correctly. In fact, ExtJS itself will now also correctly parse a string with an MS format date that it formatted itself. Seems to me to be a sensible test case to include :-)
For reference, I've attached 2 files with the relevant sessions which I captured using Fiddler. The one that failed is using the original ExtJS 4.1.3 Ext.Date.formatFunctions.MS function. The file with the successful sessions uses the patched version.
Please correct me if I'm wrong. If not, please include the correct fix in the next patch/release of ExtJS :-)

For some background on the MS date format and it's rationale, see http://weblogs.asp.net/bleroy/archive/2008/01/18/dates-and-json.aspx
I explains how a little bit of ambiguity in the JSON spec is used to be able to differentiate between a string and a date literal. In essence, one has to ensure that what goes over the wire in case of a date is exactly \/Date... i.e. an escaped forward slash.