I’ve been building an application with the MVC beta, and came to implement a form that included a file upload form control. Accessing uploaded file data is quite simple via…
HttpContext.Current.Request.Files["controlName"]
However, in this case I want to unit-test the action method on the controller, and any direct reference to a dependency will make unit-testing difficult. I can use Dependency Injection, but I don’t particularly want to provide a mocked version of the HttpContext.
This is a scenario where custom Model Binders can be applied. Define the following class that implements the IModelBinder interface.
1: public class HttpPostedFileModelBinder : IModelBinder
2: {
3: public ModelBinderResult BindModel(ModelBindingContext bindingContext)
4: {
5: HttpPostedFileBase file = bindingContext.HttpContext.Request.Files[bindingContext.ModelName];
6: byte[] fileData = new byte[file.InputStream.Length];
7: file.InputStream.Read(fileData, 0, Convert.ToInt32(file.InputStream.Length));
8:
9: return new ModelBinderResult(fileData);
10: }
11: }
Then in global.asax, hook up the custom binder to work with parameters of type byte[]…
ModelBinders.Binders[typeof(byte[])] = new HttpPostedFileModelBinder();
You can now define a named parameter on your action method of type byte[], where the name matches the name on your <input type=”file”> element, and the binary data from the uploaded file will be passed into the action method.
1: [ActionName("Index"), AcceptVerbs(HttpVerbs.Post)]
2: public ActionResult FormSubmit(byte[] photo)
3: {
4: // do something with the posted image
5: }
Unit testing the action method is now simply a case of passing a byte array, and the run-time version will pull the appropriate information from the HttpContext and pass into the action method.