In previous posts, I showed you how to get/post data to ASP.NET Web API service. However, until now, I only used JSON for communicating between server and client and what about for binary data? For example, uploading files to ASP.NET Web API? How should the controller work and which kind of HTTP request/HTTP format should the Android client send to server? In this blog post, I will show you a simple way to transfer binary data. In the demo, I have 2 components : web service and android client. Unlike the other post, for this one, unfortunately, I don’t have any sample web service (online over internet) for you to test. I don’t own any windows server (neither VPS nor dedicated server :() therefore I can’t host any web service allowing file uploading.

In the download section, at the end of post, you’ll find the source code of web service and Android client. To play the demo, you’ve to publish the service to your localhost and connect your client to it. If you don’t know how to publish a web service to your localhost, please follow instructions here .

Moreover, in this post, I will show you how a web service serves different kinds of client. I have already prepared 4 clients: Android client, console client, drag and drop web client and file browsing web client. The client and server will use HTTP request of mime multipart encoding type for transferring data. You will see this setting applied at all sample clients.

1. Web service

When you open the web service solution, you’ll see there are 3 projects.
– The “Upload File To ASPNET Web API” project is the web service itself and 2 web clients.
– The “Upload File To ASPNET Web API Client” is the console client.
– The “Upload File To ASPNET Web API Models” defines contract between server and client.

In this part, we’ll focus only on the web service to analyze how it works. Go to “Upload File To ASPNET Web API” project –> HDFilesController where the logic code of web service locates.

public Task<IQueryable<HDFile>> Post()
        var uploadFolderPath = HostingEnvironment.MapPath("~/App_Data/" + UploadFolder);
        //#region CleaningUpPreviousFiles.InDevelopmentOnly
        //DirectoryInfo directoryInfo = new DirectoryInfo(uploadFolderPath);
        //foreach (FileInfo fileInfo in directoryInfo.GetFiles())
        //  fileInfo.Delete();
        if (Request.Content.IsMimeMultipartContent())
            var streamProvider = new WithExtensionMultipartFormDataStreamProvider(uploadFolderPath);
            var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith<IQueryable<HDFile>>(t =>
                if (t.IsFaulted || t.IsCanceled)
                    throw new HttpResponseException(HttpStatusCode.InternalServerError);
                var fileInfo = streamProvider.FileData.Select(i =>
                    var info = new FileInfo(i.LocalFileName);
                    return new HDFile(info.Name, Request.RequestUri.AbsoluteUri + "?filename=" + info.Name, (info.Length / 1024).ToString());
                return fileInfo.AsQueryable();
            return task;
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted"));
    catch (Exception ex)
        throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest, ex.Message));

uploadFolderPath variable determines where the files should be temporarily uploaded into server. I upload directly to App_Data folder but you can set to other folder as you want. Just remember to give full control permission to IUSER so that IIS can write file to that folder.
After setting the folder, the content of request will be validated if it’s a mime-multipart type. If the request is not conformed, web service will reject with HttpStatusCode.NotAcceptable. If the request is correct, the binary data will be extracted from content and IIS stores files in specified location.
However we should always remember that we “never trust user input”. The file name given in HTTP request maybe not conformed (file name in Unix platform can be not accepted in Windows platform), so we have to change the original file name in the request to new file name which we can be sure that it won’t “hurt” our server. I choose the format of {GUID}.{FILE_EXTENSION}, you can choose another format as you like, maybe with time stamp. Just making a class inherits from MultipartFormDataStreamProvider and override the GetLocalFileName with your own logic. For example, my custom MultipartFormDataStreamProvider looks like following

public class WithExtensionMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
    public WithExtensionMultipartFormDataStreamProvider(string rootPath)
        : base(rootPath)
    public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
        string extension = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? Path.GetExtension(OSUtil.GetValidFileName(headers.ContentDisposition.FileName)) : "";
        return Guid.NewGuid().ToString() + extension;

After all files were successfully uploaded to server, the Post action reply the client with a list of object in JSON format. This list contains many JSON objects with file name (on server), size and URL. Return URL back to client allowing user the possibility to get file back or share file with other user.

I have already extended the web service so that the user can download files not only through the given URLs but also through a GET HTTP request with correct parameter. In the controller, I wrote a GET action receiving file name as parameter, search for file name in server if it exists and give file back.

public HttpResponseMessage Get(string fileName)
    HttpResponseMessage result = null;
    DirectoryInfo directoryInfo = new DirectoryInfo(HostingEnvironment.MapPath("~/App_Data/" + UploadFolder));
    FileInfo foundFileInfo = directoryInfo.GetFiles().Where(x => x.Name == fileName).FirstOrDefault();
    if (foundFileInfo != null)
        FileStream fs = new FileStream(foundFileInfo.FullName, FileMode.Open);
        result = new HttpResponseMessage(HttpStatusCode.OK);
        result.Content = new StreamContent(fs);
        result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        result.Content.Headers.ContentDisposition.FileName = foundFileInfo.Name;
        result = new HttpResponseMessage(HttpStatusCode.NotFound);
    return result;

That is all about our web service. One POST action for posting binary data from client to server and one GET action for give binary data back from server to client. That means we have 2 ways binary data communicating channel.

2. Clients

In this second part, we build up our clients. As I mentioned at the beginning, I will introduce 4 types of client to prove that we can use our web service for many client system. Important: Remember to start you web service when you connect the clients to it. :).

2.1 Android client

Before getting started, I recommend you to read this article first (if you didn’t) . I will use dependency injection in example, it’s nothing special. Just if you don’t know how DI works, it’s very difficult for you to understand how the code works later.

The second note is Android client can only access the web service at your real localhost. He can’t access the web service in Debug mode of Visual Studio (for example http://localhost:4260/…). So, you have to really publish the web service code to your localhost. If you don’t know how to publish the web service, you can read the instructions at the link I post at the beginning.

In Android client, there are only 2 activities: the main activity and the result activity. The main activity is a list activity where I will show all files under “sdcard/wallpapers” folder. When the Android client starts, I will list all files in folder, pop them up the main activity so that user can choose which file they would like to upload to server.

public List<HDFile> getLocalFiles() {
    List<HDFile> result = new ArrayList<HDFile>();
    String sdCard = Environment.getExternalStorageDirectory().getAbsolutePath();
    String wallpaperPath = sdCard + "/wallpapers/";
    File files[] = new File(wallpaperPath).listFiles();
    for(int index=0;index < files.length;index++)
        HDFile wallpaper = new HDFile();
    return result;

The code listing above will get path of “sdcard”, find the folder “wallpapers” beneath it and then push all files into a list. HDFile is the contract object for communicating between server and client. CryptoUtil and IOUtil are just helper utilization class. You can check the code out from the repositories at the end of post.

After the local files were loaded successfully, I will display them on our main activity with check boxes so that we can tick which files we want to upload. However, as default, the list activity doesn’t provide us a layout with check box in front. Therefore, we need to define an adapter to customize the layout as following

public class ListViewLocalFileAdapter extends ArrayAdapter<HDFile> {
    private List<HDFile> hdFiles;
    private Context context;
    public ListViewLocalFileAdapter(Context context, int textViewResourceId, List<HDFile> objects) {
        super(context, textViewResourceId, objects);
        this.context = context;
        this.hdFiles = objects;
    static class ViewHolder
        protected CheckBox checkBox;
        protected TextView textViewName;
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = null;
        if (convertView == null)
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.list_file_item,null);
            final ViewHolder viewHolder = new ViewHolder();
            viewHolder.checkBox = (CheckBox)view.findViewById(;
            viewHolder.textViewName= (TextView)view.findViewById(;
            view = convertView;
        ViewHolder viewHolder=(ViewHolder)view.getTag();
        return view;
    private CompoundButton.OnCheckedChangeListener CheckBoxOnCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            CheckBox checkBox = (CheckBox)buttonView;
            HDFile hdFile = (HDFile) checkBox.getTag();
    public List<HDFile> getItems()
        return hdFiles;

And then when the app starts, the main activity will look like this

List With Checkbox activity

Remember that the sample files are loaded from “sdcard/wallpapers” folder, be sure that you have some sample files in that folder and of course, the folder “wallpapers” must also exist.

Android Debug Monitor File Explorer

To upload file to server, just choose some files and tap on the upload button on the action bar. That will make a HTTP POST to server and upload our files.

<?xml version="1.0" encoding="utf-8"?>
    <item android:id="@+id/main_menu_upload"
          android:showAsAction="ifRoom|withText" />
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater menuInflater = getMenuInflater();
    menuInflater.inflate(, menu);
    return true;
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
            List<HDFile> selectedFiles = new ArrayList<HDFile>();
            for(HDFile file:adapter.getItems())
                if (file.isSelected())
            if (selectedFiles.size()>0)
                AlertMessageBox.Show(getApplicationContext(),"Info","Please select a file to upload", AlertMessageBox.AlertMessageBoxIcon.Info);
            return true;
            return super.onOptionsItemSelected(item);
public void uploadFiles(List<HDFile> files) {
    new UploadFilesTask().execute(files.toArray(new HDFile[files.size()]));
class UploadFilesTask extends AsyncTask<HDFile,String,Integer>
    Integer totalCount = 0;
    protected Integer doInBackground(HDFile... params) {
        Integer uploadCount =0;
        totalCount = params.length;
        uploadedFiles = new ArrayList<HDFile>();
        for(int index=0;index < params.length;index++)
            File file = new File(params[index].getFilePath());
            JSONHttpClient jsonHttpClient = new JSONHttpClient();
            HDFile[] hdFiles = jsonHttpClient.PostFile(ServiceUrl.REST_SERVICE_URL, params[index].getId(),file,params[index].getName(),HDFile[].class);
            if (hdFiles != null && hdFiles.length == 1)
        return uploadCount;
    protected void onPostExecute(Integer uploadCount) {
        UploadErrorCode errorCode = UploadErrorCode.OK;
        if (uploadCount ==0)
            errorCode = UploadErrorCode.Failed;
        else if (uploadCount < totalCount)
            errorCode = UploadErrorCode.PartlySuccessful;
        if (uploadFilesCompleteListener != null)

The files will be uploaded one by one to server. You can extend my code for notifying upload progress changes. According to the count of uploaded files, we send appropriate error code back (failed, partly successful or OK). When upload progress finishes, the information of uploaded files will be shown on the result activity.

Uploaded files

The code for this activity is pretty simple, I think you can read and understand yourself.

2.2 .Net client

We have checked how the Android client works. In this part, I will show you how to consume our web service in a desktop application. The .net client is much more simple than Android client, there is no UI for it. 🙂 . I just make a simple console application, create a HTTP post with MultipartFormDataContent, push the content to it and send it to server.

private static async void UploadFiles()
    Uri server = new Uri("http://localhost:4260/api/hdfiles");
    HttpClient httpClient = new HttpClient();
    StringContent stringContent = new StringContent("Broken Sword: The Shadow of the Templars (also known as Circle of Blood in the United States)[1] is a 1996 point-and-click adventure game developed by Revolution Software. The player assumes the role of George Stobbart, an American tourist in Paris, as he attempts to unravel a conspiracy. The game takes place in both real and fictional locations in Europe and the Middle East.", Encoding.UTF8, "text/plain");
    StreamContent streamConent = new StreamContent(new FileStream(@"..\..\TestData\HintDesk.png", FileMode.Open, FileAccess.Read, FileShare.Read));
    MultipartFormDataContent multipartFormDataContent = new MultipartFormDataContent();
    multipartFormDataContent.Add(stringContent, "Broken Sword", "Broken Sword.txt");
    multipartFormDataContent.Add(streamConent, "HintDesk", "HintDesk.png");
    //HttpResponseMessage responseMessage = await httpClient.PostAsync(server, multipartFormDataContent);
    HttpResponseMessage responseMessage = httpClient.PostAsync(server, multipartFormDataContent).Result;
    if (responseMessage.IsSuccessStatusCode)
        IList<HDFile> hdFiles = await responseMessage.Content.ReadAsAsync<IList<HDFile>>();
        if (Directory.Exists(DownloadFolder))
            (new DirectoryInfo(DownloadFolder)).Empty();
        foreach (HDFile hdFile in hdFiles)
            responseMessage = httpClient.GetAsync(new Uri(hdFile.Url)).Result;
            if (responseMessage.IsSuccessStatusCode)
                using (FileStream fs = File.Create(Path.Combine(DownloadFolder, hdFile.Name)))
                    Stream streamFromService = await responseMessage.Content.ReadAsStreamAsync();

The HTTP request of code listing above contains 2 files “Broken Sword.txt”, and “HintDesk.png”. After posting files successfully, I will download them back again, just for testing if everything works. You see, the .net client is not much different from unit test but it’s good example to show how to consume the web service in desktop application.

2.3 Web client: Drag and Drop

In this part, we’ll discuss our 3rd client: the web client with drag and drop. We’ll use feature “drag and drop” of HTML5 to allow user to drag/drop file from his local computer to server.

Web client drag and drop

The source code of this client is in the same project of web service. Browse to Views –> DirectUpload –> Index.cshtml is where the layout of this client locates.

Drag And Drop HTML

In the Index.cshtml is the HTML code for building up the container where user can drop files and another container for showing the information of uploaded files. The javascript code for handling drag and drop is in the “~/bundles/draganddropscripts” defined in BundleConfig.cs

bundles.Add(new ScriptBundle("~/bundles/draganddropscripts")

In fileuploadbydraganddrop.js is where we will handle the drop event

function drop(evt) {
    var files = evt.originalEvent.dataTransfer.files;
    if (files.length > 0) {
        if (window.FormData !== undefined) {
            var data = new FormData();
            for (i = 0; i < files.length; i++) {
                data.append("file" + i, files[i]);
                type: "POST",
                url: root + "api/hdfiles",
                contentType: false,
                processData: false,
                data: data,
                success: function (res) {
                    $.each(res, function (i, item) {
        } else {
            alert("Your browser needs to support HTML5.");

After files are dropped to container, an ajax call will be sent to HDFilesController. When ajax call finishes, result will pushed back to viewModel. Then Knockout.js will bind data to result container.

2.4 Web client: Form

Our last client is also a web client. However, we use now the web client using form object. This web client works as same as web client with drag and drop. However I have to combine HTML and Javascript to display the uploading progress like following

<section class="content-wrapper main-content clear-fix">
    <div id="divFormUpload">
        <form id="formUpload" action="@Url.Content("~/api/hdfiles")" method="post" enctype="multipart/form-data">
            <label class="displayinline">Files</label>
            <input name="inputFiles" type="file" multiple />
            <input type="submit" value="Upload" />
            <div id="divProgress" style="display: none">
                <div id="divPercentBar" class="classDivPercentBar"></div>
                <div id="divPercentText" class="classDivPercentText">0%</div>
                @*<img alt="" id="upload-animation" src="/Content/images/loading.gif" />*@
    <ul data-bind="template: { name: 'fileContainer', foreach: uploads }"></ul>
    <script type="text/html" id="fileContainer">
            <span>Uploaded: <small data-bind="text: Name"></small>.</span>
            <span>Size: <small data-bind="text: Size"></small>kB</span>
            <span>Server path: <small><a data-bind="    attr: { href: Url }, text: Url"></a></small></span>


$(document).ready(function () {
    var divProgress = $("#divProgress");
    var divBar = $("#divPercentBar");
    var divPercent = $("#divPercentText");
        beforeSend: function () {
            var percentVal = '0%';
        uploadProgress: function (event, position, total, percentComplete) {
            var percentVal = percentComplete + '%';
        success: function (res) {
            var percentVal = '100%';
            $.each(res, function (i, item) {
        complete: function (xhr) {
var viewModel = {
    uploads: ko.observableArray([])

Web client form

The api controller URL isn’t set in javascript code but directly in HTML. The javascript is just for displaying the progress changes.

3. Conclusion

– Now we’re at the end of the post. We’ve already learnt how to transfer binary data between server and client. We already know how to consume the web service with many types of client.
– The source code of server and other client can be downloaded from following link:
– Android client can be downloaded from following link
– Util classes can be checked out from

4. Updates

4.1. Update 31.01.2014

The standard limitation for file size in IIS is about 4MB. If you want to allow uploading bigger file, you can add following setting in Web.config, for example, this config below allows file size up to 100MB.

<httpRuntime targetFramework="4.5" maxRequestLength="102400" />
        <requestLimits maxAllowedContentLength="104857600" />

Please note that maxRequestLength is measured in Kb and maxAllowedContentLength in bytes. Both values above equal to 100Mbytes.

4.2. Update 18.04.2014

In the demo Android client when a file is posted to web service its name part will be set by Id

HDFile[] hdFiles = jsonHttpClient.PostFile(ServiceUrl.REST_SERVICE_URL, params[index].getId(), file, params[index].getName(), HDFile[].class);

This name part you can read it again by accessing FileData.Headers.ContentDisposition.Parameters

Get Id from Post request