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

728x90
반응형

TestProject.zip
다운로드

▶ MIMEPart.cs

using System.IO;

namespace TestProject
{
    /// <summary>
    /// MIME 파트
    /// </summary>
    public abstract class MIMEPart
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 명칭 - Name

        /// <summary>
        /// 명칭
        /// </summary>
        public string Name { get; set; }

        #endregion
        #region 컨텐트 처리 - ContentDisposition

        /// <summary>
        /// 컨텐트 처리
        /// </summary>
        public abstract string ContentDisposition { get; }

        #endregion
        #region 컨텐트 타입 - ContentType

        /// <summary>
        /// 컨텐트 타입
        /// </summary>
        public abstract string ContentType { get; }

        #endregion
        #region 바운더리 - Boundary

        /// <summary>
        /// 바운더리
        /// </summary>
        public string Boundary { get; set; }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 복사하기 - CopyTo(stream)

        /// <summary>
        /// 복사하기
        /// </summary>
        /// <param name="stream">스트림</param>
        public abstract void CopyTo(Stream stream);

        #endregion
    }
}

 

▶ NameValuePart.cs

using System.Collections.Specialized;
using System.IO;
using System.Text;

namespace TestProject
{
    /// <summary>
    /// 명칭 값 파트
    /// </summary>
    public class NameValuePart : MIMEPart
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 명칭 값 컬렉션
        /// </summary>
        private NameValueCollection nameValueCollection;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 컨텐트 처리 - ContentDisposition

        /// <summary>
        /// 컨텐트 처리
        /// </summary>
        public override string ContentDisposition
        {
            get
            {
                return "form-data";
            }
        }

        #endregion
        #region 컨텐트 타입 - ContentType

        /// <summary>
        /// 컨텐트 타입
        /// </summary>
        public override string ContentType
        {
            get
            {
                return string.Empty;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - NameValuePart(nameValueCollection)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="nameValueCollection">명칭 값 컬렉션</param>
        public NameValuePart(NameValueCollection nameValueCollection)
        {
            this.nameValueCollection = nameValueCollection;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 복사하기 - CopyTo(stream)

        /// <summary>
        /// 복사하기
        /// </summary>
        /// <param name="stream">스트림</param>
        public override void CopyTo(Stream stream)
        {
            string boundary = Boundary;

            StringBuilder stringBuilder = new StringBuilder();

            foreach(object element in this.nameValueCollection.Keys)
            {
                stringBuilder.AppendFormat("--{0}", boundary);
                stringBuilder.Append("\r\n");
                stringBuilder.AppendFormat("Content-Disposition: form-data; name=\"{0}\";", element);
                stringBuilder.Append("\r\n");
                stringBuilder.Append("\r\n");
                stringBuilder.Append(this.nameValueCollection[element.ToString()]);
                stringBuilder.Append("\r\n");
            }

            stringBuilder.AppendFormat("--{0}", boundary);
            stringBuilder.Append("\r\n");

            byte[] byteArray = Encoding.ASCII.GetBytes(stringBuilder.ToString());

            stream.Write(byteArray, 0, byteArray.Length);
        }

        #endregion
    }
}

 

▶ FilePart.cs

using System.IO;
using System.Text;

namespace TestProject
{
    /// <summary>
    /// 파일 파트
    /// </summary>
    public class FilePart : MIMEPart
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 입력 스트림
        /// </summary>
        private Stream inputStream;

        /// <summary>
        /// 컨텐트 타입
        /// </summary>
        private string contentType;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 컨텐트 처리 - ContentDisposition

        /// <summary>
        /// 컨텐트 처리
        /// </summary>
        public override string ContentDisposition
        {
            get
            {
                return "file";
            }
        }

        #endregion
        #region 컨텐트 타입 - ContentType

        /// <summary>
        /// 컨텐트 타입
        /// </summary>
        public override string ContentType
        {
            get
            {
                return string.Format("content-type: {0}", this.contentType);
            }
        }

        #endregion
        #region 파일명 - FileName

        /// <summary>
        /// 파일명
        /// </summary>
        public string FileName { get; set; }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - FilePart(inputStream, name, contentType)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="inputStream">입력 스트림</param>
        /// <param name="name">명칭</param>
        /// <param name="contentType">컨텐트 타입</param>
        public FilePart(Stream inputStream, string name, string contentType)
        {
            this.inputStream = inputStream;

            Name = name;

            this.contentType = contentType;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 복사하기 - CopyTo(stream)

        /// <summary>
        /// 복사하기
        /// </summary>
        /// <param name="stream">스트림</param>
        public override void CopyTo(Stream stream)
        {
            StringBuilder stringBuilder = new StringBuilder();

            stringBuilder.AppendFormat("Content-Disposition: {0}", ContentDisposition);

            if(this.Name != null)
            {
                stringBuilder.Append("; ").AppendFormat("name=\"{0}\"", Name);
            }

            if(this.FileName != null)
            {
                stringBuilder.Append("; ").AppendFormat("filename=\"{0}\"", FileName);
            }

            stringBuilder.Append("\r\n");

            stringBuilder.AppendFormat(ContentType);
            stringBuilder.Append("\r\n");
            stringBuilder.Append("\r\n");

            byte[] byteArray = Encoding.ASCII.GetBytes(stringBuilder.ToString());

            stream.Write(byteArray, 0, byteArray.Length);
        
            byte[] readByteArray = new byte[1024];

            int readCount = inputStream.Read(readByteArray, 0, readByteArray.Length);

            while(readCount > 0)
            {
                stream.Write(readByteArray, 0, readCount);

                readCount = inputStream.Read(readByteArray, 0, readByteArray.Length);
            }

            stringBuilder.Length = 0;

            stringBuilder.Append("\r\n");
            stringBuilder.AppendFormat("--{0}", Boundary);
            stringBuilder.Append("\r\n");

            byteArray = Encoding.ASCII.GetBytes(stringBuilder.ToString());

            stream.Write(byteArray, 0, byteArray.Length);
        }

        #endregion
    }
}

 

▶ FileCollection.cs

using System.Collections.Generic;
using System.IO;
using System.Text;

namespace TestProject
{
    /// <summary>
    /// 파일 컬렉션
    /// </summary>
    public class FileCollection : MIMEPart
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 파일 파트 리스트
        /// </summary>
        private List<FilePart> filePartList;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 카운트 - Count

        /// <summary>
        /// 카운트
        /// </summary>
        public int Count
        {
            get
            {
                return this.filePartList.Count;
            }
        }

        #endregion
        #region 컨텐트 처리 - ContentDisposition

        /// <summary>
        /// 컨텐트 처리
        /// </summary>
        public override string ContentDisposition
        {
            get
            {
                return string.Format("form-data; name=\"{0}\"", Name);
            }
        }

        #endregion
        #region 컨텐트 타입 - ContentType

        /// <summary>
        /// 컨텐트 타입
        /// </summary>
        public override string ContentType
        {
            get
            {
                return string.Format("multipart/mixed; boundary={0}", Boundary);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - FileCollection()

        /// <summary>
        /// 생성자
        /// </summary>
        public FileCollection()
        {
            this.filePartList = new List<FilePart>();

            Boundary = MultiPartHelper.GetBoundary();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 추가하기 - Add(filePart)

        /// <summary>
        /// 추가하기
        /// </summary>
        /// <param name="filePart">파일 파트</param>
        public void Add(FilePart filePart)
        {
            this.filePartList.Add(filePart);
        }

        #endregion
        #region 복사하기 - CopyTo(stream)

        /// <summary>
        /// 복사하기
        /// </summary>
        /// <param name="stream">스트림</param>
        public override void CopyTo(Stream stream)
        {
            StringBuilder stringBuilder = new StringBuilder(128);

            stringBuilder.Append("Content-Disposition: ").Append(ContentDisposition).Append("\r\n");
            stringBuilder.Append("Content-Type: ").Append(ContentType).Append("\r\n");
            stringBuilder.Append("\r\n");
            stringBuilder.AppendFormat("--{0}", Boundary).Append("\r\n");

            byte[] headerByteArray = Encoding.ASCII.GetBytes(stringBuilder.ToString());

            stream.Write(headerByteArray, 0, headerByteArray.Length);

            foreach(FilePart filePart in filePartList)
            {
                filePart.Boundary = Boundary;

                filePart.CopyTo(stream);
            }
        }

        #endregion
    }
}

 

▶ MultiPartHelper.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;

namespace TestProject
{
    /// <summary>
    /// 멀티 파트 헬퍼
    /// </summary>
    public class MultiPartHelper
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 난수 발생기
        /// </summary>
        private static Random random = new Random(Environment.TickCount);

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 명칭 값 파트 리스트
        /// </summary>
        private List<NameValuePart> nameValuePartList = new List<NameValuePart>();

        /// <summary>
        /// 파일 컬렉션
        /// </summary>
        private FileCollection fileCollection = null;

        /// <summary>
        /// 메모리 스트림
        /// </summary>
        private MemoryStream memoryStream = new MemoryStream();

        /// <summary>
        /// 바운더리
        /// </summary>
        private string boundary;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 바운더리 - Boundary

        /// <summary>
        /// 바운더리
        /// </summary>
        public string Boundary
        {
            get
            {
                return this.boundary;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MultiPartHelper()

        /// <summary>
        /// 생성자
        /// </summary>
        public MultiPartHelper()
        {
            this.boundary = GetBoundary();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 바운더리 구하기 - GetBoundary()

        /// <summary>
        /// 바운더리 구하기
        /// </summary>
        /// <returns>바운더리</returns>
        public static string GetBoundary()
        {
            return Environment.TickCount.ToString("X");
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 추가하기 - Add(nameValuePart)

        /// <summary>
        /// 추가하기
        /// </summary>
        /// <param name="nameValuePart">명칭 값 파트</param>
        public void Add(NameValuePart nameValuePart)
        {
            this.nameValuePartList.Add(nameValuePart);

            nameValuePart.Boundary = this.boundary;
        }

        #endregion
        #region 추가하기 - Add(filePart)

        /// <summary>
        /// 추가하기
        /// </summary>
        /// <param name="filePart">파일 파트</param>
        public void Add(FilePart filePart)
        {
            if(this.fileCollection == null)
            {
                this.fileCollection = new FileCollection();
            }

            this.fileCollection.Add(filePart);
        }

        #endregion
        #region 업로드하기 - Upload(webClient, url, method)

        /// <summary>
        /// 업로드하기
        /// </summary>
        /// <param name="webClient">웹 클라이언트</param>
        /// <param name="url">URL</param>
        /// <param name="method">메소드</param>
        public void Upload(WebClient webClient, string url, string method)
        {
            webClient.Headers.Add(HttpRequestHeader.ContentType, "multipart/form-data; boundary=" + this.boundary);

            Trace.WriteLine("Content-Type: multipart/form-data; boundary=" + this.boundary + "\r\n");

            foreach(NameValuePart nameValuePart in this.nameValuePartList)
            {
                nameValuePart.CopyTo(this.memoryStream);
            }

            this.fileCollection.CopyTo(this.memoryStream);

            if(this.fileCollection.Count > 0)
            {
                StringBuilder stringBuilder = new StringBuilder();

                stringBuilder.AppendFormat("--{0}", this.Boundary).Append("\r\n");

                byte[] byteArray = Encoding.ASCII.GetBytes(stringBuilder.ToString());

                this.memoryStream.Write(byteArray, 0, byteArray.Length);
            }

            this.memoryStream.Seek(0, SeekOrigin.Begin);

            Trace.WriteLine(Encoding.ASCII.GetString(this.memoryStream.ToArray()));

            byte[] responseByteArray = webClient.UploadData(url, method, this.memoryStream.ToArray());

            Trace.WriteLine("----- RESPONSE ------");
            Trace.WriteLine(Encoding.ASCII.GetString(responseByteArray));
        }

        #endregion
    }
}

 

▶ form.aspx

<form action="form.aspx" enctype="multipart/form-data" method="post" runat="server">
    Your name : <input name="fname" />
    Your id : <input name="id" />

    What files are you sending?

    <input id="pics1" name="pics1" runat="server" type="file" />
    <input id="pics2" name="pics2" runat="server" type="file" />
    <input type="submit" />
</form>

 

▶ Program.cs

using System;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Net;

namespace TestProject
{
    /// <summary>
    /// 프로그램
    /// </summary>
    class Program
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

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

        /// <summary>
        /// 프로그램 시작하기
        /// </summary>
        private static void Main()
        {
            Trace.Listeners.Add(new ConsoleTraceListener());

            try
            {
                string filePath1 = "d:\\test1.txt";
                string filePath2 = "d:\\test2.txt";

                using(Stream stream1 = File.OpenRead(filePath1))
                using(Stream stream2 = File.OpenRead(filePath2))
                using(WebClient webClient = new WebClient())
                {
                    MultiPartHelper helper = new MultiPartHelper();

                    NameValueCollection collection = new NameValueCollection();

                    collection.Add("fname", "john");
                    collection.Add("id"   , "acme");

                    helper.Add(new NameValuePart(collection));

                    FilePart filePart1 = new FilePart(stream1, "pics1", "text/plain");

                    filePart1.FileName = "test1.txt";

                    helper.Add(filePart1);

                    FilePart filePart2 = new FilePart(stream2, "pics2", "text/plain");

                    filePart2.FileName = "test2.txt";

                    helper.Add(filePart2);

                    helper.Upload(webClient, "http://127.0.0.1/form.aspx", "POST");
                }
            }
            catch(Exception exception)
            {
                Trace.WriteLine(exception);
            }
        }

        #endregion
    }
}
728x90
반응형
Posted by 사용자 icodebroker

댓글을 달아 주세요