■ WCF 스트리밍 사용하기

----------------------------------------------------------------------------------------------------


TestSolution.zip


[TestServer 프로젝트]

 

FileData.cs

 

 

using System.IO;

using System.ServiceModel;

 

namespace TestServer

{

    /// <summary>

    /// 파일 데이터

    /// </summary>

    [MessageContract]

    public class FileData

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 파일 경로 - FilePath

 

        /// <summary>

        /// 파일 경로

        /// </summary>

        [MessageHeader]

        public string FilePath { get; set; }

 

        #endregion

        #region 파일 길이 - FileLength

 

        /// <summary>

        /// 파일 길이

        /// </summary>

        [MessageHeader]

        public long FileLength { get; set; }

 

        #endregion

        #region 소스 스트림 - SourceStream

 

        /// <summary>

        /// 소스 스트림

        /// </summary>

        [MessageBodyMember]

        public Stream SourceStream { get; set; }

 

        #endregion

    }

}

 

 

FileRequest.cs

 

 

using System.ServiceModel;

 

namespace TestServer

{

    /// <summary>

    /// 파일 요청

    /// </summary>

    [MessageContract]

    public class FileRequest

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 파일명 - FileName

 

        /// <summary>

        /// 파일명

        /// </summary>

        [MessageBodyMember]

        public string FileName { get; set; }

 

        #endregion

    }

}

 

 

IFileService.cs

 

 

using System.Collections.Generic;

using System.ServiceModel;

 

namespace TestServer

{

    /// <summary>

    /// 파일 서비스 인터페이스

    /// </summary>

    [ServiceContract]

    public interface IFileService

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

 

        #region 모든 파일명 리스트 구하기 - GetAllFileNameList()

 

        /// <summary>

        /// 모든 파일명 리스트 구하기

        /// </summary>

        /// <returns>모든 파일명 리스트</returns>

        [OperationContract]

        List<string> GetAllFileNameList();

 

        #endregion

        #region 업로드 하기 - Upload(fileData)

 

        /// <summary>

        /// 업로드 하기

        /// </summary>

        /// <param name="fileData">파일 데이터</param>

        [OperationContract]

        void Upload(FileData fileData);

 

        #endregion

        #region 다운로드 하기 - Download(fileRequest)

 

        /// <summary>

        /// 다운로드 하기

        /// </summary>

        /// <param name="fileRequest">파일 요청</param>

        /// <returns>파일 데이터</returns>

        [OperationContract]

        FileData Download(FileRequest fileRequest);

 

        #endregion

    }

}

 

 

FileService.cs

 

 

using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

using System.ServiceModel;

 

namespace TestServer

{

    /// <summary>

    /// 파일 서비스

    /// </summary>

    public class FileService : IFileService

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 모든 파일명 리스트 구하기 - GetAllFileNameList()

 

        /// <summary>

        /// 모든 파일명 리스트 구하기

        /// </summary>

        /// <returns>모든 파일명 리스트</returns>

        public List<string> GetAllFileNameList()

        {

            List<string> fileNameList = Directory.GetFiles("d:\\upload").Select(Path.GetFileName).ToList();

 

            return fileNameList;

        }

 

        #endregion

        #region 업로드 하기 - Upload(fileData)

 

        /// <summary>

        /// 업로드 하기

        /// </summary>

        /// <param name="fileData">파일 데이터</param>

        public void Upload(FileData fileData)

        {

            string sourceFilePath      = fileData.FilePath;

            string sourceFileName      = Path.GetFileName(sourceFilePath);

            string targetDirectoryPath = "d:\\upload";

            string targetFilePath      = Path.Combine(targetDirectoryPath, sourceFileName);

 

            if(!Directory.Exists(targetDirectoryPath))

            {

                Directory.CreateDirectory(targetDirectoryPath);

            }

 

            try

            {

                using(FileStream targetStream = File.Create(targetFilePath))

                {

                    using(Stream sourceStream = fileData.SourceStream)

                    {

                        sourceStream.CopyTo(targetStream);

                    }

                }

            }

            catch(IOException exception)

            {

                Console.WriteLine(exception.Message);

 

                if(File.Exists(targetFilePath))

                {

                    try

                    {

                        File.Delete(targetFilePath);

                    }

                    catch

                    {

                    }

                }

            }

        }

 

        #endregion

        #region 다운로드 하기 - Download(fileRequest)

 

        /// <summary>

        /// 다운로드 하기

        /// </summary>

        /// <param name="fileRequest">파일 요청</param>

        /// <returns>파일 데이터</returns>

        public FileData Download(FileRequest fileRequest)

        {

            string sourceFilePath = Path.Combine("d:\\upload", fileRequest.FileName);

 

            Stream sourceStream = null;

 

            try

            {

                sourceStream = File.Open(sourceFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);

            }

            catch(Exception)

            {

                return null;

            }

 

            OperationContext clientContext = OperationContext.Current;

 

            clientContext.OperationCompleted += delegate(object sender, EventArgs e)

            {

                if(sourceStream != null)

                {

                    sourceStream.Dispose();

                }

            };

 

            return new FileData

            {

                FilePath     = fileRequest.FileName,

                FileLength   = sourceStream.Length,

                SourceStream = sourceStream

            };

        }

 

        #endregion

    }

}

 

 

Program.cs

 

 

using System;

using System.ServiceModel;

 

namespace TestServer

{

    /// <summary>

    /// 프로그램

    /// </summary>

    class Program

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region 프로그램 시작하기 - Main()

 

        /// <summary>

        /// 프로그램 시작하기

        /// </summary>

        private static void Main()

        {

            using(ServiceHost serviceHost = new ServiceHost(typeof(FileService)))

            {

                serviceHost.Open();

 

                Console.WriteLine("서버가 시작되었습니다 : "DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

 

                Console.ReadKey(true);

            }

        }

 

        #endregion

    }

}

 

 

App.config

 

 

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

    <startup>

        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />

    </startup>

    <system.serviceModel>

        <behaviors>

            <serviceBehaviors>

                <behavior name="mexBehavior">

                    <serviceMetadata httpGetEnabled="true" />

                    <serviceDebug includeExceptionDetailInFaults="true" />

                </behavior>

            </serviceBehaviors>

        </behaviors>

        <bindings>

            <basicHttpBinding>

                <binding name="basicHttp"

                    sendTimeout="00:10:00"

                    receiveTimeout="00:10:00"

                    maxReceivedMessageSize="1262485504"

                    transferMode="Streamed" />

            </basicHttpBinding>

            <netTcpBinding>

                <binding name="netTcp"

                    sendTimeout="00:10:00"

                    receiveTimeout="00:10:00"

                    maxReceivedMessageSize="1262485504"

                    transferMode="Streamed" />

            </netTcpBinding>

        </bindings>

        <services>

            <service name="TestServer.FileService" behaviorConfiguration="mexBehavior">

                <endpoint

                    address="FileService"

                    binding="basicHttpBinding"

                    bindingConfiguration="basicHttp"

                    contract="TestServer.IFileService" />

                <endpoint

                    address="FileService"

                    binding="netTcpBinding"

                    bindingConfiguration="netTcp"

                    contract="TestServer.IFileService" />

                <host>

                    <baseAddresses>

                        <add baseAddress="http://localhost:8080" />

                        <add baseAddress="net.tcp://localhost:8090" />

                    </baseAddresses>

                </host>

            </service>

        </services>

    </system.serviceModel>

</configuration>

 

 

[TestClient 프로젝트]

 

ReportStream.cs

 

 

using System;

using System.IO;

 

namespace TestClient

{

    /// <summary>

    /// 리포트 스트림

    /// </summary>

    public class ReportStream : Stream

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// 기준 스트림

        /// </summary>

        private readonly Stream baseStream;

 

        /// <summary>

        /// 전체 크기

        /// </summary>

        private long totalCount;

 

        /// <summary>

        /// 리포트 콜백

        /// </summary>

        private readonly Action<long, long> reportCallback;

 

        /// <summary>

        /// 전체 읽기 카운트

        /// </summary>

        private long totalReadCount;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 읽기 가능 여부 - CanRead

 

        /// <summary>

        /// 읽기 가능 여부

        /// </summary>

        public override bool CanRead

        {

            get

            {

                return this.baseStream.CanRead;

            }

        }

 

        #endregion

        #region 위치 설정 가능 여부 - CanSeek

 

        /// <summary>

        /// 위치 설정 가능 여부

        /// </summary>

        public override bool CanSeek

        {

            get

            {

                throw new NotImplementedException();

            }

        }

 

        #endregion

        #region 쓰기 가능 여부 - CanWrite

 

        /// <summary>

        /// 쓰기 가능 여부

        /// </summary>

        public override bool CanWrite

        {

            get

            {

                throw new NotImplementedException();

            }

        }

 

        #endregion

        #region 길이 - Length

 

        /// <summary>

        /// 길이

        /// </summary>

        public override long Length

        {

            get

            {

                return this.baseStream.Length;

            }

        }

 

        #endregion

        #region 위치 - Position

 

        /// <summary>

        /// 위치

        /// </summary>

        public override long Position

        {

            get

            {

                throw new NotImplementedException();

            }

            set

            {

                throw new NotImplementedException();

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - ReportStream(baseStream, totalCount, reportCallback)

 

        /// <summary>

        /// 생성자

        /// </summary>

        /// <param name="baseStream">기준 스트림</param>

        /// <param name="totalCount">전체 카운트</param>

        /// <param name="reportCallback">리포트 콜백</param>

        public ReportStream(Stream baseStream, long totalCount, Action<long, long> reportCallback)

        {

            this.baseStream     = baseStream ?? throw new ArgumentNullException("baseStream");

            this.totalCount     = totalCount;

            this.reportCallback = reportCallback;

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 닫기 - Close()

 

        /// <summary>

        /// 닫기

        /// </summary>

        public override void Close()

        {

            base.Close();

 

            this.baseStream.Close();

        }

 

        #endregion

        #region 버퍼 비우기- Flush()

 

        /// <summary>

        /// 버퍼 비우기

        /// </summary>

        public override void Flush()

        {

            throw new NotImplementedException();

        }

 

        #endregion

        #region 위치 설정하기 - Seek(offset, seekOrigin)

 

        /// <summary>

        /// 위치 설정하기

        /// </summary>

        /// <param name="offset">오프셋</param>

        /// <param name="seekOrigin">위치 기준</param>

        /// <returns>위치</returns>

        public override long Seek(long offset, SeekOrigin seekOrigin)

        {

            throw new NotImplementedException();

        }

 

        #endregion

        #region 길이 설정하기 - SetLength(value)

 

        /// <summary>

        /// 길이 설정하기

        /// </summary>

        /// <param name="value"></param>

        public override void SetLength(long value)

        {

            throw new NotImplementedException();

        }

 

        #endregion

        #region 읽기 - Read(bufferArray, offset, count)

 

        /// <summary>

        /// 읽기

        /// </summary>

        /// <param name="bufferArray">버퍼 배열</param>

        /// <param name="offset">오프셋</param>

        /// <param name="count">카운트</param>

        /// <returns>실제 읽은 카운트</returns>

        public override int Read(byte[] bufferArray, int offset, int count)

        {

            int readCount = this.baseStream.Read(bufferArray, offset, count);

 

            this.totalReadCount += readCount;

 

            this.reportCallback?.Invoke(this.totalCount, this.totalReadCount);

 

            return readCount;

        }

 

        #endregion

        #region 쓰기 - Write(bufferArray, offset, count)

 

        /// <summary>

        /// 쓰기

        /// </summary>

        /// <param name="bufferArray">버퍼 배열</param>

        /// <param name="offset">오프셋</param>

        /// <param name="count">카운트</param>

        public override void Write(byte[] bufferArray, int offset, int count)

        {

            throw new NotImplementedException();

        }

 

        #endregion

    }

}

 

 

MainForm.cs

 

 

using System;

using System.IO;

using System.Windows.Forms;

 

using TestClient.FileService;

 

namespace TestClient

{

    /// <summary>

    /// 메인 폼

    /// </summary>

    public partial class MainForm : Form

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MainForm()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainForm()

        {

            InitializeComponent();

 

            this.uploadButton.Click   += uploadButton_Click;

            this.downloadButton.Click += downloadButton_Click;

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        //////////////////////////////////////////////////////////////////////////////// Event

 

        #region 업로드 버튼 클릭시 처리하기 - uploadButton_Click(sender, e)

 

        /// <summary>

        /// 업로드 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void uploadButton_Click(object sender, EventArgs e)

        {

            using(FileServiceClient client = new FileServiceClient("NetTcpBinding_IFileService"))

            {

                FileInfo sourceFileInfo = new FileInfo("c:\\sample.txt");

 

                using(FileStream sourceStream = File.OpenRead(sourceFileInfo.FullName))

                {

                    using(ReportStream reportStream = new ReportStream(sourceStream, sourceFileInfo.Length, ProgressChanged))

                    {

                        client.Upload(sourceFileInfo.Length, sourceFileInfo.FullName, reportStream);

                    }

                }

 

                this.progressLabel.Text = string.Empty;

            }

        }

 

        #endregion

        #region 다운로드 버튼 클릭시 처리하기 - downloadButton_Click(sender, e)

 

        /// <summary>

        /// 다운로드 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void downloadButton_Click(object sender, EventArgs e)

        {

            string targetDirectoryPath = "c:\\target";

 

            if(!Directory.Exists(targetDirectoryPath))

            {

                Directory.CreateDirectory(targetDirectoryPath);

            }

 

            using(FileServiceClient client = new FileServiceClient("NetTcpBinding_IFileService"))

            {

                string sourceFileName = "sample.txt";

                string filePath;

                Stream sourceStream;

 

                long fileLength = client.Download(sourceFileName, out filePath, out sourceStream);

 

                string targetFilePath = Path.Combine(targetDirectoryPath, sourceFileName);

 

                using(FileStream targetStream = File.Create(targetFilePath))

                {

                    using(ReportStream reportStream = new ReportStream(sourceStream, fileLength, ProgressChanged))

                    {

                        reportStream.CopyTo(targetStream);

                    }

                }

 

                this.progressLabel.Text = string.Empty;

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////// Function

 

        #region 진행 변경시 처리하기 - ProgressChanged(totalCount, totalReadCount)

 

        /// <summary>

        /// 진행 변경시 처리하기

        /// </summary>

        /// <param name="totalCount">전체 카운트</param>

        /// <param name="totalReadCount">전체 읽은 카운트</param>

        private void ProgressChanged(long totalCount, long totalReadCount)

        {

            long value = 100L * totalReadCount / totalCount;

 

            this.progressLabel.Text = string.Format("{0}%", value);

 

            this.progressLabel.Update();

        }

 

        #endregion

    }

}

 

 

App.config

 

 

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

    <startup>

        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />

    </startup>

    <system.serviceModel>

        <bindings>

            <basicHttpBinding>

                <binding name="BasicHttpBinding_IFileService"

                    receiveTimeout="00:10:00"

                    sendTimeout="00:10:00"

                    maxReceivedMessageSize="1262485504"

                    transferMode="Streamed" />

            </basicHttpBinding>

            <netTcpBinding>

                <binding name="NetTcpBinding_IFileService"

                    receiveTimeout="00:10:00"

                    sendTimeout="00:10:00"

                    maxReceivedMessageSize="1262485504"

                    transferMode="Streamed" />

            </netTcpBinding>

        </bindings>

        <client>

            <endpoint name="BasicHttpBinding_IFileService"

                address="http://localhost:8080/FileService"

                binding="basicHttpBinding"

                bindingConfiguration="BasicHttpBinding_IFileService"

                contract="FileService.IFileService" />

            <endpoint name="NetTcpBinding_IFileService"

                address="net.tcp://localhost:8090/FileService"

                binding="netTcpBinding"

                bindingConfiguration="NetTcpBinding_IFileService"

                contract="FileService.IFileService" />

        </client>

    </system.serviceModel>

</configuration>

 

----------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker

댓글을 달아 주세요