Click here to Skip to main content
15,867,141 members
Articles / Web Development / HTML

Uploading/Downloading a File Using WCF REST Service in .NET 3.5

Rate me:
Please Sign up or sign in to vote.
4.77/5 (18 votes)
31 Jul 2020CPOL2 min read 110.8K   2.1K   19   32
How to upload/download a file using WCF REST service in .NET 3.5
Converting a normal WCF service to being RESTful might be an easy task, but when it comes to streaming files over a REST call using WCF, it might get a little tricky. This post discusses this issue.

Last week, I blogged about how to create a RESTful service using WCF and how it was to actually not learn anything in order to make your existing WCF service RESTful.

Converting a normal WCF service to being RESTful might be an easy task, but when it comes to streaming files over a REST call using WCF, it might get a little tricky.

Here, we are going to cover just that part of our service. This article is in continuation of the last one. So, I would advice you to go through it to get some context.

So, to start of with the implementation, we’ll write the service contract code first as shown below:

C#
[ServiceContract]
   public interface IFileUploadServ
   {
       [OperationContract]
       [WebGet(UriTemplate = "File/{fileName}/{fileExtension}")]
       Stream DownloadFile(string fileName, string fileExtension);

       [OperationContract]
       [WebInvoke(Method = "POST", UriTemplate = "/UploadFile?fileName={fileName}")]
       void UploadFile(string fileName, Stream stream);
   }
C#
public class FileUploadServ : IFileUploadServ
{
    public Stream DownloadFile(string fileName, string fileExtension)
    {
        string downloadFilePath = 
        Path.Combine(HostingEnvironment.MapPath
        ("~/FileServer/Extracts"), fileName + "." + fileExtension);

        //Write logic to create the file
        File.Create(downloadFilePath);

        String headerInfo = "attachment; filename=" + fileName + "." + fileExtension;
        WebOperationContext.Current.OutgoingResponse.Headers
                              ["Content-Disposition"] = headerInfo;

        WebOperationContext.Current.OutgoingResponse.ContentType = "application/octet-stream";

        return File.OpenRead(downloadFilePath);
    }

    public void UploadFile(string fileName, Stream stream)
    {
        string FilePath = Path.Combine
               (HostingEnvironment.MapPath("~/FileServer/Uploads"), fileName);

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

A few things to note from the above piece of code are as follows:

  1. For file download scenarios, we are using the WebGet attribute, indicating that it is indeed a get Call for a file on the server.
  2. Also, in file download, we need to add some header info like Content-disposition and Content-Type to the outgoing response in order for the consuming client to understand the file.
  3. For File upload scenarios, we are using WebInvoke with POST method.
  4. We need to make sure that the location in which we are writing the file to (“FileServer/Uploads”), is write enabled for the IIS app pool process.

Apart from the above piece of code, the web.config entries need to be as below (we need to specify reader quotas and message sizes in order to allow for larger files to stream over):

XML
<system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="MyWcfRestService.WebHttp" 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>
    <services>
        <service behaviorConfiguration="MyWcfRestService.FileUploadServBehavior" 
           name="MyWcfRestService.FileUploadServ">
        <endpoint address="" 
        behaviorConfiguration="web" binding="webHttpBinding" 
           bindingConfiguration="MyWcfRestService.WebHttp" 
           contract="MyWcfRestService.IFileUploadServ">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" 
        contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="MyWcfRestService.FileUploadServBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

Now, there is one small problem (gotcha), when we try to write the same code in .NET 3.5.

The problem happens when we try to debug our WCF code (i.e., press F5) and open up the FileUploadServ.svc URL in our browser. We are greeted with the below page:

Image 1

The error on the page says:

For request in operation UploadFile to be a stream, the operation must have a single parameter whose type is Stream.

The above message occurs only when we create the service in .NET 3.5. For .NET 4.0, it's not a problem.

The good news is that it's just a Red-herring and could be thought of as false warning. This I say because if we hit our service from a consuming client, it would run just fine. It's just that when we activate our service, it does not work.

The bottom line is that we can easily ignore this error.

Now, onto writing the JavaScript code to consume the service. It's pretty straightforward if you ask me.

HTML
<div>
           <input type="file" id="fileUpload" value="" />
           <br />
           <br />
           <button id="btnUpload" onclick="UploadFile()">
               Upload</button>
       </div>
       <button id="btnDownload" onclick="DownloadFile()">
           Download</button>
JavaScript
function UploadFile() {
            // grab your file object from a file input

            fileData = document.getElementById("fileUpload").files[0];
            var data = new FormData();

            $.ajax({
                url: 'http://localhost:15849/FileUploadServ.svc/UploadFile?fileName=' + 
                      fileData.name,
                type: 'POST',
                data: fileData,
                cache: false,
                dataType: 'json',
                processData: false, // Don't process the files
                contentType: "application/octet-stream", // Set content type to false as jQuery 
                                                         // will tell the server 
                                                         // its a query string request
                success: function (data) {
                    alert('successful..');
                },
                error: function (data) {
                    alert('Some error Occurred!');
                }
            });
        }

        function DownloadFile() {

            window.location("http://localhost:15849/FileUploadServ.svc/File/Custom/xls");
        }

That’s it! You’re done. We have successfully implemented a WCF RESTful File Upload/Download service in .NET 3.5 (and higher).

Also, I’ve attached the complete project demonstrating WCF RESTful service here.

Please do provide your valuable feedback in the comments below and let me know if you face any issues while implementing the service.

License

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


Written By
Software Developer
United States United States
I am a Developer working across multiple Technologies like .NET, Scala, Angular and NodeJS.
Passionate about WEB technologies more than anything.
Fascinated about the idea of how the WEB world and the WinForm world are slowly merging into each other, with a very thin line to differentiate them.

I am an active blogger and I blog mostly about Technology. Also, I have presented at certain points in the past on technical topics.

My Blog


Life & Tech

Programming Community Profiles


Stack Overflow
GitHub

Presentations


Slideshare

Social Profiles


Facebook | Twitter | LinkedIn | Google+

Comments and Discussions

 
QuestionMethod not allowed Pin
Member 147638674-Mar-20 23:06
Member 147638674-Mar-20 23:06 
Questionwcfrest Pin
Member 1334807712-Aug-17 20:08
Member 1334807712-Aug-17 20:08 
Buggetting same error with service as web type Pin
Member 1150897329-Aug-16 20:21
Member 1150897329-Aug-16 20:21 
GeneralRe: getting same error with service as web type Pin
Davide Natali31-Aug-16 2:38
Davide Natali31-Aug-16 2:38 
QuestionThank you Pin
Roberto_Aguirre15-Aug-16 13:52
Roberto_Aguirre15-Aug-16 13:52 
AnswerRe: Thank you Pin
Davide Natali31-Aug-16 2:42
Davide Natali31-Aug-16 2:42 
GeneralRe: Thank you Pin
Roberto_Aguirre31-Aug-16 5:48
Roberto_Aguirre31-Aug-16 5:48 
GeneralRe: Thank you Pin
Chinmoy Mohanty13-Oct-16 20:32
Chinmoy Mohanty13-Oct-16 20:32 
QuestionTwo basic questions Pin
Bhanu Chhabra2-Jul-16 6:31
Bhanu Chhabra2-Jul-16 6:31 
QuestionHow can I test as i am getting this same error. Pin
amolvp17-Jun-16 23:34
amolvp17-Jun-16 23:34 
QuestionAdding Headers for downloadFile method Pin
finny.net17-Nov-15 23:55
finny.net17-Nov-15 23:55 
QuestionStream is empty Pin
Member 82329403-May-15 13:21
Member 82329403-May-15 13:21 
AnswerRe: Stream is empty Pin
angelfx17-Aug-15 21:12
angelfx17-Aug-15 21:12 
GeneralMy vote of 1 Pin
Hanno Coetzer2-Mar-15 0:27
Hanno Coetzer2-Mar-15 0:27 
GeneralRe: My vote of 1 Pin
Chinmoy Mohanty2-Mar-15 0:47
Chinmoy Mohanty2-Mar-15 0:47 
GeneralRe: My vote of 1 Pin
Hanno Coetzer2-Mar-15 1:43
Hanno Coetzer2-Mar-15 1:43 
GeneralRe: My vote of 1 Pin
Chinmoy Mohanty2-Mar-15 3:31
Chinmoy Mohanty2-Mar-15 3:31 
QuestionReally!? Pin
Mauro Sampietro3-Feb-15 5:03
Mauro Sampietro3-Feb-15 5:03 
AnswerRe: Really!? Pin
Chinmoy Mohanty2-Mar-15 0:47
Chinmoy Mohanty2-Mar-15 0:47 
GeneralRe: Really!? Pin
Mauro Sampietro16-Mar-15 5:13
Mauro Sampietro16-Mar-15 5:13 
QuestionHow to consume both service in C# code? Pin
skskvermask_imp2-Feb-15 5:21
skskvermask_imp2-Feb-15 5:21 
AnswerRe: How to consume both service in C# code? Pin
Chinmoy Mohanty2-Mar-15 0:38
Chinmoy Mohanty2-Mar-15 0:38 
QuestionRe: How to consume both service in C# code? Pin
Alok1234567897-Feb-16 17:36
Alok1234567897-Feb-16 17:36 
QuestionIt gives same error for 4.0 too Pin
Just Kiran24-Nov-14 21:33
Just Kiran24-Nov-14 21:33 
AnswerRe: It gives same error for 4.0 too Pin
Chinmoy Mohanty2-Mar-15 0:38
Chinmoy Mohanty2-Mar-15 0:38 

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.