Asp.net mvc 自定义模型绑定、模型状态和数据注释
关于自定义模型绑定、模型状态和数据注释,我有一些问题 1) 如果我的模型上有数据注释,那么在自定义模型绑定器中进行验证是否是多余的,因为我认为数据注释的意义就在于此 2) 为什么我的控制器在模型状态无效的情况下仍将其视为有效状态,主要是我将Name属性设置为null或太短 3) 可以将自定义模型绑定器看作构造函数方法吗,因为这正是它们提醒我的 首先,这是我的模型Asp.net mvc 自定义模型绑定、模型状态和数据注释,asp.net-mvc,validation,data-annotations,modelbinders,modelstate,Asp.net Mvc,Validation,Data Annotations,Modelbinders,Modelstate,关于自定义模型绑定、模型状态和数据注释,我有一些问题 1) 如果我的模型上有数据注释,那么在自定义模型绑定器中进行验证是否是多余的,因为我认为数据注释的意义就在于此 2) 为什么我的控制器在模型状态无效的情况下仍将其视为有效状态,主要是我将Name属性设置为null或太短 3) 可以将自定义模型绑定器看作构造函数方法吗,因为这正是它们提醒我的 首先,这是我的模型 public class Projects { [Key] [Required] public Gu
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;
}
}
编辑
我在另一个stackoverflow问题上找到了一些代码,但我不确定在哪一点我会将以下值注入到这个问题中
创建新对象时要注入的内容:
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;
如何将上述代码转换为以下内容(可能的解决方案):
如果从
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
),
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);
}
}
}
或者您也可以替代CreateModel
方法:
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, System.Type modelType)
{
if (modelType == typeof(Project))
{
Project model = new Project()
{
ProjectGuid = System.Guid.NewGuid(),
AccountName = controllerContext.HttpContext.User.Identity.Name,
// don't set name, thats the default binder's job
TotalTime = 0,
};
return model;
}
throw new NotSupportedException("You can only use the ProjectModelBinder on parameters of type Project.");
}
嘿,你介意检查我的帖子吗?我在底部对它进行了编辑,并提出了一个可能的解决方案,我只是不知道下一步该怎么做。Modelbinding对我来说还是个新鲜事物。或许你有一个更简单的方法来实现同样的事情。@Odnxe:很难比你更接近,我在MVC3中实现了这个,以再次检查它是否按预期工作(或者至少我理解你的意图)。太棒了,谢谢你最后的一点帮助!我知道我离模型绑定和MVC已经很近了,但我对模型绑定和MVC还不是很熟悉。你帮我省去了好几个小时的头痛。两种解决方案都有效,这只是一种偏好还是另一种?还是一种方法天生就比另一种好?
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
),
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);
}
}
}
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, System.Type modelType)
{
if (modelType == typeof(Project))
{
Project model = new Project()
{
ProjectGuid = System.Guid.NewGuid(),
AccountName = controllerContext.HttpContext.User.Identity.Name,
// don't set name, thats the default binder's job
TotalTime = 0,
};
return model;
}
throw new NotSupportedException("You can only use the ProjectModelBinder on parameters of type Project.");
}