asp.net-mvc – 自定义模型绑定,模型状态和数据注释

前端之家收集整理的这篇文章主要介绍了asp.net-mvc – 自定义模型绑定,模型状态和数据注释前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一些关于自定义模型绑定,模型状态和数据注释的问题.

1)如果我的模型上有数据注释,那么在自定义模型绑定器中进行验证是否是多余的,因为这就是我认为的数据注释点.

2)为什么我的控制器将模型状态视为有效,即使它不是,主要是我使Name属性为null或太短.

3)将自定义模型绑定器视为构造方法是否可行,因为这是他们提醒我的.

首先是我的模型.

public class Projects
{     
    [Key]
    [required]
    public Guid ProjectGuid { get; set; }

    [required]
    public string AccountName { get; set; }

    [required(ErrorMessage = "Project name required")]
    [StringLength(128,ErrorMessage = "Project name cannot exceed 128 characters")]
    [MinLength(3,ErrorMessage = "Project name must be at least 3 characters")]
    public string Name { get; set; }

    [required]
    public long TotalTime { get; set; }
}

然后我使用自定义模型绑定器绑定模型的某些属性.请不要介意它只是试图让它运行然后重构它是快速和肮脏的.

public class ProjectModelBinder : IModelBinder
{
     public object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext)
    {
        if (controllerContext == null)
        {
            throw new ArgumentNullException("controllerContext");
        }
        if (bindingContext == null)
        {
            throw new ArgumentNullException("bindingContext");
        }
        var p = new Project();
        p.ProjectGuid = System.Guid.NewGuid();
        p.AccountName = controllerContext.HttpContext.User.Identity.Name;
        p.Name = controllerContext.HttpContext.Request.Form.Get("Name");
        p.TotalTime = 0;

        //
        // Is this redundant because of the data annotations?!?!
        //
        if (p.AccountName == null)
            bindingContext.ModelState.AddModelError("Name","Name is required");

        if (p.AccountName.Length < 3)
            bindingContext.ModelState.AddModelError("Name","Minimum length is 3 characters");

        if (p.AccountName.Length > 128)
            bindingContext.ModelState.AddModelError("Name","Maximum length is 128 characters");

        return p;
    }
}

现在我的控制器动作.

[HttpPost]
    public ActionResult CreateProject([ModelBinder(typeof(ProjectModelBinder))]Project project)
    {
        //
        // For some reason the model state comes back as valid even when I force an error
        //
        if (!ModelState.IsValid)
            return Content(Boolean.FalseString);

        //_projectRepository.CreateProject(project);

        return Content(Boolean.TrueString);

    }

编辑

我在另一个stackoverflow问题上找到了一些代码,但我不确定在哪个点上我会将以下值注入此possible solution.

创建新对象时我想要注入的内容

var p = new Project();
        p.ProjectGuid = System.Guid.NewGuid();
        p.AccountName = controllerContext.HttpContext.User.Identity.Name;
        p.Name = controllerContext.HttpContext.Request.Form.Get("Name");
        p.TotalTime = 0;

如何将上述代码纳入以下内容(可能的解决方案):

public class ProjectModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(Project))
            {
                ModelBindingContext newBindingContext = new ModelBindingContext()
                {

                    ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(
                        () => new Project(),// construct a Project object,typeof(Project)         // using the Project Metadata
                    ),ModelState = bindingContext.ModelState,ValueProvider = bindingContext.ValueProvider

                };

                // call the default model binder this new binding context
                return base.BindModel(controllerContext,newBindingContext);
            }
            else
            {
                return base.BindModel(controllerContext,bindingContext);
            }
        }

    }

}

解决方法

如果从DefaultModelBinder继承,覆盖BindModel方法,调用base.BindModel方法然后进行手动更改(设置guid,帐户名和总时间),您会发现事情更容易.

1)完成验证是多余的.您可以编写代码来反映验证元数据,就像默认情况一样,或者只是删除数据注释验证,因为您没有在模型绑定器中使用它.

2)我不知道,似乎是正确的,您应该单步执行代码并确保自定义绑定器填充所有适用的规则.

3)这是一个肯定的工厂,但不是一个构造函数.

编辑:你不能更接近解决方案,只需在模型工厂函数中设置所需的属性

public class ProjectModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(Project))
        {
            ModelBindingContext newBindingContext = new ModelBindingContext()
            {

                ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(
                    () => new Project()  // construct a Project object
                    {
                        ProjectGuid = System.Guid.NewGuid(),AccountName = controllerContext.HttpContext.User.Identity.Name,// don't set name,thats the default binder's job
                        TotalTime = 0,},typeof(Project)         // using the Project Metadata
                ),ValueProvider = bindingContext.ValueProvider

            };

            // call the default model binder this new binding context
            return base.BindModel(controllerContext,newBindingContext);
        }
        else
        {
            return base.BindModel(controllerContext,bindingContext);
        }
    }

}

或者您可以替代地覆盖CreateModel方法

protected override object CreateModel(ControllerContext controllerContext,ModelBindingContext bindingContext,System.Type modelType)
{
    if (modelType == typeof(Project))
    {
        Project model = new Project()
        {
            ProjectGuid = System.Guid.NewGuid(),thats the default binder's job
            TotalTime = 0,};

        return model;
    }

    throw new NotSupportedException("You can only use the ProjectModelBinder on parameters of type Project.");
}

猜你在找的asp.Net相关文章