Routing: Datetime parameter passing as null/empty

别等时光非礼了梦想. 提交于 2019-12-02 09:18:19

I had the same problem with GET requests and dates in ASP.NET Core 2. If you want to override the default behaviour across the app so it uses the servers default date format for both GET and POST requests see below. Possible room for improvement around parsing the date (ie using TryParseExact etc) and note this doesn't cover nullable datetimes.

This code is heavily based on https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding

public class DateTimeModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        // Specify a default argument name if none is set by ModelBinderAttribute
        var modelName = bindingContext.BinderModelName;
        if (string.IsNullOrEmpty(modelName))
        {
            modelName = bindingContext.ModelName;
        }

        // Try to fetch the value of the argument by name
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

        if (valueProviderResult == ValueProviderResult.None)
        {
            return Task.CompletedTask;
        }

        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

        var value = valueProviderResult.FirstValue;

        // Check if the argument value is null or empty
        if (string.IsNullOrEmpty(value))
        {
            logger.Debug($"{modelName} was empty or null");
            return Task.CompletedTask;
        }

        if (!DateTime.TryParse(value, out DateTime date))
        {
            bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "Invalid date or format.");
            return Task.CompletedTask;
        }

        bindingContext.Result = ModelBindingResult.Success(date);
        return Task.CompletedTask;
    }
}

public class DateTimeModelBinderProvider : IModelBinderProvider
{
    private readonly IModelBinder binder = new DateTimeModelBinder();

    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        //Could possibly inspect the context and apply to GETs only if needed?
        return context.Metadata.ModelType == typeof(DateTime) ? binder : null;
    }
}

Then in the StartUp Class > ConfigureServices Method

services.AddMvc(options =>
    {
        //Forces Dates to parse via server format, inserts in the binding pipeline as first but you can adjust it as needed
        options.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());
    });
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!