첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

728x90
반응형

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>
728x90
반응형
Posted by 사용자 icodebroker
TAG , ,

댓글을 달아 주세요