Providing DateTime values in OData - c#

I'm currently writing a special client application to allow our unit tests to work with an OData interface using the XML structure for atom feeds.
All seems to be working properly, but i'm running into trouble when I need to pass a DateTime value as property.
I've written the following code that extracts the DateTime value from the property of the object and stores it in a specific format:
private static void GenerateProperty<T>(StringBuilder xml, T obj, PropertyInfo info)
{
// Extract the information about the property if it contains a value.
if (info.GetValue(obj, null) == null) return;
string type = info.GetGetMethod().ReturnType.ToString().Split('.').Last();
string value = info.GetValue(obj, null).ToString();
if (type == "DateTime")
value = ((DateTime)info.GetValue(obj, null)).ToString("yyyy-mm-ddThh:mm:ss");
if (type == "Boolean") value = value.ToLower();
// Append the property to the generated XML.
xml.Append(type.ToLower().Equals("string") ?
string.Format("<d:{0}>{1}</d:{0}>", info.Name, value) :
string.Format("<d:{0} m:type=\"Edm.{1}\">{2}</d:{0}>", info.Name, type, value));
}
The code is heavy on reflection, but that's beside the point. The values returned by this code for a DateTime are in the following format: 2011-49-13T11:49:41Z
However, i'm receiving the following error from my OData Service:
Error processing request
stream. Error encountered in converting the value from request payload
for property 'Created' to type 'System.DateTime', which is the
property's expected type. See inner exception for more
detail.
The string '2011-49-13T11:49:41Z' is not a valid AllXsd
value.
System.FormatException
at System.Xml.XmlConvert.ToDateTime(String s,
XmlDateTimeSerializationMode dateTimeOption)
 at
System.Data.Services.Parsing.WebConvert.StringToPrimitive(String text,
Type targetType)
 at
System.Data.Services.Serializers.PlainXmlDeserializer.ConvertValuesForXml(Object
value, String propertyName, Type typeToBeConverted)
So apparently it doesn't understand the DateTime format, but when I look at the documentation that's posted here: http://www.odata.org/developers/protocols/overview#AbstractTypeSystem
I'd expect it to be valid. Anyone have any experience with this?

yyyy-mm-ddThh:mm:ss
should be
yyyy-MM-ddTHH:mm:ssZ

ToString("O") will solve the problem too.

Related

Unable to save Date to salesforce?

To my surprise , its not st.forward thing to do; saving Date to Salesforce .
I'm trying to update one field which is of type Date but it throws me some weird error .
Code :
var objSer = new JavaScriptSerializer();
string json = objSer .Serialize(new{
startdate = sfdcValue
});
MyUpdateMethod("objectName/" + id, json);
I tried to convert date to IS0 8601 standard (as suggested over SO)
1.) DateTime.UtcNow.ToString("s",System.Globalization.CultureInfo.InvariantCulture)
2.) DateTime.UtcNow.ToString("o")
Error Info :
{"message":"Cannot deserialize instance of double from VALUE_STRING
value 2017-05-26T10:31:40.5790708Z or request may be missing a
required field at [line:1, column:2]","errorCode":"JSON_PARSER_ERROR"}
You didn't elaborate on which method you are using to communicate between the server and client. I am using Javascript Remoting (#RemoteAction on the apex method) and I ran into this issue. For me, the date and datetime fields were being expected by Salesforce as date serials (your mileage may vary if using a different access method).
Given I was dealing with a dynamic list of fields, I ended up with a pair of marshall / unmarshall functions on the client that created client-only slave fields I removed before sending the data back to Salesforce (NB: the example below is javascript not c#). In your case, a marshall / unmarshall may take a different approach:
// Provide an client-only date field based on a date serial (SFDC input)
function createDateDerivedField(currentRecord, fieldName) {
Object.defineProperty(currentRecord, fieldName + '__ui', {
enumerable: true,
get: function () {
return currentRecord[fieldName] == null ? null : new Date(currentRecord[fieldName]);
},
set: function(newValue) {
// Update the original field
currentRecord[fieldName] = newValue == null ? null : (new Date(newValue)).getTime(); // Convert back to date serial
}
});
}

C# - Converting from string to my object

In my code I load a text file and read it, looking for specific parameters. After I get them, I save them as string, and now I need to send them to a set-method, that only gets MyProperties type variables. ("MyProperties" is an enum class, and the method that receives the parameter needs to get an enum of this type)
So my question is: how can I convert them from string to MyProperties type?
Reading the file:
string input = File.ReadAllText("C:/avi/properties/" + propertiesFile);
After I get a parameter I need, I save it in a string var named mode.
string mode; // ---> Needs to be "MyProperties mode;"
vpa.Set(MyProperties.Mode, mode);
Solutions like checking if (mode.equals("string")) or "switch" are too long because there is a lot to check.
Been able to find an answer on another post, this is what i used:
TypeConverter converter = TypeDescriptor.GetConverter(type);
MyProperties prop = (MyProperties)converter.ConvertFrom(mode);

Passing date as string - prevent json.net from parsing date

I have a Web API middle layer which consumes an API which exposes a field which carries a timestamp as string (the field is string and it contains a value like "2016-05-31T14:12:45.753Z").
The proxy classes in the middle tier are generated using Visual Studio from Swagger endpoint and under the hood the object is deserialized using Json.NET.
I can see that the field was received as string (that's good):
inputObject {{ "When": "2016-05-31T14:12:45.753Z" }} Newtonsoft.Json.Linq.JToken {Newtonsoft.Json.Linq.JObject}
However, even though the target field is string the value of inputObject["When"] is a parsed as a timestamp.
inputObject["When"] {31/05/2016 14:12:45} Newtonsoft.Json.Linq.JToken {Newtonsoft.Json.Linq.JValue}
Then
JToken whenValue = inputObject["When"];
if (whenValue != null && whenValue.Type != JTokenType.Null)
{
this.When = ((string)whenValue);
}
In the end this.When is a string with value 31/05/2016 14:12:45.
Is there an option to prevent json.net from parsing the date and then casting it to string again?
Please remember that this transformation happens in auto generated code so I'm looking for some way of decorating the field on the server side which would make Swagger mark it somehow and then the generated classes would avoid the deserialize/serialize issue.
Something like:
[JsonProperty("This really is a string, leave it alone")]
public string When { get; private set; }
(Answering my own question)
I needed a solution quickly and this is my temporary solution, for the record.
I format the date as
"When": "2016-05-31 14:12:45"
and not
"When": "2016-05-31T14:12:45.753Z"
This prevents it from being interpreted. The front end (javascript) code knows that timestamps from the API are UTC and it appends 'Z' before transforming the timestamp to local time and formatting for display, e.g:
<td>{{vm.prettyDateTimeFormat(item.StatusDate+'Z')}}</td>
The ctrl code:
vm.prettyDateTimeFormat = function (dateString)
{
var momentDate = moment(dateString, "YYYY-MM-DD HH:mm:ssZZ");
if (typeof(momentDate) === "undefined" || (!momentDate.isValid()))
{
return dateString;
}
//The format needs to be sortable as it ends up in the grid.
var nicePrettyDate = momentDate.format('YYYY-MM-DD HH:mm:ss');
return nicePrettyDate;
}
As far as I don't like this solution it carried us through the demo. This issue is obviously in the back log now to be addressed properly.
[JsonIgnore]
public string When { get; private set; }

TypeDescriptor does not recongnise date

I'm having an ussue with the TypeDescriptor class.
I have a cookie which contains a date - the date is converted to a string and then back again using some helper methods.
One of my staple extension methods is used to do the conversion, however it throws a forced error because the date is not convertible back from a string.
Here's the message I output:
22/01/2015 14:29:15 could not be converted to DateTime
Looks like a DateTime to me!
The problem can be overcome by using Convert.ToDateTime(), so the code in general is ok. i also use it for dates elwhere with no problems to date.
The only difference is that I'm converting in the middle of a linq statement like this:
Set = new SortedSet<TrackedItem>(set
.Split(';')
.Select(s =>
{
var parts = s.Split(',');
return new TrackedItem(
parts[0].ConvertTo<int>(),
Convert.ToDateTime(parts[1]));
}));
Any ideas?
public static T ConvertTo<T>(this object obj, bool throwInvalid = false)
where T : IConvertible
{
// Object does not require converting.
if (obj is T) return (T)obj;
// Determine if object can be converted.
var type = typeof(T);
var converter = TypeDescriptor.GetConverter(type);
var isConvertible = converter != null && converter.IsValid(obj);
var error = string.Format("'{0}' could not be converted to type {1}", obj, type.Name);
// If no conversion is available, and defaults not allowed throw an error.
(!isConvertible && throwInvalid).ThrowTrue(error);
// If the object is convertible, convert it, else return the default(T).
return isConvertible ? (T)converter.ConvertFrom(obj) : default(T);
}
I'm guessing from your date example that you're running in the en-GB culture. Unfortunately, to draw liberally from this related q/a, IsValid always uses CultureInfo.InvariantCulture (US date format) to decide its answer. So when running in en-GB with a date such as your example, IsValid will return false; but ConvertFrom, which by default uses the current thread culture will succeed!
Interestingly, the latest docs for IsValid massively hedge the question of whether this is actually a bug:
The IsValid method is used to validate a value within the type
rather than to determine if value can be converted to the given type.
For example, IsValid can be used to determine if a given value is
valid for an enumeration type.
So really you shouldn't be using IsValid here at all - you should be doing what the same docs go on to suggest:
You can write your own WillConvertSucceed method by wrapping the
ConvertTo and ConvertFrom methods in exception blocks.
And in that method you can be sure to use the CultureInfo you actually care about.

Coding practice to convert string variables to actual types

I have a service that validates the user input. So, in other layers I am just using the below statement to get the amount value assuming that it is already validated.
But while writing unit test cases, I realized this is failing. So, my question is do we need to ALWAYS try to parse the values whenever string values needs to be converted to actual types.
var amountValue = Convert.ToDecimal(string.Format("{0}.{1}", view.amount, view.fraction))
You should parse strings because that's what you actually want to do.
A type conversion is something different than parsing.
Imagine a case where in the US you separate decimals with a dot . and in EU you'd use a comma ,. You can't really know how the locale separates decimals and whatnot (especially dates are crucial and should be PARSED no CONVERTED).
That said, the rule user input => parse is quite straight forward.
Here is a convert method based on generics:
public static void Convert<T>(string text, out T value, CultureInfo culture) where T : IConvertible
{
if (typeof(T).IsEnum)
{
value = (T) Enum.Parse(typeof (T), text, true);
}
else
{
value = (T)System.Convert.ChangeType(text, typeof(T), culture);
}
}

Categories