Browse Source

Introduce `AbpMongoDbDateTimeSerializer`.

`MongoDb` will normalize the datetime based on  `AbpClockOptions`.
pull/10149/head
maliming 4 years ago
parent
commit
6a3e4e3e5e
  1. 24
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  2. 2
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContext.cs
  3. 43
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbDateTimeSerializer.cs
  4. 60
      framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoModelBuilder.cs
  5. 18
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs
  6. 4
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs
  7. 17
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/UnitTestModelCacheKeyFactory.cs
  8. 9
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter_Tests.cs
  9. 66
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/EFCore_DateTimeKindTests.cs
  10. 7
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs
  11. 81
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Serializer/MongoDB_DateTimeKind_Tests.cs
  12. 30
      framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/PersonRepository.cs
  13. 73
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs
  14. 46
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DateTimeKind_Tests.cs

24
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs

@ -61,9 +61,9 @@ namespace Volo.Abp.EntityFrameworkCore
public IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
public IClock Clock => LazyServiceProvider.LazyGetRequiredService<IClock>();
public IDistributedEventBus DistributedEventBus => LazyServiceProvider.LazyGetRequiredService<IDistributedEventBus>();
public ILocalEventBus LocalEventBus => LazyServiceProvider.LazyGetRequiredService<ILocalEventBus>();
public ILogger<AbpDbContext<TDbContext>> Logger => LazyServiceProvider.LazyGetService<ILogger<AbpDbContext<TDbContext>>>(NullLogger<AbpDbContext<TDbContext>>.Instance);
@ -167,9 +167,9 @@ namespace Volo.Abp.EntityFrameworkCore
}
var result = await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
PublishEntityEvents(eventReport);
if (entityChangeList != null)
{
EntityHistoryHelper.UpdateChangeList(entityChangeList);
@ -285,11 +285,11 @@ namespace Volo.Abp.EntityFrameworkCore
}
}
}
private void PublishEventsForTrackedEntity(EntityEntry entry)
{
switch (entry.State)
{
{
case EntityState.Added:
EntityChangeEventHelper.PublishEntityCreatingEvent(entry.Entity);
EntityChangeEventHelper.PublishEntityCreatedEvent(entry.Entity);
@ -308,7 +308,7 @@ namespace Volo.Abp.EntityFrameworkCore
EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity);
}
}
break;
case EntityState.Deleted:
EntityChangeEventHelper.PublishEntityDeletingEvent(entry.Entity);
@ -324,11 +324,11 @@ namespace Volo.Abp.EntityFrameworkCore
ApplyAbpConcepts(entry);
}
}
protected virtual EntityEventReport CreateEventReport()
{
var eventReport = new EntityEventReport();
foreach (var entry in ChangeTracker.Entries().ToList())
{
var generatesDomainEventsEntity = entry.Entity as IGeneratesDomainEvents;
@ -369,7 +369,7 @@ namespace Volo.Abp.EntityFrameworkCore
return eventReport;
}
protected virtual void ApplyAbpConcepts(EntityEntry entry)
{
switch (entry.State)
@ -638,7 +638,7 @@ namespace Volo.Abp.EntityFrameworkCore
!typeof(TEntity).IsDefined(typeof(OwnedAttribute), true) &&
!mutableEntityType.IsOwned())
{
if (LazyServiceProvider == null || Clock == null || !Clock.SupportsMultipleTimezone)
if (LazyServiceProvider == null || Clock == null)
{
return;
}
@ -650,7 +650,7 @@ namespace Volo.Abp.EntityFrameworkCore
(property.PropertyType == typeof(DateTime) ||
property.PropertyType == typeof(DateTime?)) &&
property.CanWrite &&
!property.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true)
ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableDateTimeNormalizationAttribute>(property) == null
).ToList();
dateTimePropertyInfos.ForEach(property =>

2
framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbContext.cs

@ -6,6 +6,8 @@ namespace Volo.Abp.MongoDB
{
public abstract class AbpMongoDbContext : IAbpMongoDbContext, ITransientDependency
{
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
public IMongoModelSource ModelSource { get; set; }
public IMongoClient Client { get; private set; }

43
framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/AbpMongoDbDateTimeSerializer.cs

@ -0,0 +1,43 @@
using System;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
namespace Volo.Abp.MongoDB
{
public class AbpMongoDbDateTimeSerializer : DateTimeSerializer
{
protected DateTimeKind DateTimeKind { get; set; }
protected bool DisableDateTimeNormalization{ get; set; }
public AbpMongoDbDateTimeSerializer(DateTimeKind dateTimeKind , bool disableDateTimeNormalization)
{
DateTimeKind = dateTimeKind;
DisableDateTimeNormalization = disableDateTimeNormalization;
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, DateTime value)
{
context.Writer.WriteDateTime(DisableDateTimeNormalization
? ToMillisecondsSinceEpoch(value)
: ToMillisecondsSinceEpoch(DateTime.SpecifyKind(value, DateTimeKind)));
}
public override DateTime Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var dateTime = new BsonDateTime(context.Reader.ReadDateTime()).ToUniversalTime();
return DateTime.SpecifyKind(dateTime, DisableDateTimeNormalization ? DateTimeKind.Unspecified : DateTimeKind);
}
private static long ToMillisecondsSinceEpoch(DateTime dateTime)
{
return (dateTime - BsonConstants.UnixEpoch).Ticks / 10000L;
}
// For unit testing.
internal void SetDateTimeKind(DateTimeKind dateTimeKind)
{
DateTimeKind = dateTimeKind;
}
}
}

60
framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoModelBuilder.cs

@ -3,9 +3,13 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Reflection;
using Volo.Abp.Timing;
namespace Volo.Abp.MongoDB
{
@ -20,10 +24,12 @@ namespace Volo.Abp.MongoDB
_entityModelBuilders = new Dictionary<Type, object>();
}
public MongoDbContextModel Build(AbpMongoDbContext dbContext)
public virtual MongoDbContextModel Build(AbpMongoDbContext dbContext)
{
lock (SyncObj)
{
var clockOptions = dbContext.LazyServiceProvider?.LazyGetService<IOptions<AbpClockOptions>>();
var entityModels = _entityModelBuilders
.Select(x => x.Value)
.Cast<IMongoEntityModel>()
@ -34,6 +40,33 @@ namespace Volo.Abp.MongoDB
foreach (var entityModel in entityModels.Values)
{
var map = entityModel.As<IHasBsonClassMap>().GetMap();
if (clockOptions != null)
{
var dateTimePropertyInfos = entityModel.EntityType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.Where(property =>
(property.PropertyType == typeof(DateTime) ||
property.PropertyType == typeof(DateTime?)) &&
property.CanWrite
).ToList();
dateTimePropertyInfos.ForEach(property =>
{
var disableDateTimeNormalization =
entityModel.EntityType.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true) ||
ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableDateTimeNormalizationAttribute>(property) != null;
if (property.PropertyType == typeof(DateTime?))
{
map.MapProperty(property.Name).SetSerializer(new NullableSerializer<DateTime>().WithSerializer(new AbpMongoDbDateTimeSerializer(clockOptions.Value.Kind, disableDateTimeNormalization)));
}
else
{
map.MapProperty(property.Name).SetSerializer(new AbpMongoDbDateTimeSerializer(clockOptions.Value.Kind, disableDateTimeNormalization));
}
});
}
if (!BsonClassMap.IsClassMapRegistered(map.ClassType))
{
BsonClassMap.RegisterClassMap(map);
@ -52,6 +85,29 @@ namespace Volo.Abp.MongoDB
{
var map = new BsonClassMap(baseClass);
map.ConfigureAbpConventions();
if (clockOptions != null)
{
var dateTimePropertyInfos = baseClass.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.Where(property =>
(property.PropertyType == typeof(DateTime) ||
property.PropertyType == typeof(DateTime?)) &&
property.CanWrite
).ToList();
dateTimePropertyInfos.ForEach(property =>
{
if (property.PropertyType == typeof(DateTime?))
{
map.MapProperty(property.Name).SetSerializer(new NullableSerializer<DateTime>().WithSerializer(new AbpMongoDbDateTimeSerializer(clockOptions.Value.Kind, false)));
}
else
{
map.MapProperty(property.Name).SetSerializer(new AbpMongoDbDateTimeSerializer(clockOptions.Value.Kind, false));
}
});
}
BsonClassMap.RegisterClassMap(map);
}
}

18
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs

@ -16,7 +16,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
{
public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
{
protected DateTimeKind DateTimeKind { get; set; }
protected DateTimeKind Kind { get; set; }
protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
@ -34,7 +34,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
resultAsString.ShouldBe(DateTimeKind.ToString().ToLower());
resultAsString.ShouldBe(Kind.ToString().ToLower());
}
[Fact]
@ -45,7 +45,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
resultAsString.ShouldBe(DateTimeKind.ToString().ToLower());
resultAsString.ShouldBe(Kind.ToString().ToLower());
}
[Fact]
@ -89,7 +89,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
var resultAsString = await response.Content.ReadAsStringAsync();
//Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is UTC
//https://docs.microsoft.com/en-us/aspnet/core/migration/31-to-50?view=aspnetcore-3.1&tabs=visual-studio#datetime-values-are-model-bound-as-utc-times
resultAsString.ShouldBe($"utc_{DateTimeKind.ToString().ToLower()}_{DateTimeKind.ToString().ToLower()}_utc");
resultAsString.ShouldBe($"utc_{Kind.ToString().ToLower()}_{Kind.ToString().ToLower()}_utc");
}
[Fact]
@ -111,7 +111,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
resultAsString.ShouldBe($"local_{DateTimeKind.ToString().ToLower()}_{DateTimeKind.ToString().ToLower()}_local");
resultAsString.ShouldBe($"local_{Kind.ToString().ToLower()}_{Kind.ToString().ToLower()}_local");
}
}
@ -119,8 +119,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
{
protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
DateTimeKind = DateTimeKind.Utc;
services.Configure<AbpClockOptions>(x => x.Kind = DateTimeKind);
Kind = DateTimeKind.Utc;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
base.ConfigureServices(context, services);
}
@ -130,8 +130,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
{
protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
DateTimeKind = DateTimeKind.Local;
services.Configure<AbpClockOptions>(x => x.Kind = DateTimeKind);
Kind = DateTimeKind.Local;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
base.ConfigureServices(context, services);
}

4
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs

@ -1,4 +1,3 @@
using System;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
@ -13,7 +12,6 @@ using Volo.Abp.Modularity;
using Volo.Abp.TestApp;
using Volo.Abp.TestApp.Domain;
using Volo.Abp.TestApp.EntityFrameworkCore;
using Volo.Abp.Timing;
namespace Volo.Abp.EntityFrameworkCore
{
@ -55,8 +53,6 @@ namespace Volo.Abp.EntityFrameworkCore
abpDbContextConfigurationContext.DbContextOptions.UseSqlite(sqliteConnection);
});
});
Configure<AbpClockOptions>(options => options.Kind = DateTimeKind.Utc);
}
public override void OnPreApplicationInitialization(ApplicationInitializationContext context)

17
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/UnitTestModelCacheKeyFactory.cs

@ -0,0 +1,17 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Volo.Abp.EntityFrameworkCore
{
/// <summary>
/// Avoid unit test caching the configure of the entity.
/// OnModelCreating will be executed multiple times
/// </summary>
public class UnitTestModelCacheKeyFactory : IModelCacheKeyFactory
{
public object Create(DbContext context)
{
return context;
}
}
}

9
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpDateTimeValueConverter_Tests.cs

@ -1,9 +0,0 @@
using Volo.Abp.TestApp.Testing;
namespace Volo.Abp.EntityFrameworkCore.ValueConverters
{
public class AbpDateTimeValueConverter_Tests : AbpDateTimeValueConverter_Tests<AbpEntityFrameworkCoreTestModule>
{
}
}

66
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/ValueConverters/EFCore_DateTimeKindTests.cs

@ -0,0 +1,66 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.TestApp.Domain;
using Volo.Abp.TestApp.Testing;
using Volo.Abp.Timing;
using Xunit;
namespace Volo.Abp.EntityFrameworkCore.ValueConverters
{
public abstract class EFCore_DateTimeKindTests : DateTimeKind_Tests<AbpEntityFrameworkCoreTestModule>
{
[Fact]
public async Task DateTime_Kind_Should_Be_Normalized_In_View_Query_Test()
{
var personName = "bob lee";
await PersonRepository.InsertAsync(new Person(Guid.NewGuid(), personName, 18)
{
Birthday = DateTime.Parse("2020-01-01 00:00:00"),
LastActive = DateTime.Parse("2020-01-01 00:00:00"),
}, true);
var person = await PersonRepository.GetViewAsync(personName);
person.ShouldNotBeNull();
person.CreationTime.Kind.ShouldBe(Kind);
person.Birthday.ShouldNotBeNull();
person.Birthday.Value.Kind.ShouldBe(Kind);
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
//LastActive DisableDateTimeNormalization
person.LastActive.ShouldNotBeNull();
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified);
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
}
}
public class DateTimeKindTests : EFCore_DateTimeKindTests
{
protected override void AfterAddApplication(IServiceCollection services)
{
Kind = DateTimeKind.Unspecified;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
}
}
public class DateTimeKindTests_Local : EFCore_DateTimeKindTests
{
protected override void AfterAddApplication(IServiceCollection services)
{
Kind = DateTimeKind.Local;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
}
}
public class DateTimeKindTests_Utc : EFCore_DateTimeKindTests
{
protected override void AfterAddApplication(IServiceCollection services)
{
Kind = DateTimeKind.Utc;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
}
}
}

7
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs

@ -1,5 +1,6 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
@ -34,6 +35,12 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.ReplaceService<IModelCacheKeyFactory, UnitTestModelCacheKeyFactory>();
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Owned<District>();

81
framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Serializer/MongoDB_DateTimeKind_Tests.cs

@ -0,0 +1,81 @@
using System;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
using Volo.Abp.TestApp.Testing;
using Volo.Abp.Timing;
using Xunit;
namespace Volo.Abp.MongoDB.Serializer
{
[Collection(MongoTestCollection.Name)]
public abstract class MongoDB_DateTimeKind_Tests : DateTimeKind_Tests<AbpMongoDbTestModule>, IDisposable
{
protected override void AfterAddApplication(IServiceCollection services)
{
// MongoDB uses static properties to store the mapping information,
// We must reconfigure it in the new unit test.
foreach (var registeredClassMap in BsonClassMap.GetRegisteredClassMaps())
{
var frozen = registeredClassMap.GetType().BaseType?.GetField("_frozen", BindingFlags.NonPublic | BindingFlags.Instance);
frozen?.SetValue(registeredClassMap, false);
foreach (var declaredMemberMap in registeredClassMap.DeclaredMemberMaps)
{
var serializer = declaredMemberMap.GetSerializer();
switch (serializer)
{
case AbpMongoDbDateTimeSerializer dateTimeSerializer:
dateTimeSerializer.SetDateTimeKind(Kind);
break;
case NullableSerializer<DateTime> nullableSerializer:
{
var lazySerializer = nullableSerializer.GetType()
?.GetField("_lazySerializer", BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(serializer)?.As<Lazy<IBsonSerializer<DateTime>>>();
if (lazySerializer?.Value is AbpMongoDbDateTimeSerializer dateTimeSerializer)
{
dateTimeSerializer.SetDateTimeKind(Kind);
}
break;
}
}
}
frozen?.SetValue(registeredClassMap, true);
}
}
}
public class DateTimeKindTests_Unspecified : MongoDB_DateTimeKind_Tests
{
protected override void AfterAddApplication(IServiceCollection services)
{
Kind = DateTimeKind.Unspecified;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
base.AfterAddApplication(services);
}
}
public class DateTimeKindTests_Local : MongoDB_DateTimeKind_Tests
{
protected override void AfterAddApplication(IServiceCollection services)
{
Kind = DateTimeKind.Local;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
base.AfterAddApplication(services);
}
}
public class DateTimeKindTests_Utc : MongoDB_DateTimeKind_Tests
{
protected override void AfterAddApplication(IServiceCollection services)
{
Kind = DateTimeKind.Utc;
services.Configure<AbpClockOptions>(x => x.Kind = Kind);
base.AfterAddApplication(services);
}
}
}

30
framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/PersonRepository.cs

@ -0,0 +1,30 @@
using System;
using System.Threading.Tasks;
using MongoDB.Driver;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB;
using Volo.Abp.TestApp.Domain;
namespace Volo.Abp.TestApp.MongoDB
{
public class PersonRepository : MongoDbRepository<ITestAppMongoDbContext, Person, Guid>, IPersonRepository
{
public PersonRepository(IMongoDbContextProvider<ITestAppMongoDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task<PersonView> GetViewAsync(string name)
{
var person = await (await (await GetCollectionAsync()).FindAsync(x => x.Name == name)).FirstOrDefaultAsync();
return new PersonView()
{
Name = person.Name,
CreationTime = person.CreationTime,
Birthday = person.Birthday,
LastActive = person.LastActive
};
}
}
}

73
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/AbpDateTimeValueConverter_Tests.cs

@ -1,73 +0,0 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Modularity;
using Volo.Abp.TestApp.Domain;
using Volo.Abp.Timing;
using Xunit;
namespace Volo.Abp.TestApp.Testing
{
public abstract class AbpDateTimeValueConverter_Tests<TStartupModule> : TestAppTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IPersonRepository _personRepository;
protected AbpDateTimeValueConverter_Tests()
{
_personRepository = GetRequiredService<IPersonRepository>();
}
[Fact]
public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_Test()
{
var personId = Guid.Parse("4125582e-d100-4c27-aa84-e4de85830dca");
await _personRepository.InsertAsync(new Person(personId, "bob lee", 18)
{
Birthday = DateTime.Parse("2020-01-01 00:00:00"),
LastActive = DateTime.Parse("2020-01-01 00:00:00"),
}, true);
var person = await _personRepository.GetAsync(personId);
person.ShouldNotBeNull();
person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc);
person.Birthday.ShouldNotBeNull();
person.Birthday.Value.Kind.ShouldBe(DateTimeKind.Utc);
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
//LastActive DisableDateTimeNormalization
person.LastActive.ShouldNotBeNull();
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified);
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
}
[Fact]
public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_View_Test()
{
var personName = "bob lee";
await _personRepository.InsertAsync(new Person(Guid.NewGuid(), personName, 18)
{
Birthday = DateTime.Parse("2020-01-01 00:00:00"),
LastActive = DateTime.Parse("2020-01-01 00:00:00"),
}, true);
var person = await _personRepository.GetViewAsync(personName);
person.ShouldNotBeNull();
person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc);
person.Birthday.ShouldNotBeNull();
person.Birthday.Value.Kind.ShouldBe(DateTimeKind.Utc);
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
//LastActive DisableDateTimeNormalization
person.LastActive.ShouldNotBeNull();
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified);
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
}
}
}

46
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DateTimeKind_Tests.cs

@ -0,0 +1,46 @@
using System;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Volo.Abp.TestApp.Domain;
using Xunit;
namespace Volo.Abp.TestApp.Testing
{
public abstract class DateTimeKind_Tests<TStartupModule> : TestAppTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
protected IPersonRepository PersonRepository { get; }
protected DateTimeKind Kind { get; set; }
protected DateTimeKind_Tests()
{
PersonRepository = GetRequiredService<IPersonRepository>();
}
[Fact]
public async Task DateTime_Kind_Should_Be_Normalized_Test()
{
var personId = Guid.NewGuid();
await PersonRepository.InsertAsync(new Person(personId, "bob lee", 18)
{
Birthday = DateTime.Parse("2020-01-01 00:00:00"),
LastActive = DateTime.Parse("2020-01-01 00:00:00"),
}, true);
var person = await PersonRepository.GetAsync(personId);
person.ShouldNotBeNull();
person.CreationTime.Kind.ShouldBe(Kind);
person.Birthday.ShouldNotBeNull();
person.Birthday.Value.Kind.ShouldBe(Kind);
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
//LastActive DisableDateTimeNormalization
person.LastActive.ShouldNotBeNull();
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified);
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00");
}
}
}
Loading…
Cancel
Save