Click here to Skip to main content
12,452,721 members (50,401 online)
Click here to Skip to main content
Add your own
alternative version

Stats

55.4K views
148 downloads
41 bookmarked
Posted

File Upload using WCF REST API and JavaScript

, 28 Jul 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Uploading a file using WCF REST API and JavaScript

Introduction

Recently, I had the need to upload files. As the architecture that had been chosen implied creating the application client side with HTML/JavaScript consuming WCF services exposed with the REST API, I wanted to keep that orientation and drop every ASP.NET aspect of the application.

Background

I found some requests of information for this on the internet but none was answered in a satisfactory, code example, way. So, when I figured out the way to post a file this way, I also felt the need to share it.

Using the Code

First, we must create the service. As the upload function itself can only have a parameter of type Stream, I return a object with the upload path so I can refer to it after to the server. In my case, I must load a name, read a description, validate a hash but here I will keep it simple...

[DataContract]
public class UploadedFile
{
  [DataMember]
  public string FilePath { get; set; }

  [DataMember]
  public string FileLength { get; set;

  [DataMember]
  public string FileName { get; set; }

  //Other information. On upload only path and size are obvious.
  //...
}

The service contract consists of a method receiving a stream and returning an object with the path where the file was saved. For example purposes, I included another method where we will include a human readable file name.

[ServiceContract(Name = "IWCFUploader"]
public interface IWCFUploader
{
  [OperationContract(Name = "Upload")]
  [DataContractFormat]
  [WebInvoke(Method = "POST",
             UriTemplate = "Upload/",
             BodyStyle = WebMessageBodyStyle.Bare,
             ResponseFormat = WebMessageFormat.Json)]
  UploadedFile Upload(Stream Uploading);

  [OperationContract(Name = "Transform")]
  [DataContractFormat]
  [WebInvoke(Method = "POST",
             UriTemplate = "Transform",
             BodyStyle = WebMessageBodyStyle.Bare,
             ResponseFormat = WebMessageFormat.Json)]
  UploadedFile Transform(UploadedFile Uploading, string FileName);
}

The service behavior is also very straightforward:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, 
                 InstanceContextMode = InstanceContextMode.PerCall, 
                 IgnoreExtensionDataObject = true, 
                 IncludeExceptionDetailInFaults = true)]
public class WCFUploader : IWCFUploader
{
  #region IWCFUploader Members

  public UploadedFile Upload(Stream Uploading)
  {
    UploadedFile upload = new UploadedFile 
    {
      FilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())
    };

    int length = 0;
    using (FileStream writer = new FileStream(upload.FilePath, FileMode.Create))
    {
      int readCount;
      var buffer = new byte[8192];
      while ((readCount = Uploading.Read(buffer, 0, buffer.Length)) != 0)
      {
        writer.Write(buffer, 0, readCount);
        length += readCount;
      }
    }

    upload.FileLength = length;

    return upload;
  }

  public UploadedFile Transform(UploadedFile Uploading, string FileName)
  {
    Uploading.FileName = FileName;
    return Uploading;
  }

  #endregion
}  

In the web.config, you must remember to set the buffer and the maximum received message to a value that allows you to stream your file and, of course, set transfer mode to streamed. webHttp is also necessary in your endpoint behavior. I had an issue where if I named my binding in the service, I would get strange errors so I named all my other bindings and left the binding used for streaming as default, and it worked. You may also have to configure IIS if you want to upload files over 4.5 megabytes, that is if you need it to host the application.

  <configuration>
  <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding maxBufferSize="2147483647"
                 maxBufferPoolSize="2147483647"
                 maxReceivedMessageSize="2147483647"
                 transferMode="Streamed"
                 sendTimeout="00:05:00">
          <readerQuotas  maxDepth="2147483647"
                         maxStringContentLength="2147483647"
                         maxArrayLength="2147483647"
                         maxBytesPerRead="2147483647"
                         maxNameTableCharCount="2147483647"/>
          <security mode="None" />
        </binding>
      </webHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="defaultEndpointBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="defaultServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name="WCFUpload.WCFUploader" behaviorConfiguration="defaultServiceBehavior">
        <endpoint address="" behaviorConfiguration="defaultEndpointBehavior"
          binding="webHttpBinding" contract="WCFUpload.IWCFUploader" />
      </service>
    </services>
  </system.serviceModel>
</configuration> 

The JavaScript code is painfully simple. I tried so much stuff that when I finally figured this out, I felt really stupid.

function upload() {
  var request = new XMLHttpRequest();
  request.open('POST', 'wcf/WCFUploader.svc/Upload/');
  request.send(filePicker.files[0]);
} 

The HTML is as plain as it gets:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Uploading using WCF REST API</title>
    <script type="text/javascript">

        function uploadBlobOrFile(blobOrFile) {
            var xhr = new XMLHttpRequest();
            xhr.open('POST', 'wcf/WCFUploader.svc/Upload/', true);

            xhr.setRequestHeader('Content-length', blobOrFile.size);

            xhr.onload = function (e) {
                progressBar.value = 0;
                progressBar.textContent = progressBar.value;
            };

            // Listen to the upload progress.
            var progressBar = document.querySelector('progress');
            xhr.upload.onprogress = function(e) {
                if (e.lengthComputable) {
                    progressBar.value = (e.loaded / e.total) * 100;
                    progressBar.textContent = progressBar.value; // Fallback.
                }
            };
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    alert(xhr.responseText);
                }
            };

            xhr.send(blobOrFile);
        }

    </script>
</head>
<body>
    <input id="filePicker" type="file" name="Package" accept="image/*"/>
    <br />
    <progress min="0" max="100" value="0">0% complete</progress>
    <br />
    <button title="upload" 
            onclick="if (filePicker.files[0]) uploadBlobOrFile(filePicker.files[0])">
        <span>Upload</span>
    </button>
</body>
</html> 

I included a progress bar and it worked fine on the latest Firefox, Chrome and Internet Explorer. Hope it helps you.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

lusgon
Portugal Portugal
No Biography provided

You may also be interested in...

Pro
Pro

Comments and Discussions

 
QuestionFile Getting Corrupted while transmission Pin
Member 1207573021-Oct-15 0:35
memberMember 1207573021-Oct-15 0:35 
AnswerRe: File Getting Corrupted while transmission Pin
lusgon21-Oct-15 3:46
memberlusgon21-Oct-15 3:46 
QuestionNot working in Firefox and Chrome. Only works in IE. Pin
Praveen Raghuvanshi16-Jun-15 18:32
professionalPraveen Raghuvanshi16-Jun-15 18:32 
Questionservice on different server Pin
Member 237103018-May-15 22:27
memberMember 237103018-May-15 22:27 
GeneralGreats Article Pin
pioneer.amarpal8-Aug-14 3:28
professionalpioneer.amarpal8-Aug-14 3:28 
QuestionGreat tip! thanks for it! Pin
neaflo6-Aug-14 5:57
memberneaflo6-Aug-14 5:57 
AnswerRe: Great tip! thanks for it! Pin
lusgon6-Aug-14 10:11
memberlusgon6-Aug-14 10:11 
QuestionRequest for source code Pin
Bridewin27-Jul-14 7:00
memberBridewin27-Jul-14 7:00 
AnswerRe: Request for source code Pin
lusgon28-Jul-14 8:12
memberlusgon28-Jul-14 8:12 
QuestionTransform -> Upload Pin
Bridewin23-Jul-14 0:10
memberBridewin23-Jul-14 0:10 
AnswerRe: Transform -> Upload Pin
TwoWheelRider15-Jan-16 9:17
memberTwoWheelRider15-Jan-16 9:17 
GeneralMy vote of 2 Pin
gappani17-Jul-14 20:20
membergappani17-Jul-14 20:20 
QuestionError 'fileStream.ReadTimeout' threw an exception of type 'System.InvalidOperationException'? Pin
gappani17-Jul-14 8:49
membergappani17-Jul-14 8:49 
AnswerRe: Error 'fileStream.ReadTimeout' threw an exception of type 'System.InvalidOperationException'? Pin
lusgon17-Jul-14 10:48
memberlusgon17-Jul-14 10:48 
GeneralRe: Error 'fileStream.ReadTimeout' threw an exception of type 'System.InvalidOperationException'? Pin
gappani17-Jul-14 11:39
membergappani17-Jul-14 11:39 
GeneralRe: Error 'fileStream.ReadTimeout' threw an exception of type 'System.InvalidOperationException'? Pin
gappani17-Jul-14 20:40
membergappani17-Jul-14 20:40 
GeneralRe: Error 'fileStream.ReadTimeout' threw an exception of type 'System.InvalidOperationException'? Pin
lusgon18-Jul-14 4:00
memberlusgon18-Jul-14 4:00 
GeneralRe: Error 'fileStream.ReadTimeout' threw an exception of type 'System.InvalidOperationException'? Pin
gappani18-Jul-14 9:59
membergappani18-Jul-14 9:59 
QuestionGreat Post, Thanks. Pin
E-kul14-May-14 9:40
memberE-kul14-May-14 9:40 
AnswerRe: Great Post, Thanks. Pin
lusgon15-May-14 3:39
memberlusgon15-May-14 3:39 
GeneralRe: Great Post, Thanks. Pin
E-kul15-May-14 11:17
memberE-kul15-May-14 11:17 
QuestionGreat article Pin
Thandermax14-Apr-14 9:37
memberThandermax14-Apr-14 9:37 
QuestionMaximum file size? Pin
Ravi Lodhiya11-Apr-14 1:11
memberRavi Lodhiya11-Apr-14 1:11 
AnswerRe: Maximum file size? Pin
lusgon11-Apr-14 5:12
memberlusgon11-Apr-14 5:12 
AnswerRe: Maximum file size? Pin
lusgon11-Apr-14 6:21
memberlusgon11-Apr-14 6:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.160826.1 | Last Updated 28 Jul 2014
Article Copyright 2014 by lusgon
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid