Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to Conditionally Return a Binary File from a Web API App and Save it to Disk at the Client

0.00/5 (No votes)
19 Feb 2014 1  
Check for a newer version of a file and then return it if the client's version is outdated

What's New, ServerCat?!?

If you need a client app to check the Web API server to see if the server's version of a file is newer than the version the client has, you can set up the server to do so by performing these steps:

Add the appropriate method to a Repository Interface, such as:

HttpResponseMessage GetCervezaBeberUpdate(string clientVersion);

Add this to the corresponding Controller class (where the Controller name is "HenryFieldingController"):

[Route("api/HenryFielding/GetUpdatedCervezaBeber")]
public HttpResponseMessage GetUpdate(string clientVersion)
{
    return _tomJonesRepository.GetCervezaBeberUpdate(clientVersion);
}

Add the appropriate method to the concrete Repository class, such as:

public HttpResponseMessage GetCervezaBeberUpdate(string clientVersion)
{
    var binaryFilePath = HostingEnvironment.MapPath(@"~\App_Data\CervezaBeber.exe");
    FileVersionInfo currentVersion = FileVersionInfo.GetVersionInfo(binaryFilePath);
    if (!ServerFileIsNewer(clientVersion, currentVersion))
    {
        result = new HttpResponseMessage(HttpStatusCode.NoContent);
    }
    else
    {
        var stream = new FileStream(binaryFilePath, FileMode.Open);
        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
        result.Content = new StreamContent(stream);
        result.Content.Headers.ContentType =
            new MediaTypeHeaderValue("application/octet-stream");
    }
    return result;
}

Also add the method in that Repository class that GetCervezaBeberUpdate() calls:

private bool ServerFileIsNewer(string clientFileVersion, FileVersionInfo serverFile)
{
    Version client = new Version(clientFileVersion);
    Version server = new Version(string.Format("{0}.{1}.{2}.{3}", serverFile.FileMajorPart, serverFile.FileMinorPart, serverFile.FileBuildPart, serverFile.FilePrivatePart));
    return server > client;
}

Thanks to Servy, the method above is now as clean as an unblown whistle, as concise as Joe Friday's dream witness, and as elegant as Grace Kelley.

Whoa-oh-oh-oh-OH-oh!

Now the client can call this by passing a URI like this to the server:

http://<servername>:<portnumber>/api/
<controllername>?clientVersion=<clientversionquad>

Or, for a more literal example, in the event your server's name is "Platypus", the port to use is 4242, the Controller is named HenryFieldingController, and the version of the file the client currently has is 3.1.4.1:

http://Platypus:4242/api/HenryFielding?clientVersion=3.1.4.1

How About a Bonus?

As a free-as-in-beer (you/I wish!) premium, here's some code the client can use to save the server's response to a file (passing this a URI such as shown above):

private void DownloadTheFile(string uri)
{
    var outputFileName = "Platypus.exe";
    var webRequest = (HttpWebRequest)WebRequest.Create(uri);
    var webResponse = (HttpWebResponse)webRequest.GetResponse();
    string statusCode = webResponse.StatusCode.ToString();
    // From here on (including the CopyStream() method) derived from Jon Skeet's 
    // answer at http://stackoverflow.com/questions/411592/how-do-i-save-a-stream-to-a-file
    if (statusCode == "NoContent")
    {
        MessageBox.Show("You already have the newest available version.");
    }
    else
    {
        var responseStream = webResponse.GetResponseStream();
        using (Stream file = File.Create(outputFileName))
        {
            CopyStream(responseStream, file);
            MessageBox.Show(string.Format("New version downloaded to {0}", outputFileName));
        }
    }
}

public static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[8 * 1024];
    int len;
    while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, len);
    }
}

Oyez! Oyez!

If you like this tip and/or found it useful, you should either scale Mt. Rushmore and yell "How-dee!!!" like Minnie Pearl once you reach the summit, OR you should practice your falsetto until you can break a glass, a la Ella Fitzgerald. If you refuse to do either, you must simultaneously listen to Pearl Jam, "The Wreck of the Edmund Fitzgerald", and JFK's "Ask Not" speechifying.

OR!!! (I must be feeling magnanimous today) finish (no pun intended) this joke: "Sven the Finnish Carpenter was having lunch with Dane the Danish baker, when..."

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here