从自定义模型装订器调用默认模型装订器?

时间:2011-06-20 13:35:13

标签: c# asp.net-mvc-2 asp.net-mvc-3

我编写了一个自定义模型Binder,它应该根据当前文化来映射来自URL-Strings(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

3 个答案:

答案 0 :(得分:6)

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

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

        return base.BindModel(controllerContext, bindingContext);
    }

}

答案 1 :(得分:4)

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

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
}

答案 2 :(得分:1)

另一种可能的解决方案是将一些最佳的默认模型出价者传递给自定义项,然后在其中调用。

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));
            })