How to set byte field [] correctly?

I need to check byte[] in my model as Required , but whenever I use Data Annotation [Required] it will do nothing. Even if I select a file, it gives an error message.

More details:

Model:

 Public class MyClass { [Key] public int ID {get; set;} [Required] public string Name {get; set;} public byte[] Image {get; set;} [Required] public byte[] Template {get; set;} } 

View:

 <div class="editor-label"> <%:Html.LabelFor(model => model.Image) %> </div> <div class="editor-field"> <input type="file" id="file1" name="files" /> </div> <div class="editor-label"> <%:Html.Label("Template") %> </div> <div class="editor-field"> <input type="file" id="file2" name="files"/> </div> <p> <input type="submit" value="Create" /> </p> 

I looked through the messages and noticed that people use special checking, but they used HttpPostedFileBase as file types instead of byte[] , like me, for some reason, when I try to use the same errors with an missing ID for it ... Despite that the model has its own identifier.

EDIT:

Context - OnModelCreating Add- OnModelCreating for Report

 modelBuilder.Entity<Report>().Property(p => p.Image).HasColumnType("image"); modelBuilder.Entity<Report>().Property(p => p.Template).HasColumnType("image"); 

Please note that I had to set image as ColumnType due to Byte array truncation to a length of 4000. error.

Controller:

 public ActionResult Create(Report report, IEnumerable<HttpPostedFileBase> files) { if (ModelState.IsValid) { db.Configuration.ValidateOnSaveEnabled = false; if (files.ElementAt(0) != null && files.ElementAt(0).ContentLength > 0) { using (MemoryStream ms = new MemoryStream()) { files.ElementAt(0).InputStream.CopyTo(ms); report.Image = ms.GetBuffer(); } } if (files.ElementAt(1) != null && files.ElementAt(1).ContentLength > 0) { using (MemoryStream ms1 = new MemoryStream()) { files.ElementAt(1).InputStream.CopyTo(ms1); report.Template = ms1.GetBuffer(); } } db.Reports.Add(report); db.SaveChanges(); //Temporary save method var tempID = 10000000 + report.ReportID; var fileName = tempID.ToString(); //current by-pass for name var path = Path.Combine(Server.MapPath("~/Content/Report/"), fileName); files.ElementAt(1).SaveAs(path); db.Configuration.ValidateOnSaveEnabled = true; return RedirectToAction("Index"); } 

I hope you notice what I am missing.

+4
source share
3 answers

I changed my Create method, and this is what I came up with. Seems to work well, but ...

 if (files.ElementAt(1) != null && files.ElementAt(1).ContentLength > 0) { using (MemoryStream ms1 = new MemoryStream()) { files.ElementAt(1).InputStream.CopyTo(ms1); report.Template = ms1.GetBuffer(); } } else // this part of code did the trick, although not sure how good it is in practice { return View(report); } 
0
source

RequiredAttribute checks for null and an empty string.

 public override bool IsValid(object value) { if (value == null) return false; string str = value as string; if (str != null && !this.AllowEmptyStrings) return str.Trim().Length != 0; else return true; } 

This works fine if your byte array is NULL, but you probably want to check for an empty array as well (not seeing how you assign the value of your Template property, I can only guess that it is). You can define your own required attribute that performs this check for you.

 public class RequiredCollectionAttribute : RequiredAttribute { public override bool IsValid(object value) { bool isValid = base.IsValid(value); if(isValid) { ICollection collection = value as ICollection; if(collection != null) { isValid = collection.Count != 0; } } return isValid; } } 

Now just replace the Required attribute in the Template property with our new RequiredCollection attribute.

 [RequiredCollection] public byte[] Template {get; set;} 
+4
source

I looked through the messages and noticed that people use special checking but they used HttpPostedFileBase as file types, not bytes [] like me ..

Do you want to link the published file in the byterray field in the model? If so, you should go for a custom bonding device.

ASP.NET MVC already has a built-in middleware for the byte array, so you can easily expand it as suggested in this post .

 public class CustomFileModelBinder : ByteArrayModelBinder {    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)    {        var file = controllerContext.HttpContext.Request.Files[bindingContext.ModelName];        if (file != null)        {            if (file.ContentLength != 0 && !String.IsNullOrEmpty(file.FileName))            {                var fileBytes = new byte[file.ContentLength];                file.InputStream.Read(fileBytes, 0, fileBytes.Length);                return fileBytes;            }            return null;        }        return base.BindModel(controllerContext, bindingContext);    } } protected void Application_Start() {    ...    ModelBinders.Binders.Remove(typeof(byte[]));    ModelBinders.Binders.Add(typeof(byte[]), new CustomFileModelBinder()); } 

Now the downloaded file will directly come and sit as a bytearray in the properties.

0
source

All Articles