DateTime.Kind is set to indefinite, not UTC, after loading from the database

When I create a Buyin object, the response from the ASP.NET MVC controller ( return Json(response, JsonRequestBehavior.AllowGet); ) looks like this:

 "Buyin": { "Id": 95, "PlayerSessionId": 88, "PlayerId": 45, "PlayerName": "Alan", "Amount": 888, "BuyinType": "Credits", "Description": null, "Authorized": true, "SignPath": "~/Signs/Buyins\\95.png", "Payment": null, "CreationDate": "/Date(1477242738042)/" }, 

If I convert it to Epoch Converter , I get this time: GMT: Sun, 23 Oct 2016 17:12:18.042 GMT

In the database, the stored datetime seems to be correct:

 95 NULL 1 1 2016-10-23 17:12:18.043 

When the response is sent, Kind set to UTC .

Now I call the controller to get all my data, and all the dates added a few hours to it:

  { "Id": 95, "PlayerSessionId": 88, "PlayerId": 45, "PlayerName": "Alan", "Amount": 888, "BuyinType": "Credits", "Description": null, "Authorized": true, "SignPath": "~/Signs/Buyins\\95.png", "Payment": null, "CreationDate": "/Date(1477267938043)/" } 

1477267938043 = GMT: Mon, 24 Oct 2016 00:12:18.043 GMT

However, when I request this object, I see that the actual object has the correct date: enter image description here

But the Kind parameter is set to Unspecified , so I think this is causing the problem.

At the moment, I have not set any globalization settings.

So basically, my question is: when ASP.NET MVC loads dates from the database, is there any way to tell the server to load dates with Kind set to UTC , since I think this is the problem?

The database is saved and loaded using the Entity Framework.

Update after accepted answer

The accepted answer was wonderful, however my date values ​​were already stored in the database as UTC dates, so I changed GetDateTime to this: public override DateTime GetDateTime (int serial number)

 { var date = base.GetDateTime(ordinal); var utcDate = DateTime.SpecifyKind(date, DateTimeKind.Utc); return utcDate; //return base.GetDateTime(ordinal).ToUniversalTime(); } 
+2
sql-server-2012 entity-framework
Oct 23 '16 at 17:38
source share
1 answer

Assuming you are using EF6 and you want to set the Kind property of any DateTime value retrieved from the database to Utc .

Similar questions were asked, and the answers usually involve connecting to the ObjectContext.ObjectMaterialized event, but it did not work for queries that use projection.

The solution that I am going to offer for work both for entities and for projection queries by performing a conversion at the DbDataReader level (which is used by this type of query).

To do this, we need a special implementation of DbDataReader that intercepts the GetDateTime method. Unfortunately, the DbDataReader derived class requires a lot of template code. Fortunately, I already created the base class from my answer to Dynamic Translation, to avoid C # syntax errors that simply delegates each method to the base instance of DbDataReader , so I just take it from there:

 abstract class DelegatingDbDataReader : DbDataReader { readonly DbDataReader source; public DelegatingDbDataReader(DbDataReader source) { this.source = source; } public override object this[string name] { get { return source[name]; } } public override object this[int ordinal] { get { return source[ordinal]; } } public override int Depth { get { return source.Depth; } } public override int FieldCount { get { return source.FieldCount; } } public override bool HasRows { get { return source.HasRows; } } public override bool IsClosed { get { return source.IsClosed; } } public override int RecordsAffected { get { return source.RecordsAffected; } } public override bool GetBoolean(int ordinal) { return source.GetBoolean(ordinal); } public override byte GetByte(int ordinal) { return source.GetByte(ordinal); } public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) { return source.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length); } public override char GetChar(int ordinal) { return source.GetChar(ordinal); } public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) { return source.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); } public override string GetDataTypeName(int ordinal) { return source.GetDataTypeName(ordinal); } public override DateTime GetDateTime(int ordinal) { return source.GetDateTime(ordinal); } public override decimal GetDecimal(int ordinal) { return source.GetDecimal(ordinal); } public override double GetDouble(int ordinal) { return source.GetDouble(ordinal); } public override IEnumerator GetEnumerator() { return source.GetEnumerator(); } public override Type GetFieldType(int ordinal) { return source.GetFieldType(ordinal); } public override float GetFloat(int ordinal) { return source.GetFloat(ordinal); } public override Guid GetGuid(int ordinal) { return source.GetGuid(ordinal); } public override short GetInt16(int ordinal) { return source.GetInt16(ordinal); } public override int GetInt32(int ordinal) { return source.GetInt32(ordinal); } public override long GetInt64(int ordinal) { return source.GetInt64(ordinal); } public override string GetName(int ordinal) { return source.GetName(ordinal); } public override int GetOrdinal(string name) { return source.GetOrdinal(name); } public override string GetString(int ordinal) { return source.GetString(ordinal); } public override object GetValue(int ordinal) { return source.GetValue(ordinal); } public override int GetValues(object[] values) { return source.GetValues(values); } public override bool IsDBNull(int ordinal) { return source.IsDBNull(ordinal); } public override bool NextResult() { return source.NextResult(); } public override bool Read() { return source.Read(); } public override void Close() { source.Close(); } public override T GetFieldValue<T>(int ordinal) { return source.GetFieldValue<T>(ordinal); } public override Task<T> GetFieldValueAsync<T>(int ordinal, CancellationToken cancellationToken) { return source.GetFieldValueAsync<T>(ordinal, cancellationToken); } public override Type GetProviderSpecificFieldType(int ordinal) { return source.GetProviderSpecificFieldType(ordinal); } public override object GetProviderSpecificValue(int ordinal) { return source.GetProviderSpecificValue(ordinal); } public override int GetProviderSpecificValues(object[] values) { return source.GetProviderSpecificValues(values); } public override DataTable GetSchemaTable() { return source.GetSchemaTable(); } public override Stream GetStream(int ordinal) { return source.GetStream(ordinal); } public override TextReader GetTextReader(int ordinal) { return source.GetTextReader(ordinal); } public override Task<bool> IsDBNullAsync(int ordinal, CancellationToken cancellationToken) { return source.IsDBNullAsync(ordinal, cancellationToken); } public override Task<bool> ReadAsync(CancellationToken cancellationToken) { return source.ReadAsync(cancellationToken); } public override int VisibleFieldCount { get { return source.VisibleFieldCount; } } } 

and build the class we need:

 class UtcDateTimeConvertingDbDataReader : DelegatingDbDataReader { public UtcDateTimeConvertingDbDataReader(DbDataReader source) : base(source) { } public override DateTime GetDateTime(int ordinal) { return DateTime.SpecifyKind(base.GetDateTime(ordinal), DateTimeKind.Utc); } } 

Once we get this, we need to connect it to the EF infrastructure using EF interception .

We start by creating a custom DbCommandInterceptor derived class:

 class UtcDateTimeConvertingDbCommandInterceptor : DbCommandInterceptor { public override void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { base.ReaderExecuted(command, interceptionContext); if (interceptionContext.Result != null && interceptionContext.Exception == null) interceptionContext.Result = new UtcDateTimeConvertingDbDataReader(interceptionContext.Result); } } 

register it (for example, from your static constructor of the derived DbContext class):

 public class YourDbContext : DbContext { static YourDbContext() { DbInterception.Add(new UtcDateTimeConvertingDbCommandInterceptor()); } // ... } 

and we are done.

Now, every DateTime value coming from the database will have the Kind property set to Utc .

+7
Oct 31 '16 at 19:18
source share



All Articles