我有以下观点:
@model dynamic
<form class="form-horizontal" id="formDynamicItem" action="/DynamicItem/SaveItem" method="post">
@Html.AntiForgeryToken()
<div class="col-xs-12 buttonBar">
<button type="submit" value="Save" name="submitButton" class="btn">Save</button>
<button type="submit" value="Cancel" name="submitButton" class="btn">Cancel</button>
</div>
<div class="col-lg-6">
<div class="ibox ">
<div class="ibox-content">
@{
foreach (var obj in Model)
{
var kvpObj = (KeyValuePair<string, object>)obj;
var entityProp = (EntityAttributeProperties)kvpObj.Value;
<div class="form-group">
@if (entityProp.IsHiddenField)
{
<input type="hidden" class="form-control" data-val="true" id="@kvpObj.Key" name="@kvpObj.Key" value="@entityProp.Value" />
}
else if (entityProp.IsFormField)
{
var isReadOnly = entityProp.IsReadonly ? "readonly" : "";
IHtmlString validationRules = Html.Raw(string.Empty);
if (entityProp.ValidationRules != null)
{
validationRules = entityProp.ValidationRules;
}
@Html.Label(entityProp.Name, new { @class = labelClass })
<div class="@controlClass">
@switch (@entityProp.Type)
{
//... many cases
default:
<input type="text" class="form-control" id="@kvpObj.Key" name="@kvpObj.Key" value="@entityProp.Value" @isReadOnly @validationRules />
break;
}
</div>
}
</div>
}
}
</div>
</div>
</div>
</form>
@section Scripts {
<script>
$("#formDynamicItem").validate();
</script>
}
在控制器中,我使用FormCollection获取我的值:
public ActionResult SaveItem(FormCollection form)
{
...
newValue = typeConverter.ConvertFromString(form[entityAttribute.Name]);
...
}
}
我的问题如下:
如何在此类动态模型上建立服务器端验证?我能以某种方式使用FormCollection吗?可能以某种方式构建动态视图模型?如果有人有这方面的经验,请考虑给出一个建议(答案)。
更新:使用ViewModel制作详细信息页面,其中包含动态模型
所以,经过多次重构后,我似乎再次陷入服务器端验证:
所以现在我有了这个ViewModel:
public class DynamicItemViewModel
{
public Guid Id { get; set; }
public List<EntityAttributeProperties> Properties { get; set; }
}
此详细信息页面:
@model ExactDistillation.Models.DynamicItem.DynamicItemViewModel
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
@using (Html.BeginForm("SaveItem", "DynamicItem", FormMethod.Post, new { @class = "form-horizontal", @id = "formDynamicItem" }))
{
@Html.AntiForgeryToken()
@Html.HiddenFor(x => x.Id)
<div class="col-xs-12 buttonBar">
<button type="submit" value="Save" name="submitButton" class="btn btn-primary pull-right">Save</button>
<button type="submit" value="Cancel" name="submitButton" class="btn btn-default pull-right cancel">Cancel</button>
</div>
<div class="col-lg-6">
<div class="ibox float-e-margins">
<div class="ibox-title text-webwonders">
<h5>Item</h5>
</div>
<div class="ibox-content">
@{
for (int i = 0; i < Model.Properties.Count; i++)
{
@Html.EditorFor(m => Model.Properties[i], "EntityAttributeProperties", "Properties[" + i + "]")
}
}
</div>
</div>
</div>
}
</div>
</div>
这就是我定义EntityAttributeProperties页面的方式:
@model EntityAttributeProperties
<div class="form-group">
@if (Model.IsHiddenField)
{
@Html.HiddenFor(x => x.Value)
}
else if (Model.IsFormField)
{
@Html.Label(Model.Name, new { @class = "col-sm-5 col-md-4 col-lg-3" })
<div class="col-sm-7 col-md-8 col-lg-9">
@switch (Model.Type)
{
--- Many cases
default:
@Html.DynamicTextBoxFor(m => m.Value, null, Model.IsReadonly, Model.ValidationRules)
break;
}
</div>
}
</div>
EntityAttributesProperties看起来如下:
public class EntityAttributeProperties
{
public string Name { get; set; }
public string DisplayName { get; set; }
public object Value { get; set; }
public EntityAttributeDataTypeEnum Type { get; set; }
public short Order { get; set; }
public bool IsFormField { get; set; }
public bool IsReadonly { get; set; }
public bool IsHiddenField { get; set; }
public Dictionary<string,object> ValidationRules { get; set; }
}
所以,我正在尝试为Model进行服务器端验证,但是我被困住了,因为我找不到任何优雅的解决方案来解决我的问题,只是我需要进行大量硬编码的解决方案(我不喜欢)。
以下是我收到表格提交的方式:
public ActionResult SaveItem(DynamicItemViewModel model)
{
List<EntityAttributeExtendedView> entityAttributes = GetItemEntityAttributes();
DataObject dataObject = _dbContext.DataObjectCollection.FirstOrDefault(x => x.Id == model.Id);
if (dataObject != null)
{
JObject json = JObject.Parse(dataObject.Value);
dynamic dynJson = JsonConvert.DeserializeObject(dataObject.Value);
// Possibly loop through all entity attributes and separately make a custom validation ?
// Or somehow create custom Model State for validation ?
}
return View("Detail", model);
}
对于如何通过服务器端验证解决问题,我将不胜感激。
感谢。
答案 0 :(得分:2)
FormCollection
是一种非常原始的数据形式,无法轻松验证。我建议您重构视图以便能够使用ViewModel,否则您将很难处理数据。
我无法向您展示完整的方式,但会给您一些提示:
Items
(类型为EntityAttributeProperties
)的列表。我们称之为MainViewModel
。@Html.EditoFor(x => x.Items)
生成正确的HTML。 ASP.NET MVC将使用EntityAttributeProperties
类型EntityAttributeProperties.cshtml
子文件夹中创建新视图EditorTemplates
的好时机entityProp.Type
次切换,但请注意ID生成,始终使用@Html.IdFor(...)
等,而不是生成自己的ID以保持视图模型的类型安全< / LI>
MainViewModel
的视图模型。如果一切顺利,即使您使用不同的控件(隐藏字段,文本字段,下拉菜单......)来填充值从我的角度来看,只有这种MVC安全方法才能在这种情况下取得成功
答案 1 :(得分:1)
我正在添加另一个答案,因为问题发生了重大变化。
一个好方法是使用IValidatableObject
接口。因此,您将此界面添加到EntityAttributeProperties
类,并且必须覆盖方法Validate
。对于像必填字段这样的简单验证,您可以使用所谓的验证属性。
您的EntityAttributeProperties
课程将按照以下方式进行装饰:
public class EntityAttributeProperties : IValidatableObject
{
public string Name { get; set; }
[Required]
public object Value { get; set; }
...
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if (... /* some condition, e.g. specific EntityAttributeDataTypeEnum */)
{
// Do some validation
// some other random test
if (.../* something not right... */)
{
results.Add(new ValidationResult("your input was not valid!"));
}
}
return results;
}
}
你可能还需要让你的DynamicItemViewModel
和IValidatableObject
循环遍历这些项目,但有时MVC足够智能自动验证子项目,所以你< em>可能需要这个:
public class DynamicItemViewModel : IValidatableObject
{
...
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return Items.SelectMany(x => x.Validate(validationContext));
}
}
现在在你的控制器中,你基本上需要检查你的ModelState
。自动生成的ModelState
属性包含所有错误。