Closed hpraheja closed 9 years ago
@hpraheja I've tried to reproduce this issue. When we only have DateTimeOffset defined in CLR types, both GET and POST should work fine.
It looks like the message is indicating a conversion to 'System.Nullable`1[System.DateTime]'. Then I tried to add a nullable DateTime type in CLR class. Nothing would happen as the model builder just ignores DateTime type, which is not supported in OData V4. Then if I manually add a DateTimeOffset type in model with the same name of the DateTime property. It would behavior as you described. The GET works fine, but POST would return following error.
{
"error":{
"code":"","message":"An error has occurred.","innererror":{
"message":"Object of type 'System.DateTimeOffset' cannot be converted to type 'System.Nullable`1[System.DateTime]'.","type":"System.ArgumentException","stacktrace":" at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast)\r\n at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)\r\n at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)\r\n at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\r\n at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\r\n at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)\r\n at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index)\r\n at Microsoft.Restier.EntityFramework.Submit.ChangeSetPreparer.SetValues(Object instance, Type type, IReadOnlyDictionary`2 values)\r\n at Microsoft.Restier.EntityFramework.Submit.ChangeSetPreparer.<PrepareAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Restier.Core.Submit.DefaultSubmitHandler.<SubmitAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Restier.Core.Domain.<SubmitAsync>d__19.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Restier.WebApi.ODataDomainController`1.<Post>d__e.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__3`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}
}
In this case, your database seems to have a DateTime type column, then it maps to the CLR DateTime type. To use CLR type in model, you can try the following approach: add a wrapper with DateTimeOffset type marked with NotMapped, then manually add it to model. (This should work for basic CRUD operations, but may not support query options.)
public DateTime? dtn { get; set; }
[NotMapped]
public DateTimeOffset? dtnWrapper
{
get
{
if (dtn.HasValue) return new DateTimeOffset(dtn.Value);
return null;
}
set
{
if (value.HasValue)
{
dtn = value.Value.UtcDateTime;
}
}
}
You can also refer following issue for DateTime support: https://github.com/OData/RESTier/issues/14, https://github.com/OData/RESTier/issues/74
Thanks for your response. I could not update this thread earlier. Datetimeoffset is working for us but we are still having issues with complex data type.
We are using datetimeoffset in our service for dates and GET is working fine. When we make a call for POST operation it throws below error:
"Object of type 'System.DateTimeOffset' cannot be converted to type 'System.Nullable`1[System.DateTime]'.","type":"System.ArgumentException","stacktrace":" at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast)