Is there a unit-testable way to upload files to ASP.NET WebAPI?
asp.net-web-api, c#, file-upload, tdd
Solution
The answer is "no". ASP.NET is an inheritance-based framework. If you're trying to write composition-based applications, you will, at some point, find friction and road-blocks. Time to switch to something like Nancy.
Problem
I'm working in a project that uses the new ASP.NET WebAPI. My current task is to accept an uploaded file. So far, I have used TDD to drive out the WebAPI code, but I've hit a wall with uploading. I'm currently following the advice found at http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2, but there seems to be no way at all to drive this out of a unit test. In order to get at the file and form data, I have to use `MultipartFormDataStreamProvider`, which is impossible to mock and/or override. Short of forsaking my TDD approach, what can I do? Here's the code from the example: ``` public Task<HttpResponseMessage> PostFormData() { // Check if the request contains multipart/form-data. if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } string root = HttpContext.Current.Server.MapPath("~/App_Data"); var provider = new MultipartFormDataStreamProvider(root); // Read the form data and return an async task. var task = Request.Content.ReadAsMultipartAsync(provider). ContinueWith<HttpResponseMessage>(t => { if (t.IsFaulted || t.IsCanceled) { Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception); } // This illustrates how to get the file names. foreach (MultipartFileData file in provider.FileData) { Trace.WriteLine(file.Headers.ContentDisposition.FileName); Trace.WriteLine("Server file path: " + file.LocalFileName); } return Request.CreateResponse(HttpStatusCode.OK); }); return task; } ``` The first problem is this line: ``` var provider = new MultipartFormDataStreamProvider(root); ``` For starters, to unit test this code, I need to be able to inject such a provider. It does WAY too much in that simple constructor call to be "newing it up" in line. There's got to be another way. (If not, WebAPI fails)