Click here to Skip to main content
15,887,214 members
Articles / General Programming / File
Tip/Trick

Transfer File Using WCF

Rate me:
Please Sign up or sign in to vote.
4.83/5 (14 votes)
8 Jan 2015CPOL2 min read 76K   3.9K   28   9
How to use WCF to stream large file size over TCP

Introduction

So you have a new task that ask to send some files to client once it become available from some application, the developer ask you to provide a web service so he can use it in his application, what the service do simply it take a file and push it the client server, the biggest problem you will face it in issues like this, is  sending a large file using HTTP

HTTP is not the best way considering it has not been built to this kind of work.  This Article trying solve this issue using WCF and TCP and streaming, in this artical will build the client and server at the end we will be able to send 75 MB file in less then 12 seconds. 

Using the code

Creating the receiver layer

The receiver will provide the sender with one simple method named ( Put) this method will take a FileTransferRequest object, as you can see in the code: 

C#
/// <summary>
/// Push File to the client
/// </summary>
/// <param name="fileToPush">file you want to Push</param>
/// <returns>a file transfer Response</returns>
public FileTransferResponse Put(FileTransferRequest fileToPush)
{
    FileTransferResponse fileTransferResponse = this.CheckFileTransferRequest(fileToPush);
    if(fileTransferResponse.ResponseStatus == "FileIsValed")
    {
        try
        {
            this.SaveFileStream(System.Configuration.ConfigurationManager.AppSettings["SavedLocation"].ToString() + "\\" + fileToPush.FileName, new MemoryStream(fileToPush.Content));
            return new FileTransferResponse
            {
                CreateAt = DateTime.Now,
                FileName = fileToPush.FileName,
                Message = "File was transfered",
                ResponseStatus = "Successful"
            };
        }
        catch (Exception ex)
        {
            return new FileTransferResponse
            {
                CreateAt = DateTime.Now,
                FileName = fileToPush.FileName,
                Message = ex.Message,
                ResponseStatus = "Error"
            };
        }
    }

    return fileTransferResponse;
}

The method ( Put ) will take a FileTransferRequest object and it will call the method SaveFileStream witch will talk the file content as byte and converted into stream then save it to given folder path , here's how the FileTransferRequest look like: 

C#
namespace FileTransferFramework.Client
{
    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.ServiceModel;

    [DataContract]
    /// <summary>
    /// Transfer Request Object
    /// </summary>
    public class FileTransferRequest
    {
        [DataMember]
        /// <summary>
        /// Gets or sets File Name
        /// </summary>
        public string FileName { get; set; }

        [DataMember]
        public byte[] Content { get; set; }
    }
}

Before I call the SaveStream method I'm just make a simple check that the content file is not null and the name is set:

C#
/// <summary>
/// Check From file Transfer Object is not null
/// and all properties is set
/// </summary>
/// <param name="fileToPush">file to check</param>
/// <returns>File Transfer Response</returns>
private FileTransferResponse CheckFileTransferRequest(FileTransferRequest fileToPush)
{
    if (fileToPush != null)
    {
        if (!string.IsNullOrEmpty(fileToPush.FileName))
        {
            if (fileToPush.Content !=null)
            {
                return new FileTransferResponse
                {
                    CreateAt = DateTime.Now,
                    FileName = fileToPush.FileName,
                    Message = string.Empty,
                    ResponseStatus = "FileIsValed"
                };
            }

            return new FileTransferResponse
            {
                CreateAt = DateTime.Now,
                FileName = "No Name",
                Message = " File Content is null",
                ResponseStatus = "Error"
            };
        }

        return new FileTransferResponse
        {
            CreateAt = DateTime.Now,
            FileName = "No Name",
            Message = " File Name Can't be Null",
            ResponseStatus = "Error"
        };
    }

    return new FileTransferResponse
    {
        CreateAt = DateTime.Now,
        FileName = "No Name",
        Message = " File Can't be Null",
        ResponseStatus = "Error"
    };
}

I return a FileTransferResponse to tell the Put method that file is valed, so it can start wrting:

C#
/// <summary>
/// Write the Stream in the hard drive
/// </summary>
/// <param name="filePath">path to write the file in</param>
/// <param name="stream">stream to write</param>
private void SaveFileStream(string filePath, Stream stream)
{
    try
    {
        if(File.Exists(filePath))
        {
            File.Delete(filePath);
        }

        var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write);
        stream.CopyTo(fileStream);
        fileStream.Dispose();
    }
    catch(Exception ex)
    {
        throw ex;
    }
}

Note's the FileTransfer is inherited from IFileTransfer, as you can see: 

C#
namespace FileTransferFramework.Client
{
    using System.IO;
    using System.ServiceModel;

    [ServiceContract]
    public interface IFileTransfer
    {
        [OperationContract]
        FileTransferResponse Put(FileTransferRequest fileToPush);
    }
}

Now let's Update the app.onfig file to accept large file 

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="SavedLocation" value="C:\Users\aghabban\Documents\Visual Studio 2013\Projects\FileTransferFramework\Client\FileTransferFramework.Client\bin\Debug\Data\"/>
  </appSettings>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="StreamServiceBehavior">
          <serviceMetadata httpGetEnabled="True" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
        <binding name="NewBinding0" transferMode="Streamed" transactionFlow="false"  transactionProtocol="OleTransactions"
              hostNameComparisonMode="StrongWildcard" listenBacklog="10"
              maxBufferPoolSize="79623599" maxBufferSize="4967295" maxConnections="10"
              maxReceivedMessageSize="78623599">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="79623599"
              maxBytesPerRead="4096" maxNameTableCharCount="79623599" />
          <reliableSession ordered="true"
              enabled="false" />
          <security mode="None">
            <transport clientCredentialType="None"/>
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
    <services>
      <service behaviorConfiguration="StreamServiceBehavior" name="FileTransferFramework.Client.FileTransfer">
        <endpoint address="net.tcp://localhost:3021/streamserver" binding="netTcpBinding"
          bindingConfiguration="NewBinding0" bindingName="" contract="FileTransferFramework.Client.IFileTransfer" />
        <endpoint address="mex" binding="mexHttpBinding"
          contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:5210/StreamService" />
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
</configuration>

Now the main method in Program class  will start the service

C#
static void Main(string[] args)
   {
       try
       {
           IntPtr hwnd;
           hwnd = GetConsoleWindow();
           ShowWindow(hwnd, SW_HIDE);

           using (var serviceHost = new ServiceHost(typeof(FileTransfer)))
           {
               serviceHost.Open();
               Console.WriteLine("Client Started..");
               Console.ReadKey();
           }
       }
       catch (Exception ex)
       {
           Console.WriteLine(ex.ToString());
           Console.ReadKey();
       }
   }

Now the receiver is ready to and wating for the sender, let's build the receiver. 

Building the sender 

First the sender will use the receiver wcf that we build, it locat in the code example at http://localhost:5201/StreamService so I will add it from the service references dialog, as the task ask me to do " is take what ever file you see in some folder and push it to the client ", so what I will do is using File watcher control in order to watch that folder and fire create file event when a new file created, 

C#
/// <summary>
/// main Program
/// </summary>
/// <param name="args">args of the file</param>
static void Main(string[] args)
{
    try
    {
        IntPtr hwnd;
        hwnd = GetConsoleWindow();
        ShowWindow(hwnd, SW_HIDE);

        FileSystemWatcher fileWatcher = new FileSystemWatcher(System.Configuration.ConfigurationManager.AppSettings["FolderToWatch"].ToString());
        fileWatcher.Created += FileWatcher_Created;
        fileWatcher.EnableRaisingEvents = true;
        Console.WriteLine("Watcher Started...");
    }
    catch (Exception ex)
    {
        Console.Write(ex.Message);
        new Logger().Create("Service not started", DateTime.Now, "Error", ex.Message);
    }

    Console.ReadKey();
}

In the FileWatcher_Created file I will take what ever file created and call the put method in the receiver service pass a FileTransferRequest as you can see:

C#
/// <summary>
/// File Watcher when Created
/// </summary>
/// <param name="sender">sender object</param>
/// <param name="e">e object</param>
private static void FileWatcher_Created(object sender, FileSystemEventArgs e)
{
    FileTransferResponse response = null;
    try
    {
        if (IsFileLocked(e.FullPath) == false)
        {
            DateTime startAt = DateTime.Now;
            FileTransferRequest createdFile = new FileTransferRequest()
            {
                FileName = e.Name,
                Content = File.ReadAllBytes(e.FullPath)
            };

            response = new FileTransferClient().Put(createdFile);

            if (response.ResponseStatus != "Successful")
            {
                MoveToFailedFolder(e);
            }
            else
            {
                if (File.Exists(e.FullPath))
                {
                    File.Delete(e.FullPath);
                }
            }

            Console.WriteLine(response.ResponseStatus + " at: " + DateTime.Now.Subtract(startAt).ToString());
            new Logger().Create(e.Name, DateTime.Now, response.ResponseStatus, response.Message);
        }
    }
    catch (System.ServiceModel.CommunicationException ex)
    {
        MoveToFailedFolder(e);
        Console.WriteLine(ex.Message);
        new Logger().Create(e.Name, DateTime.Now, "Error", ex.Message);
    }
    catch(Exception ex)
    {
        Console.WriteLine(ex.Message);
        if(response != null)
        {
            new Logger().Create(e.Name, DateTime.Now, response.ResponseStatus, response.Message);
        }
        else
        {
            new Logger().Create(e.Name, DateTime.Now, "Error", ex.Message);
        }
    }
}

Finally you need to steup the config file of the receiver  

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="DbConnection" value="Data Source=10.10.5.133;Initial Catalog=FileTransferFrwork;Integrated Security=True"/>
    <add key="FolderToWatch" value="C:\Users\aghabban\Documents\Visual Studio 2013\Projects\FileTransferFramework\Server\FileTrainsferFramework.Server\bin\Debug\Data\"/>
  </appSettings>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>     
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_IFileTransfer" transferMode="Streamed"                     
              transactionFlow="false"  transactionProtocol="OleTransactions"
              hostNameComparisonMode="StrongWildcard" listenBacklog="10"
              maxBufferPoolSize="79623599" maxBufferSize="4967295" maxConnections="10"
              maxReceivedMessageSize="79623599">
                  <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="555555555"
                      maxBytesPerRead="4096" maxNameTableCharCount="79623599" />
                  <reliableSession ordered="true" 
                      enabled="false" />
                  <security mode="None">
                    <message clientCredentialType="None"/>
                    <transport clientCredentialType="None"/>
                  </security>
                </binding>              
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://192.168.1.108:3021/streamserver" binding="netTcpBinding"
                bindingConfiguration="NetTcpBinding_IFileTransfer" contract="ClientFileTransferServiceReference.IFileTransfer"
                name="NetTcpBinding_IFileTransfer">               
            </endpoint>
        </client>      
    </system.serviceModel>
</configuration>

 

License

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


Written By
Software Developer
Saudi Arabia Saudi Arabia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionНе получилось запустить код Pin
Member 1563178415-May-22 1:03
Member 1563178415-May-22 1:03 
Questionusing mtom ? Pin
kiquenet.com19-Mar-19 19:57
professionalkiquenet.com19-Mar-19 19:57 
Questionsend files that are more than 10Kb Pin
Member 1116322310-Jan-17 22:48
Member 1116322310-Jan-17 22:48 
QuestionBound to web sites Pin
User 79238657-Sep-16 7:29
User 79238657-Sep-16 7:29 
QuestionCannot send really large file Pin
yachting1-Mar-16 16:18
yachting1-Mar-16 16:18 
QuestionHow to send file ? Pin
Member 116078426-Dec-15 21:51
Member 116078426-Dec-15 21:51 
Questiongood but one problem Pin
Member 1193706330-Aug-15 19:16
Member 1193706330-Aug-15 19:16 
GeneralMy vote of 4 Pin
Kissta KaMakabeni9-Jan-15 1:29
professionalKissta KaMakabeni9-Jan-15 1:29 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun8-Jan-15 19:00
Humayun Kabir Mamun8-Jan-15 19:00 

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.