在我的班级中,我有一个文件附件的属性,如此......
public class Certificate {
[Required]
// TODO: Wow looks like there's a problem with using regex in MVC 4, this does not work!
[RegularExpression(@"^.*\.(xlsx|xls|XLSX|XLS)$", ErrorMessage = "Only Excel files (*.xls, *.xlsx) files are accepted")]
public string AttachmentTrace { get; set; }
}
我的正则表达式没有任何问题,但我总是得到ModelState.IsValid false。这似乎是非常简单和简单的正则表达式,我错过了什么?我是否需要编写自己的自定义验证?
我通过类型文件的常规输入填充AttachmentTrace:
<div class="editor-label">
@Html.LabelFor(model => model.AttachmentTrace)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.AttachmentTrace, new { type = "file" })
@Html.ValidationMessageFor(model => model.AttachmentTrace)
</div>
动作方法只是一个常规动作:
public ActionResult Create(Certificate certificate, HttpPostedFileBase attachmentTrace, HttpPostedFileBase attachmentEmail)
{
if (ModelState.IsValid)
{
// code ...
}
return View(certificate);
}
答案 0 :(得分:1)
好的,这是我找到的解决方案。我相信还有其他解决方案。首先是一个小背景,因为我的应用程序使用EF代码优先迁移,在我的模型中指定 HttpPostedFileBase 属性类型,在添加迁移时会产生此错误:
在模型生成期间检测到一个或多个验证错误: System.Data.Entity.Edm.EdmEntityType :: EntityType 'HttpPostedFileBase'没有定义键。为此定义密钥 的EntityType。 \ tSystem.Data.Entity.Edm.EdmEntitySet:EntityType: EntitySet'HttpPostedFileBases'基于类型'HttpPostedFileBase' 没有定义键。
所以我真的不得不坚持使用AttachmentTrace属性的字符串类型。
解决方案是使用这样的ViewModel类:
public class CertificateViewModel {
// .. other properties
[Required]
[FileTypes("xls,xlsx")]
public HttpPostedFileBase AttachmentTrace { get; set; }
}
然后像这样创建一个FileTypesAttribute,我从this excellent post借用了这段代码。
public class FileTypesAttribute : ValidationAttribute {
private readonly List<string> _types;
public FileTypesAttribute(string types) {
_types = types.Split(',').ToList();
}
public override bool IsValid(object value) {
if (value == null) return true;
var postedFile = value as HttpPostedFileBase;
var fileExt = System.IO.Path.GetExtension(postedFile.FileName).Substring(1);
return _types.Contains(fileExt, StringComparer.OrdinalIgnoreCase);
}
public override string FormatErrorMessage(string name) {
return string.Format("Invalid file type. Only {0} are supported.", String.Join(", ", _types));
}
}
在控制器Action中,我需要进行更改以使用ViewModel,然后使用AutoMapper将其映射回我的实体(顺便说一句,它很棒):
public ActionResult Create(CertificateViewModel certificate, HttpPostedFileBase attachmentTrace, HttpPostedFileBase attachmentEmail) {
if (ModelState.IsValid) {
// Let's use AutoMapper to map the ViewModel back to our Certificate Entity
// We also need to create a converter for type HttpPostedFileBase -> string
Mapper.CreateMap<HttpPostedFileBase, string>().ConvertUsing(new HttpPostedFileBaseTypeConverter());
Mapper.CreateMap<CreateCertificateViewModel, Certificate>();
Certificate myCert = Mapper.Map<CreateCertificateViewModel, Certificate>(certificate);
// other code ...
}
return View(myCert);
}
对于AutoMapper,我为HttpPostedFileBase创建了我自己的TypeConverter,如下所示:
public class HttpPostedFileBaseTypeConverter : ITypeConverter<HttpPostedFileBase, string> {
public string Convert(ResolutionContext context) {
var fileBase = context.SourceValue as HttpPostedFileBase;
if (fileBase != null) {
return fileBase.FileName;
}
return null;
}
}
就是这样。希望这可以帮助那些可能遇到同样问题的人。