.NET Core Model活页夹仅适用于基类

时间:2019-01-25 15:20:45

标签: c# asp.net-mvc asp.net-core model-binding

public class BondsFilterModel : BaseListRequest
{
    public string Keyword { get; set; }

    public DateTime? DateFrom { get; set; }

    public DateTime? DateTo { get; set; }
}

 public class BaseListRequest
{
    public int PageSize { get; set; }

    public int Page { get; set; }

    public string SortColumn { get; set; }

    public SortDirection SortDirection { get; set; }
}

public enum SortDirection
{
    Ascending = 1,
    Descending = 2
}

您可以在完整的.NET框架中

public class BaseListRequestModelBinder : DefaultModelBinder
{
    public const string KendoSort = "sort";
    public const string KendoPage = "page";
    public const string KendoPageSize = "pageSize";
    public const char SplitChar = '-';
    public const string AscendingDirectionString = "asc";

    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var request = controllerContext.HttpContext.Request;

        if (bindingContext.Model is BaseListRequest model)
        {
            var page = Convert.ToInt32(request.Form[KendoPage]);
            model.Page = Math.Max(page - 1, 0);

            model.PageSize = Convert.ToInt32(request.Form[KendoPageSize]);

            var sort = request.Form[KendoSort];

            if (!string.IsNullOrWhiteSpace(sort))
            {
                model.SortColumn = sort.Remove(sort.LastIndexOf(SplitChar));
                model.SortDirection = sort.Split(SplitChar)
                    .LastOrDefault()
                    ?.Equals(AscendingDirectionString, StringComparison.InvariantCultureIgnoreCase) ?? false ? SortDirection.Ascending : SortDirection.Descending;
            }
        }

        base.OnModelUpdated(controllerContext, bindingContext);
    }
}

public class BaseListRequestModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(Type modelType)
    {
        if (typeof(BaseListRequest).IsAssignableFrom(modelType))
        {
            return new BaseListRequestModelBinder();
        }

        return null;
    }
}

和global.asax

    protected void Application_Start()
    {
       // other code
        ModelBinderProviders.BinderProviders.Add(new BaseListRequestModelBinderProvider());
    }

那只会填充基类的属性,派生类将从默认的模型绑定器填充。

在.NET Core中,当我这样做时:

public class BaseListRequestModelBinder : IModelBinder
{
    public const string KendoSort = "sort";
    public const string KendoPage = "page";
    public const string KendoPageSize = "pageSize";
    public const char SplitChar = '-';
    public const string AscendingDirectionString = "asc";

    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        var model = Activator.CreateInstance(bindingContext.ModelType) as BondsFilterModel;

        var pageString = bindingContext.ValueProvider.GetValue(KendoPage).FirstValue;

        var page = Convert.ToInt32(pageString);
        model.Page = Math.Max(page - 1, 0);

        var pageSizeString = bindingContext.ValueProvider.GetValue(KendoPageSize).FirstValue;
        model.PageSize = Convert.ToInt32(pageSizeString);

        var sort = bindingContext.ValueProvider.GetValue(KendoSort).FirstValue;

        if (!string.IsNullOrWhiteSpace(sort))
        {
            model.SortColumn = sort.Remove(sort.LastIndexOf(SplitChar));
            model.SortDirection = sort.Split(SplitChar)
                .LastOrDefault()
                ?.Equals(AscendingDirectionString, StringComparison.InvariantCultureIgnoreCase) ?? false ? SortDirection.Ascending : SortDirection.Descending;
        }

        bindingContext.Result = ModelBindingResult.Success(model);

        return Task.CompletedTask;
    }
}

public class BaseListRequestModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (typeof(BaseListRequest).IsAssignableFrom(context.Metadata.ModelType))
        {
            return new BinderTypeModelBinder(typeof(BaseListRequestModelBinder));
        }

        return null;
    }
}

和Startup.cs

services.AddMvc(config => config.ModelBinderProviders.Insert(0, new BaseListRequestModelBinderProvider()))

我的资料夹被调用,并且基类被正确绑定。但是没有派生类的属性被设置。 我猜想完整的.NET Framework和Core之间的主要区别在于,我必须在Core的绑定器中亲自实例化模型,而在完整的.NET Framework中,我要更改现有模型。

有没有办法像在完整的.NET框架中那样仅绑定基类并将派生类留给默认的绑定器?

1 个答案:

答案 0 :(得分:-1)

按顺序检查Model Binder Provider集合。

在.Net Framework中,您要在集合的末尾添加自定义模型绑定程序提供程序。因此,它将允许您在自定义模型联编程序之前调用内置模型联编程序提供程序。

ModelBinderProviders.BinderProviders.Add(new BaseListRequestModelBinderProvider());

在.Net Core中,您是在集合开始时通过将其插入索引0来添加自定义模型绑定程序提供程序的。

services.AddMvc(config => config.ModelBinderProviders.Insert(0, new BaseListRequestModelBinderProvider()));

因此解决方案是将其添加到集合的末尾,以使内置模型提供程序在自定义模型提供程序之前被调用,与在.Net Framework中执行的步骤相同。

services.AddMvc(config => config.ModelBinderProviders.Add(new BaseListRequestModelBinderProvider()));