从自定义模型活页夹调用默认模型活页夹

本文关键字:模型 默认 调用 自定义 | 更新日期: 2023-09-27 17:59:31

我已经编写了一个自定义模型绑定器,它应该映射日期,根据当前区域性来自URL字符串(GET)(这里有一个附带说明:如果使用GET作为http调用,默认模型绑定器不考虑当前区域性…)。

public class DateTimeModelBinder : IModelBinder
{
    #region IModelBinder Members
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (controllerContext.HttpContext.Request.HttpMethod == "GET")
        {
            string theDate = controllerContext.HttpContext.Request.Form[bindingContext.ModelName];
            DateTime dt = new DateTime();
            bool success = DateTime.TryParse(theDate, System.Globalization.CultureInfo.CurrentUICulture, System.Globalization.DateTimeStyles.None, out dt);
            if (success)
            {
                return dt;
            }
            else
            {
                return null;
            }
        }
        return null; // Oooops...
    }
    #endregion
}

我在global.asax:中注册了模型绑定器

ModelBinders.Binders.Add(typeof(DateTime?), new DateTimeModelBinder());

现在问题出现在最后一个return null;中。如果我在POST中使用其他表单,它会用null覆盖已经映射的值。我该如何避免这种情况?

Thx用于任何输入。sl3dg3

从自定义模型活页夹调用默认模型活页夹

DefaultModelBinder派生,然后调用基本方法:

public class DateTimeModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // ... Your code here
        return base.BindModel(controllerContext, bindingContext);
    }
}

这实际上是一个微不足道的解决方案:我创建了一个默认绑定器的新实例,并将任务传递给他:

public class DateTimeModelBinder : IModelBinder
{
#region IModelBinder Members
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    if (controllerContext.HttpContext.Request.HttpMethod == "GET")
    {
        string theDate = controllerContext.HttpContext.Request.Form[bindingContext.ModelName];
        DateTime dt = new DateTime();
        bool success = DateTime.TryParse(theDate, System.Globalization.CultureInfo.CurrentUICulture, System.Globalization.DateTimeStyles.None, out dt);
        if (success)
        {
            return dt;
        }
        else
        {
            return null;
        }
    }
    DefaultModelBinder binder = new DefaultModelBinder();
    return binder.BindModel(controllerContext, bindingContext);
}
#endregion
}

另一个可能的解决方案是将一些最好的默认模型投标者传递到自定义中并在那里调用它。

public class BaseApiRequestModelBinder : IModelBinder
{
    private readonly IModelBinder _modelBinder;
    public BaseApiRequestModelBinder(IModelBinder modelBinder)
    {
        _modelBinder = modelBinder;
    }
    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        //calling best default model binder
        await _modelBinder.BindModelAsync(bindingContext);
        var model = bindingContext.Result.Model as BaseApiRequestModel;
        //do anything you want with a model that was bind with default binder
    }
}

public class BaseApiRequestModelBinderProvider : IModelBinderProvider
{
    private IList<IModelBinderProvider> _modelBinderProviders { get; }
    public BaseApiRequestModelBinderProvider(IList<IModelBinderProvider> modelBinderProviders)
    {
        _modelBinderProviders = modelBinderProviders;
    }
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }
        if (context.Metadata.ModelType == typeof(BaseApiRequestModel) || context.Metadata.ModelType.IsSubclassOf(typeof(BaseApiRequestModel))) 
        {
            //Selecting best default model binder. Don't forget to exlude the current one as it is also in list
            var defaultBinder = _modelBinderProviders
                    .Where(x => x.GetType() != this.GetType())
                    .Select(x => x.GetBinder(context)).FirstOrDefault(x => x != null);
            if (defaultBinder != null)
            {
                return new BaseApiRequestModelBinder(defaultBinder);
            }
        }
        return null;
    }

 //Register model binder provider in ConfigureServices in startup
        services
            .AddMvc(options => {                 
                options.ModelBinderProviders.Insert(0, new BaseApiRequestModelBinderProvider(options.ModelBinderProviders));
            })