Merge pull request #2151 from abpframework/maiming/AbpDateTimeModelBinder

Implement AbpDateTimeModelBinderProvider & AbpDateTimeModelBinder
pull/2253/head
Halil İbrahim Kalkan 5 years ago committed by GitHub
commit cfb714ece7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -4,6 +4,7 @@ using Volo.Abp.AspNetCore.Mvc.Auditing;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
using Volo.Abp.AspNetCore.Mvc.Features;
using Volo.Abp.AspNetCore.Mvc.ModelBinding;
using Volo.Abp.AspNetCore.Mvc.Uow;
using Volo.Abp.AspNetCore.Mvc.Validation;
@ -35,7 +36,7 @@ namespace Volo.Abp.AspNetCore.Mvc
private static void AddModelBinders(MvcOptions options)
{
//options.ModelBinderProviders.Add(new AbpDateTimeModelBinderProvider());
options.ModelBinderProviders.Insert(0, new AbpDateTimeModelBinderProvider());
}
private static void AddMetadataProviders(MvcOptions options, IServiceCollection services)

@ -0,0 +1,49 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Volo.Abp.Timing;
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
{
public class AbpDateTimeModelBinder : IModelBinder
{
private readonly Type _type;
private readonly SimpleTypeModelBinder _simpleTypeModelBinder;
private readonly IClock _clock;
public AbpDateTimeModelBinder(ModelBinderProviderContext context)
{
_type = context.Metadata.ModelType;
_clock = context.Services.GetRequiredService<IClock>();
_simpleTypeModelBinder = new SimpleTypeModelBinder(context.Metadata.ModelType,
context.Services.GetRequiredService<ILoggerFactory>());
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
await _simpleTypeModelBinder.BindModelAsync(bindingContext);
if (!bindingContext.Result.IsModelSet)
{
return;
}
if (_type == typeof(DateTime))
{
var dateTime = (DateTime) bindingContext.Result.Model;
bindingContext.Result = ModelBindingResult.Success(_clock.Normalize(dateTime));
}
else
{
var dateTime = (DateTime?) bindingContext.Result.Model;
if (dateTime != null)
{
bindingContext.Result = ModelBindingResult.Success(_clock.Normalize(dateTime.Value));
}
}
}
}
}

@ -0,0 +1,47 @@
using System;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Volo.Abp.Timing;
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
{
public class AbpDateTimeModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType != typeof(DateTime) &&
context.Metadata.ModelType != typeof(DateTime?))
{
return null;
}
if (context.Metadata.ContainerType == null)
{
if (context.Metadata is DefaultModelMetadata defaultModelMetadata &&
defaultModelMetadata.Attributes.Attributes.All(x => x.GetType() != typeof(DisableDateTimeNormalizationAttribute)))
{
return new AbpDateTimeModelBinder(context);
}
}
else
{
var dateNormalizationDisabledForClass =
context.Metadata.ContainerType.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true);
var dateNormalizationDisabledForProperty = context.Metadata.ContainerType
.GetProperty(context.Metadata.PropertyName)
?.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true);
if (!dateNormalizationDisabledForClass &&
dateNormalizationDisabledForProperty != null &&
!dateNormalizationDisabledForProperty.Value)
{
return new AbpDateTimeModelBinder(context);
}
}
return null;
}
}
}

@ -0,0 +1,61 @@
using System;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Timing;
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
{
[Route("api/model-Binding-test")]
public class ModelBindingController : AbpController
{
[HttpGet("DateTimeKind")]
public string DateTimeKind(DateTime input)
{
return input.Kind.ToString().ToLower();
}
[HttpGet("NullableDateTimeKind")]
public string NullableDateTimeKind(DateTime? input)
{
return input.Value.Kind.ToString().ToLower();
}
[HttpGet("DisableDateTimeNormalizationDateTimeKind")]
public string DisableDateTimeNormalizationDateTimeKind([DisableDateTimeNormalization]DateTime input)
{
return input.Kind.ToString().ToLower();
}
[HttpGet("DisableDateTimeNormalizationNullableDateTimeKind")]
public string DisableDateTimeNormalizationNullableDateTimeKind([DisableDateTimeNormalization]DateTime? input)
{
return input.Value.Kind.ToString().ToLower();
}
[HttpGet("ComplexTypeDateTimeKind")]
public string ComplexTypeDateTimeKind(GetDateTimeKindModel input)
{
return input.Time1.Kind.ToString().ToLower() + "_" +
input.Time2.Kind.ToString().ToLower() + "_" +
input.Time3.Value.Kind.ToString().ToLower() + "_" +
input.InnerModel.Time4.Kind.ToString().ToLower();
}
}
public class GetDateTimeKindModel
{
[DisableDateTimeNormalization]
public DateTime Time1 { get; set; }
public DateTime Time2 { get; set; }
public DateTime? Time3 { get; set; }
public GetDateTimeKindInnerModel InnerModel { get; set; }
[DisableDateTimeNormalization]
public class GetDateTimeKindInnerModel
{
public DateTime Time4 { get; set; }
}
}
}

@ -0,0 +1,100 @@
using System;
using System.Net;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Shouldly;
using Volo.Abp.Timing;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
{
public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase
{
protected DateTimeKind DateTimeKind { get; set; }
protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
services.Configure<AbpClockOptions>(x => x.Kind = DateTimeKind);
}
[Fact]
public async Task DateTimeKind_Test()
{
var response = await Client.GetAsync("/api/model-Binding-test/DateTimeKind?input=2010-01-01T00:00:00Z");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
resultAsString.ShouldBe(DateTimeKind.ToString().ToLower());
}
[Fact]
public async Task NullableDateTimeKind_Test()
{
var response =
await Client.GetAsync("/api/model-Binding-test/NullableDateTimeKind?input=2010-01-01T00:00:00Z");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
resultAsString.ShouldBe(DateTimeKind.ToString().ToLower());
}
[Fact]
public async Task DisableDateTimeNormalizationDateTimeKind_Test()
{
var response =
await Client.GetAsync(
"/api/model-Binding-test/DisableDateTimeNormalizationDateTimeKind?input=2010-01-01T00:00:00Z");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
//Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local.
resultAsString.ShouldBe(DateTimeKind.Local.ToString().ToLower());
}
[Fact]
public async Task DisableDateTimeNormalizationNullableDateTimeKind_Test()
{
var response =
await Client.GetAsync(
"/api/model-Binding-test/DisableDateTimeNormalizationNullableDateTimeKind?input=2010-01-01T00:00:00Z");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
//Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local.
resultAsString.ShouldBe(DateTimeKind.Local.ToString().ToLower());
}
[Fact]
public async Task ComplexTypeDateTimeKind_Test()
{
var response = await Client.GetAsync("/api/model-Binding-test/ComplexTypeDateTimeKind?" +
"Time1=2010-01-01T00:00:00Z&" +
"Time2=2010-01-01T00:00:00Z&" +
"Time3=2010-01-01T00:00:00Z&" +
"InnerModel.Time4=2010-01-01T00:00:00Z");
response.StatusCode.ShouldBe(HttpStatusCode.OK);
var resultAsString = await response.Content.ReadAsStringAsync();
//Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local.
resultAsString.ShouldBe(
$"local_{DateTimeKind.ToString().ToLower()}_{DateTimeKind.ToString().ToLower()}_local");
}
}
public class ModelBindingController_Utc_Tests : ModelBindingController_Tests
{
public ModelBindingController_Utc_Tests()
{
DateTimeKind = DateTimeKind.Utc;
}
}
public class ModelBindingController_Local_Tests : ModelBindingController_Tests
{
public ModelBindingController_Local_Tests()
{
DateTimeKind = DateTimeKind.Local;
}
}
}
Loading…
Cancel
Save