views:

280

answers:

2

ASP.NET MVC seems to correctly automatically bind between HTML form's file input field and HttpPostedFileBase. On the other hand it cannot bind from file input field to byte array..I tried and it issues exception - something about not being able to convert to Base64. I had only the byte array property on my Model classes previously because later on I need it to perform serialization of the object into XML file.

Now I've come up with this workaround and it works fine but I am not sure if this will be ok:

  [DataContract]
     public class Section : BaseContentObject
     {

       ...
      [DataMember]
      public byte[] ImageBytes;

      private HttpPostedFileBase _imageFile;
      public HttpPostedFileBase ImageFile
      {
       get { return _imageFile; }
       set
       {
        _imageFile = value;
        if (value.ContentLength > 0)
        {
         byte[] buffer = new byte[value.ContentLength];
         value.InputStream.Read(buffer, 0, value.ContentLength);
         ImageBytes = buffer;
         ImageType = value.ContentType;
        }
       }
      }

      [DataMember]
      public string ImageType { get; set; }
     }
A: 

I think you are letting your Model connect to closely with your Controller. The usual way to do this is:

public ActionResult AcceptFile(HttpPostedFileBase submittedFile) {
  var bytes = submittedFile.FileContents;
  var model = new DatabaseThing { data = bytes };
  model.SaveToDatabase();
}

In this case, there is no need for your Model to be aware of HttpPostedFileBase, which is strictly an ASP.NET concept.

If you need complex binding beyond what the DefaultModelBinder supplies (which is alot), the usual way is to register specialized ModelBinders in Global.asax and then accept your own Model classes as Action Method arguments, like so:

In Global.asax:

ModelBinders.Binders.Add(typeof(MyThing), new ThingModelBinder()); 

This ModelBinder could then, for example, find any file that was posted with the form and bind the contents of that file to the Data property of your Thing.

And in your Controller:

public ActionResult AcceptThing(MyThing thing) {
  thing.Data.SaveToDatabase();
}

In this Action Method, your ThingModelBinder would have handled all binding, making it transparent to both the Controller and the Model.

Modifying your actual Model classes to be aware of, and function with, ASP.NET would not be necessary in this case. Your Model classes are, after all, supposed to represent your actual data.

bzlm
You are partially right but I'm working on my actions to try and get rid of FormCollection and HttpPostedFileBase, replacing them with strong typed Model classes.
mare
@mare I think you might find better ways to do that. I've updated my answer.
bzlm
A: 

Apparently there are huge changes (just found it out) in MVC Futures 2, especially regarding Model Binders.

For instance, the problem with my input file binding to byte array, there is a binder now:

• BinaryDataModelBinderProvider – Handles binding base-64 encoded input to byte[] and System.Linq.Data.Binary models.

mare