Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wcf n此.requestStream.Position; } if(byteReadFromStream.Equals(LF)| this.readBuffer.IsFull) { 此参数为.readBuffer.Reset(); } } } 专用字节[]ToByteArray(流) { 字节[]缓冲区=新字节[32768]; 使用(MemoryStream ms=new MemoryStream()) { while(true) { int read=stream.read(buffer,0,buffer.Length); if(读取(this.end-this.position)) { 计数=(int)(this.end-this.position); } if(count=this.end) { 返回-1; } this.stream.Position=this.Position; var byteReadFromStream=this.stream.ReadByte(); 这一点。后述(1); 返回byteReadFromStream; } /// ///在派生类中重写时,设置当前流中的位置。 /// ///当前流中的新位置。 ///相对于参数的字节偏移量。 ///指示用于获取新位置的参考点的类型值。 公共覆盖长寻道(长偏移,参见原始坐标系) { var子流相对位置= 这。计算子流相对位置(原点、偏移); 此。通过异常定位为自动边界(子流相对定位); this.position=this.stream.Seek(subStreamRelativePosition,参见korigin.Begin); 返回此位置; } /// ///在派生类中重写时,设置当前流的长度。 /// ///当前流的所需长度(字节)。 ///这将始终为该类型抛出一个错误。 公共覆盖无效设置长度(长值) { 抛出新的InvalidOperationException(); } /// ///在派生类中重写时,将字节序列写入当前流,并按写入的字节数前进此流中的当前位置。 /// ///字节数组。此方法将字节从复制到当前流。 ///从零开始向当前流复制字节的字节偏移量。 ///要写入当前流的字节数。 ///这将始终为该类型抛出一个错误。 公共重写无效写入(字节[]缓冲区、整数偏移量、整数计数) { 抛出新的InvalidOperationException(); } 通过ExceptionsPositionIsOutofBounds(长子流相对位置)的私有无效 { if(subStreamRelativePositionthis.end) { 抛出新的InvalidOperationException(); } } private long Calculates Substreamr相对位置(请参见原始原点,长偏移量) { var subStreamRelativePosition=0L; 开关(原点) { 案例请参见Korigin。开始: subStreamRelativePosition=this.start+offset; 打破 案例见Korigin.Current: 子流相对位置=此位置+偏移量; 打破 案例请参见Korigin。结束: subStreamRelativePosition=this.end+偏移量; 打破 } 返回子流相对位置; } 私有读取(int bytesReadFromStream) { if(bytesReadFromStream==-1) { this.position=this.end; } 其他的 { this.position+=字节从流读取; } } } }_Wcf_Multipartform Data - Fatal编程技术网

Wcf n此.requestStream.Position; } if(byteReadFromStream.Equals(LF)| this.readBuffer.IsFull) { 此参数为.readBuffer.Reset(); } } } 专用字节[]ToByteArray(流) { 字节[]缓冲区=新字节[32768]; 使用(MemoryStream ms=new MemoryStream()) { while(true) { int read=stream.read(buffer,0,buffer.Length); if(读取(this.end-this.position)) { 计数=(int)(this.end-this.position); } if(count=this.end) { 返回-1; } this.stream.Position=this.Position; var byteReadFromStream=this.stream.ReadByte(); 这一点。后述(1); 返回byteReadFromStream; } /// ///在派生类中重写时,设置当前流中的位置。 /// ///当前流中的新位置。 ///相对于参数的字节偏移量。 ///指示用于获取新位置的参考点的类型值。 公共覆盖长寻道(长偏移,参见原始坐标系) { var子流相对位置= 这。计算子流相对位置(原点、偏移); 此。通过异常定位为自动边界(子流相对定位); this.position=this.stream.Seek(subStreamRelativePosition,参见korigin.Begin); 返回此位置; } /// ///在派生类中重写时,设置当前流的长度。 /// ///当前流的所需长度(字节)。 ///这将始终为该类型抛出一个错误。 公共覆盖无效设置长度(长值) { 抛出新的InvalidOperationException(); } /// ///在派生类中重写时,将字节序列写入当前流,并按写入的字节数前进此流中的当前位置。 /// ///字节数组。此方法将字节从复制到当前流。 ///从零开始向当前流复制字节的字节偏移量。 ///要写入当前流的字节数。 ///这将始终为该类型抛出一个错误。 公共重写无效写入(字节[]缓冲区、整数偏移量、整数计数) { 抛出新的InvalidOperationException(); } 通过ExceptionsPositionIsOutofBounds(长子流相对位置)的私有无效 { if(subStreamRelativePositionthis.end) { 抛出新的InvalidOperationException(); } } private long Calculates Substreamr相对位置(请参见原始原点,长偏移量) { var subStreamRelativePosition=0L; 开关(原点) { 案例请参见Korigin。开始: subStreamRelativePosition=this.start+offset; 打破 案例见Korigin.Current: 子流相对位置=此位置+偏移量; 打破 案例请参见Korigin。结束: subStreamRelativePosition=this.end+偏移量; 打破 } 返回子流相对位置; } 私有读取(int bytesReadFromStream) { if(bytesReadFromStream==-1) { this.position=this.end; } 其他的 { this.position+=字节从流读取; } } } }

Wcf n此.requestStream.Position; } if(byteReadFromStream.Equals(LF)| this.readBuffer.IsFull) { 此参数为.readBuffer.Reset(); } } } 专用字节[]ToByteArray(流) { 字节[]缓冲区=新字节[32768]; 使用(MemoryStream ms=new MemoryStream()) { while(true) { int read=stream.read(buffer,0,buffer.Length); if(读取(this.end-this.position)) { 计数=(int)(this.end-this.position); } if(count=this.end) { 返回-1; } this.stream.Position=this.Position; var byteReadFromStream=this.stream.ReadByte(); 这一点。后述(1); 返回byteReadFromStream; } /// ///在派生类中重写时,设置当前流中的位置。 /// ///当前流中的新位置。 ///相对于参数的字节偏移量。 ///指示用于获取新位置的参考点的类型值。 公共覆盖长寻道(长偏移,参见原始坐标系) { var子流相对位置= 这。计算子流相对位置(原点、偏移); 此。通过异常定位为自动边界(子流相对定位); this.position=this.stream.Seek(subStreamRelativePosition,参见korigin.Begin); 返回此位置; } /// ///在派生类中重写时,设置当前流的长度。 /// ///当前流的所需长度(字节)。 ///这将始终为该类型抛出一个错误。 公共覆盖无效设置长度(长值) { 抛出新的InvalidOperationException(); } /// ///在派生类中重写时,将字节序列写入当前流,并按写入的字节数前进此流中的当前位置。 /// ///字节数组。此方法将字节从复制到当前流。 ///从零开始向当前流复制字节的字节偏移量。 ///要写入当前流的字节数。 ///这将始终为该类型抛出一个错误。 公共重写无效写入(字节[]缓冲区、整数偏移量、整数计数) { 抛出新的InvalidOperationException(); } 通过ExceptionsPositionIsOutofBounds(长子流相对位置)的私有无效 { if(subStreamRelativePositionthis.end) { 抛出新的InvalidOperationException(); } } private long Calculates Substreamr相对位置(请参见原始原点,长偏移量) { var subStreamRelativePosition=0L; 开关(原点) { 案例请参见Korigin。开始: subStreamRelativePosition=this.start+offset; 打破 案例见Korigin.Current: 子流相对位置=此位置+偏移量; 打破 案例请参见Korigin。结束: subStreamRelativePosition=this.end+偏移量; 打破 } 返回子流相对位置; } 私有读取(int bytesReadFromStream) { if(bytesReadFromStream==-1) { this.position=this.end; } 其他的 { this.position+=字节从流读取; } } } },wcf,multipartform-data,Wcf,Multipartform Data,对于我试图做的事情来说,用法相对简单。我只是定义了一个边界,只查找特定的零件名称。因此,对于我问题中的示例,我使用了边界“----------------------------acebdf13572468”和三个文件:Json,frontImage,和realimage,我提供的答案是,除非所有文件都是文本文件,否则无法工作。由于我试图让其中两个成为图像,它们被错误地编码到字节数组,图像被破坏。 HEADERS: Content-Type: multipart/form-data; bound

对于我试图做的事情来说,用法相对简单。我只是定义了一个边界,只查找特定的零件名称。因此,对于我问题中的示例,我使用了边界
“----------------------------acebdf13572468”
和三个文件:
Json
frontImage
,和
realimage
我提供的答案是,除非所有文件都是文本文件,否则无法工作。由于我试图让其中两个成为图像,它们被错误地编码到字节数组,图像被破坏。
HEADERS: Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
         User-Agent: Fiddler
         Host: dhiibews.brandonb.com
         Content-Length: 107865
REQUESTBODY: ---------------------------acebdf13572468
             Content-Disposition: form-data; name="Json"; filename="depositcheckrequest.txt"
             Content-Type: application/json

             <@INCLUDE *C:\depositcheckrequest.txt*@>
             ---------------------------acebdf13572468
             Content-Disposition: form-data; name="frontImage"; filename="front.jpg"
             Content-Type: image/jpeg

             <@INCLUDE *C:\front.jpg*@>
             ---------------------------acebdf13572468
             Content-Disposition: form-data; name="rearImage"; filename="rear.jpg"
             Content-Type: image/jpeg

             <@INCLUDE *C:\rear.jpg*@>
             ---------------------------acebdf13572468--
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MyProjectNamespace
{
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// Retrieves <see cref="HttpMultipartBoundary"/> instances from a request stream.
    /// </summary>
    public class HttpMultipart
    {
        private const byte LF = (byte)'\n';
        private readonly byte[] boundaryAsBytes;
        private readonly HttpMultipartBuffer readBuffer;
        private readonly MemoryStream requestStream;
        private readonly byte[] closingBoundaryAsBytes;

        /// <summary>
        /// Initializes a new instance of the <see cref="HttpMultipart"/> class.
        /// </summary>
        /// <param name="requestStream">The request stream to parse.</param>
        /// <param name="boundary">The boundary marker to look for.</param>
        public HttpMultipart(Stream requestStream, string boundary)
        {
            this.requestStream = new MemoryStream(ToByteArray(requestStream));
            this.boundaryAsBytes = GetBoundaryAsBytes(boundary, false);
            this.closingBoundaryAsBytes = GetBoundaryAsBytes(boundary, true);
            this.readBuffer = new HttpMultipartBuffer(this.boundaryAsBytes, this.closingBoundaryAsBytes);
        }

        /// <summary>
        /// Gets the <see cref="HttpMultipartBoundary"/> instances from the request stream.
        /// </summary>
        /// <returns>An <see cref="IEnumerable{T}"/> instance, containing the found <see cref="HttpMultipartBoundary"/> instances.</returns>
        public IEnumerable<HttpMultipartBoundary> GetBoundaries()
        {
            return
                (from boundaryStream in this.GetBoundarySubStreams()
                 select new HttpMultipartBoundary(boundaryStream)).ToList();
        }

        private static byte[] GetBoundaryAsBytes(string boundary, bool closing)
        {
            var boundaryBuilder = new StringBuilder();

            boundaryBuilder.Append("--");
            boundaryBuilder.Append(boundary);

            if (closing)
            {
                boundaryBuilder.Append("--");
            }
            else
            {
                boundaryBuilder.Append('\r');
                boundaryBuilder.Append('\n');
            }

            var bytes =
                Encoding.ASCII.GetBytes(boundaryBuilder.ToString());

            return bytes;
        }

        private IEnumerable<HttpMultipartSubStream> GetBoundarySubStreams()
        {
            var boundarySubStreams = new List<HttpMultipartSubStream>();
            var boundaryStart = this.GetNextBoundaryPosition();

            while (MultipartIsNotCompleted(boundaryStart))
            {
                var boundaryEnd = this.GetNextBoundaryPosition();
                boundarySubStreams.Add(new HttpMultipartSubStream(
                    this.requestStream,
                    boundaryStart,
                    this.GetActualEndOfBoundary(boundaryEnd)));

                boundaryStart = boundaryEnd;
            }

            return boundarySubStreams;
        }

        private bool MultipartIsNotCompleted(long boundaryPosition)
        {
            return boundaryPosition > -1 && !this.readBuffer.IsClosingBoundary;
        }

        //we add two because or the \r\n before the boundary
        private long GetActualEndOfBoundary(long boundaryEnd)
        {
            if (this.CheckIfFoundEndOfStream())
            {
                return this.requestStream.Position - (this.readBuffer.Length + 2);
            }
            return boundaryEnd - (this.readBuffer.Length + 2);
        }

        private bool CheckIfFoundEndOfStream()
        {
            return this.requestStream.Position.Equals(this.requestStream.Length);
        }

        private long GetNextBoundaryPosition()
        {
            this.readBuffer.Reset();
            while (true)
            {
                var byteReadFromStream = this.requestStream.ReadByte();

                if (byteReadFromStream == -1)
                {
                    return -1;
                }

                this.readBuffer.Insert((byte)byteReadFromStream);

                if (this.readBuffer.IsFull && (this.readBuffer.IsBoundary || this.readBuffer.IsClosingBoundary))
                {
                    return this.requestStream.Position;
                }

                if (byteReadFromStream.Equals(LF) || this.readBuffer.IsFull)
                {
                    this.readBuffer.Reset();
                }
            }
        }

        private byte[] ToByteArray(Stream stream)
        {
            byte[] buffer = new byte[32768];
            using (MemoryStream ms = new MemoryStream())
            {
                while (true)
                {
                    int read = stream.Read(buffer, 0, buffer.Length);
                    if (read <= 0)
                    {
                        return ms.ToArray();
                    }
                    ms.Write(buffer, 0, read);
                }
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MyProjectNamespace
{
    public class HttpMultipartBuffer
    {
        private readonly byte[] boundaryAsBytes;
        private readonly byte[] closingBoundaryAsBytes;
        private readonly byte[] buffer;
        private int position;

        /// <summary>
        /// Initializes a new instance of the <see cref="HttpMultipartBuffer"/> class.
        /// </summary>
        /// <param name="boundaryAsBytes">The boundary as a byte-array.</param>
        /// <param name="closingBoundaryAsBytes">The closing boundary as byte-array</param>
        public HttpMultipartBuffer(byte[] boundaryAsBytes, byte[] closingBoundaryAsBytes)
        {
            this.boundaryAsBytes = boundaryAsBytes;
            this.closingBoundaryAsBytes = closingBoundaryAsBytes;
            this.buffer = new byte[this.boundaryAsBytes.Length];
        }

        /// <summary>
        /// Gets a value indicating whether the buffer contains the same values as the boundary.
        /// </summary>
        /// <value><see langword="true"/> if buffer contains the same values as the boundary; otherwise, <see langword="false"/>.</value>
        public bool IsBoundary
        {
            get { return this.buffer.SequenceEqual(this.boundaryAsBytes); }
        }

        public bool IsClosingBoundary
        {
            get { return this.buffer.SequenceEqual(this.closingBoundaryAsBytes); }
        }

        /// <summary>
        /// Gets a value indicating whether this buffer is full.
        /// </summary>
        /// <value><see langword="true"/> if buffer is full; otherwise, <see langword="false"/>.</value>
        public bool IsFull
        {
            get { return this.position.Equals(this.buffer.Length); }
        }

        /// <summary>
        /// Gets the the number of bytes that can be stored in the buffer.
        /// </summary>
        /// <value>The number of butes that can be stored in the buffer.</value>
        public int Length
        {
            get { return this.buffer.Length; }
        }

        /// <summary>
        /// Resets the buffer so that inserts happens from the start again.
        /// </summary>
        /// <remarks>This does not clear any previously written data, just resets the buffer position to the start. Data that is inserted after Reset has been called will overwrite old data.</remarks>
        public void Reset()
        {
            this.position = 0;
        }

        /// <summary>
        /// Inserts the specified value into the buffer and advances the internal position.
        /// </summary>
        /// <param name="value">The value to insert into the buffer.</param>
        /// <remarks>This will throw an <see cref="ArgumentOutOfRangeException"/> is you attempt to call insert more times then the <see cref="Length"/> of the buffer and <see cref="Reset"/> was not invoked.</remarks>
        public void Insert(byte value)
        {
            this.buffer[this.position++] = value;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace DHIWebSvc.Models
{
    public class HttpMultipartBoundary
    {
        private const byte LF = (byte)'\n';
        private const byte CR = (byte)'\r';

        /// <summary>
        /// Initializes a new instance of the <see cref="HttpMultipartBoundary"/> class.
        /// </summary>
        /// <param name="boundaryStream">The stream that contains the boundary information.</param>
        public HttpMultipartBoundary(HttpMultipartSubStream boundaryStream)
        {
            this.Value = boundaryStream;
            this.ExtractHeaders();
        }

        /// <summary>
        /// Gets the contents type of the boundary value.
        /// </summary>
        /// <value>A <see cref="string"/> containing the name of the value if it is available; otherwise <see cref="string.Empty"/>.</value>
        public string ContentType { get; private set; }

        /// <summary>
        /// Gets or the filename for the boundary value.
        /// </summary>
        /// <value>A <see cref="string"/> containing the filename value if it is available; otherwise <see cref="string.Empty"/>.</value>
        /// <remarks>This is the RFC2047 decoded value of the filename attribute of the Content-Disposition header.</remarks>
        public string Filename { get; private set; }

        /// <summary>
        /// Gets name of the boundary value.
        /// </summary>
        /// <remarks>This is the RFC2047 decoded value of the name attribute of the Content-Disposition header.</remarks>
        public string Name { get; private set; }

        /// <summary>
        /// A stream containig the value of the boundary.
        /// </summary>
        /// <remarks>This is the RFC2047 decoded value of the Content-Type header.</remarks>
        public HttpMultipartSubStream Value { get; private set; }

        private void ExtractHeaders()
        {
            while (true)
            {
                var header =
                    this.ReadLineFromStream();

                if (string.IsNullOrEmpty(header))
                {
                    break;
                }

                if (header.StartsWith("Content-Disposition", StringComparison.CurrentCultureIgnoreCase))
                {
                    this.Name = Regex.Match(header, @"name=""(?<name>[^\""]*)", RegexOptions.IgnoreCase).Groups["name"].Value;
                    this.Filename = Regex.Match(header, @"filename=""(?<filename>[^\""]*)", RegexOptions.IgnoreCase).Groups["filename"].Value;
                }

                if (header.StartsWith("Content-Type", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.ContentType = header.Split(new[] { ' ' }).Last().Trim();
                }
            }

            this.Value.PositionStartAtCurrentLocation();
        }

        private string ReadLineFromStream()
        {
            var readBuffer = new StringBuilder();

            while (true)
            {
                var byteReadFromStream = this.Value.ReadByte();

                if (byteReadFromStream == -1)
                {
                    return null;
                }

                if (byteReadFromStream.Equals(LF))
                {
                    break;
                }

                readBuffer.Append((char)byteReadFromStream);
            }

            var lineReadFromStream =
                readBuffer.ToString().Trim(new[] { (char)CR });

            return lineReadFromStream;
        }
    }
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;

namespace DHIWebSvc.Models
{
    public class HttpMultipartSubStream : Stream
    {
        private readonly Stream stream;
        private readonly long end;
        private long start;
        private long position;

        /// <summary>
        /// Initializes a new instance of the <see cref="HttpMultipartSubStream"/> class.
        /// </summary>
        /// <param name="stream">The stream to create the sub-stream ontop of.</param>
        /// <param name="start">The start offset on the parent stream where the sub-stream should begin.</param>
        /// <param name="end">The end offset on the parent stream where the sub-stream should end.</param>
        public HttpMultipartSubStream(Stream stream, long start, long end)
        {
            this.stream = stream;
            this.start = start;
            this.position = start;
            this.end = end;
        }

        /// <summary>
        /// When overridden in a derived class, gets a value indicating whether the current stream supports reading.
        /// </summary>
        /// <returns><see langword="true"/> if the stream supports reading; otherwise, <see langword="false"/>.</returns>
        public override bool CanRead
        {
            get { return true; }
        }

        /// <summary>
        /// When overridden in a derived class, gets a value indicating whether the current stream supports seeking.
        /// </summary>
        /// <returns><see langword="true"/> if the stream supports seeking; otherwise, <see langword="false"/>.</returns>
        public override bool CanSeek
        {
            get { return true; }
        }

        /// <summary>
        /// When overridden in a derived class, gets a value indicating whether the current stream supports writing.
        /// </summary>
        /// <returns><see langword="true"/> if the stream supports writing; otherwise, <see langword="false"/>.</returns>
        public override bool CanWrite
        {
            get { return false; }
        }

        /// <summary>
        /// When overridden in a derived class, gets the length in bytes of the stream.
        /// </summary>
        /// <returns>A long value representing the length of the stream in bytes.</returns>
        /// <exception cref="NotSupportedException">A class derived from Stream does not support seeking. </exception><exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed.</exception>
        public override long Length
        {
            get 
            { 
                return this.end - this.start; 
            }
        }

        /// <summary>
        /// When overridden in a derived class, gets or sets the position within the current stream.
        /// </summary>
        /// <returns>
        /// The current position within the stream.
        /// </returns>
        /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception><exception cref="T:System.NotSupportedException">The stream does not support seeking. </exception><exception cref="T:System.ObjectDisposedException">Methods were called after the stream was closed. </exception><filterpriority>1</filterpriority>
        public override long Position
        {
            get { return this.position - this.start; }
            set { this.position = this.Seek(value, SeekOrigin.Begin); }
        }

        public void PositionStartAtCurrentLocation()
        {
            this.start = this.stream.Position;
        }

        /// <summary>
        /// When overridden in a derived class, clears all buffers for this stream and causes any buffered data to be written to the underlying device.
        /// </summary>
        /// <remarks>In the <see cref="HttpMultipartSubStream"/> type this method is implemented as no-op.</remarks>
        public override void Flush()
        {
        }

        /// <summary>
        /// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
        /// </summary>
        /// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. </returns>
        /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between <paramref name="offset"/> and (<paramref name="offset"/> + <paramref name="count"/> - 1) replaced by the bytes read from the current source. </param>
        /// <param name="offset">The zero-based byte offset in <paramref name="buffer"/> at which to begin storing the data read from the current stream.</param>
        /// <param name="count">The maximum number of bytes to be read from the current stream. </param>
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (count > (this.end - this.position))
            {
                count = (int)(this.end - this.position);
            }

            if (count <= 0)
            {
                return 0;
            }

            this.stream.Position = this.position;

            var bytesReadFromStream =
                this.stream.Read(buffer, offset, count);

            this.RepositionAfterRead(bytesReadFromStream);

            return bytesReadFromStream;
        }

        /// <summary>
        /// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.
        /// </summary>
        /// <returns>The unsigned byte cast to an Int32, or -1 if at the end of the stream.</returns>
        public override int ReadByte()
        {
            if (this.position >= this.end)
            {
                return -1;
            }

            this.stream.Position = this.position;

            var byteReadFromStream = this.stream.ReadByte();

            this.RepositionAfterRead(1);

            return byteReadFromStream;
        }

        /// <summary>
        /// When overridden in a derived class, sets the position within the current stream.
        /// </summary>
        /// <returns>The new position within the current stream.</returns>
        /// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param>
        /// <param name="origin">A value of type <see cref="SeekOrigin"/> indicating the reference point used to obtain the new position.</param>
        public override long Seek(long offset, SeekOrigin origin)
        {
            var subStreamRelativePosition =
                this.CalculateSubStreamRelativePosition(origin, offset);

            this.ThrowExceptionIsPositionIsOutOfBounds(subStreamRelativePosition);

            this.position = this.stream.Seek(subStreamRelativePosition, SeekOrigin.Begin);

            return this.position;
        }

        /// <summary>
        /// When overridden in a derived class, sets the length of the current stream.
        /// </summary>
        /// <param name="value">The desired length of the current stream in bytes.</param>
        /// <remarks>This will always throw a <see cref="InvalidOperationException"/> for the <see cref="HttpMultipartSubStream"/> type.</remarks>
        public override void SetLength(long value)
        {
            throw new InvalidOperationException();
        }

        /// <summary>
        /// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
        /// </summary>
        /// <param name="buffer">An array of bytes. This method copies <paramref name="count"/> bytes from <paramref name="buffer"/> to the current stream. </param>
        /// <param name="offset">The zero-based byte offset in <paramref name="buffer"/> at which to begin copying bytes to the current stream. </param>
        /// <param name="count">The number of bytes to be written to the current stream. </param>
        /// <remarks>This will always throw a <see cref="InvalidOperationException"/> for the <see cref="HttpMultipartSubStream"/> type.</remarks>
        public override void Write(byte[] buffer, int offset, int count)
        {
            throw new InvalidOperationException();
        }

        private void ThrowExceptionIsPositionIsOutOfBounds(long subStreamRelativePosition)
        {
            if (subStreamRelativePosition < 0 || subStreamRelativePosition > this.end)
            {
                throw new InvalidOperationException();
            }
        }

        private long CalculateSubStreamRelativePosition(SeekOrigin origin, long offset)
        {
            var subStreamRelativePosition = 0L;

            switch (origin)
            {
                case SeekOrigin.Begin:
                    subStreamRelativePosition = this.start + offset;
                    break;

                case SeekOrigin.Current:
                    subStreamRelativePosition = this.position + offset;
                    break;

                case SeekOrigin.End:
                    subStreamRelativePosition = this.end + offset;
                    break;
            }
            return subStreamRelativePosition;
        }

        private void RepositionAfterRead(int bytesReadFromStream)
        {
            if (bytesReadFromStream == -1)
            {
                this.position = this.end;
            }
            else
            {
                this.position += bytesReadFromStream;
            }
        }
    }
}