One thing I’ve learned today: Learning new technologies via samples results in Frankencode

I was asked to develop an internal tool that would manage the advertisements we would display in our application. My requirements were simple: I needed to provide the user the ability to view the list of existing ads, create an ad by uploading an image along with the ad metadata, update and ad or delete an ad. Since our customers would never see this application, I went on a limb and chose a technology I’d never tried and knew nothing about: .Net Web Api. I figured I’d adapt one of the many excellent examples I found on the web so that it would serve my purpose. How difficult could it be?

I wrote the service component first and left the ad management user interface till last and for that, I chose a simple product catalog sample application that used jQuery and Knockout.js, two more technologies I had no previous experience with. Again, I knew there were lots of code snippets available on the web for those libraries so, armed with a decent search engine and StackOverflow, how could I go wrong?

The product catalog sample provided me with code for a basic grid and a set of detail fields. The user would enter the row id in an edit field and click a button to fill the detail fields with the data for that particular ad. An Update and a Delete button at the bottom of the page would update or delete the selected ad. This wasn’t quite what I had in mind but it was a close approximation. I figured adding a delete button to the appropriate row in the grid and providing the ability to click a row to populate the detail fields would be simple to implement once I had the basic functionality working.

I looked for examples of image uploading and found several, all with their quirks and limitations. Figuring out which limitations I could live with and which I couldn’t took some time. I really wanted to be able to upload an image and its associated metadata (name, width and height) all in a single POST request but most of the samples either dealt with uploading just the file or uploading a whole slew of files…but no other data. I tried all sorts of file upload methods with various degrees of success before settling on one that used a strict HTML page with a form tag and a submit button. Have I mentioned I’d never dealt with uploading files over HTTP POST requests before?

Frankencode monster

Once I got the file upload working (though I’m now working on the functionality that will inform the user whether the upload succeeded), I stepped back and took a cold hard look at my application. What I saw was a Frankenstein-type application. The samples I combined were never meant to go together. I know I’m not validating my fields in an even remotely optimal manner. I’ve tried to hide the delete button for images that are still referenced by an ad and therefore can’t be deleted but haven’t figured it out yet. It should be a simple matter of making the delete button’s visibility conditional upon whether the image is referenced by an ad but my condition always evaluates to true so I still have to do a bit more work on the project.

Have I learned something? A resounding yes! I can now claim to know some jQuery, a bit of Knockout.JS and something of .Net Web APIs. However, I’m lacking a lot of the very basic knowledge that I would have gained if I’d picked up a book about any of these topics and read the first few chapters. I liken it to trying to learn C# by trying out async samples. You might eventually understand how the async functionality works but without an understanding of basic C# constructs, you won’t be able to extend those samples without creating a monster and without looking for yet another sample to base your next bit of code on.

But I have to admit it’s been a lot of fun! 😉

File Upload with ASP.Net Web API

I recently had the opportunity to create a new RESTful service for the project I was developing for my employer. As this service would be used internally, it was the perfect opportunity to try a technology that was new to me: ASP.NET Web API.

This new service would enable the caller to upload and download images. This is nothing particularly unique as there are many excellent examples on the web that demonstrate some flavor of this. All these solutions call System.Net.Http.MultipartFormDataStreamProvider to write the image file to disk. In my case, I wanted to store the image binary in a SQL Server table so I used the System.Net.Http.MultipartMemoryStreamProvider class to allow me to read the contents of the request and send the image stream to the method that wrote to the database.

As I was developing with Visual Studio 2010, I could not use the new await functionality.

public Task<IEnumerable<int>> Post()
{
  if (!Request.Content.IsMimeMultipartContent())
  {
    throw new HttpResponseException(Request.CreateResponse(
	HttpStatusCode.NotAcceptable, 
	"This request is not properly formatted"));
  }

  try
  {
    var streamProvider = new MultipartMemoryStreamProvider();
    var task = Request.Content.ReadAsMultipartAsync(streamProvider)
	      .ContinueWith<IEnumerable<int>>(t =>
    {
      if (t.IsFaulted || t.IsCanceled)
      {
        throw new HttpResponseException(HttpStatusCode.InternalServerError);
      }

      var addedId = streamProvider.Contents.Select(i =>
      {
        Stream stream = i.ReadAsStreamAsync().Result;                      

        // Insert your own code to deal with the Stream.  
        // In my case, I called my code that wrote the image to 
        // database and returned the image's id in imageId such as below.
        int imageId = DatabaseCode(stream);
        return imageId;
      });
      return addedId;
    });
    return task;
  }
  catch (Exception ex)
  {
    throw new HttpResponseException(Request.CreateResponse(
	HttpStatusCode.NotAcceptable, 
	"Error: " + ex.Message));
  }
}

This is a minor tweak to the code from the samples linked above but I thought this might be of use to the next person, or even my future self, who attempts to store images elsewhere than directly to disk as I had to do.

If you found this post helpful or wish to constructively point out improvements, leave me a comment!

Happy coding!