為wcf寫個CircularStream

來源:互聯網
上載者:User

    wcf提供了streaming方式後,一直有個小問題,找不到合適的stream載體,如果能用上檔案流什麼的做傳回值那是最好不過了,但是更多的情況下,需要返回一個流,但是這個流並沒有類似檔案之類的真實載體,而且有時候這個流還比較大(如果很小的話,也不需要用到streaming方式了),這時候似乎就有那麼點麻煩了。

    首先,我不喜歡用MemoryStream,因為它真實的佔用了這麼多記憶體,遇到大資料量的情況下,wcf的streaming方式的威力將大大降低。當然,也可以藉助檔案,返迴文件流來繞開這個問題,或者使用其他的什麼現成的流。

    然而,我更傾向於使用類似Circular Buffer的邏輯來處理這個流,這樣可以佔用很小的記憶體,來輸出很大體積的流,最大限度的體現wcf的streaming模式的優勢。

    不過,網上查了幾個Circlar Buffer的實現,總感覺不是特別滿意。。。無奈之下只能自己動手打造一個:

CircularStream    public class CircularStream
        : Stream
    {

        #region Fields
        private const int DefaultCapacity = 0x10000;
        private readonly object SyncRoot = new object();
        private bool m_closed;
        private readonly byte[] m_buffer;
        private int m_read;
        private int m_write;
        #endregion

        #region Ctors

        public CircularStream(int capacity)
        {
            m_buffer = new byte[capacity];
        }

        public CircularStream(Action<Stream> action)
            : this(DefaultCapacity)
        {
            ThreadPool.QueueUserWorkItem(_ =>
            {
                try
                {
                    action(this);
                }
                finally
                {
                    this.Dispose();
                }
            });
        }

        #endregion

        #region Overrides

        public override bool CanRead
        {
            get { return true; }
        }

        public override bool CanSeek
        {
            get { return false; }
        }

        public override bool CanWrite
        {
            get { return true; }
        }

        public override void Flush() { }

        public override long Length
        {
            get { throw new NotSupportedException(); }
        }

        public override long Position
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new NotSupportedException();
        }

        public override void SetLength(long value)
        {
            throw new NotSupportedException();
        }

        protected override void Dispose(bool disposing)
        {
            lock (SyncRoot)
            {
                m_closed = true;
                Monitor.Pulse(SyncRoot);
            }
            base.Dispose(disposing);
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            lock (SyncRoot)
            {
                while (m_read == m_write)//empty
                    if (m_closed)
                        return 0;
                    else
                        Monitor.Wait(SyncRoot, 100, true);
                int c;
                if (m_write > m_read)
                    c = m_write - m_read;
                else
                    c = m_buffer.Length - m_read;
                Monitor.Pulse(SyncRoot);
                if (c > count)
                {
                    Buffer.BlockCopy(m_buffer, m_read, buffer, offset, count);
                    m_read += count;
                    return count;
                }
                else
                {
                    Buffer.BlockCopy(m_buffer, m_read, buffer, offset, c);
                    m_read = (m_read + c) % m_buffer.Length;
                    return c;
                }
            }
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            lock (SyncRoot)
            {
                if (m_closed)
                    throw new ObjectDisposedException("CircleBufferStream");
                while (count > 0)
                {
                    while ((m_write + 1) % m_buffer.Length == m_read)// full
                        Monitor.Wait(SyncRoot, 100, true);
                    if (m_read > m_write)
                    {
                        int c = Math.Min(m_read - m_write - 1, count);
                        Buffer.BlockCopy(buffer, offset, m_buffer, m_write, c);
                        m_write += c;
                        count -= c;
                        offset += c;
                    }
                    else
                    {
                        int c = m_buffer.Length - m_write;
                        if (m_read == 0)
                            --c;
                        if (c > count)
                        {
                            Buffer.BlockCopy(buffer, offset, m_buffer, m_write, count);
                            m_write += count;
                            count = 0;
                        }
                        else
                        {
                            Buffer.BlockCopy(buffer, offset, m_buffer, m_write, c);
                            m_write = (m_write + c) % m_buffer.Length;
                            count -= c;
                            offset += c;
                        }
                    }
                    Monitor.Pulse(SyncRoot);
                }
            }
        }

        #endregion

        #region Properties

        public int Capacity { get { return m_buffer.Length; } }

        #endregion

    }

    加上配套的契約和實現:

契約    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        Stream GetStream(int value);
    }實現    public class Service1 : IService1
    {
        public Stream GetStream(int value)
        {
            return new CircularStream(s =>
                new XStreamingElement("root",
                    from i in Enumerable.Range(1, value)
                    select new XElement("item",
                        new XAttribute("id", i))).Save(s));
        }
    }

    以及調用的服務和用戶端:

服務和用戶端    static class Program
    {
        static void Main(string[] args)
        {
            var host = new ServiceHost(typeof(Service1));
            host.Open();
            var binding= new BasicHttpBinding();
            binding.TransferMode=TransferMode.StreamedResponse;
            binding.MaxReceivedMessageSize = int.MaxValue;
            // 如果覺得不過癮,可以開啟迴圈爽一把
            //for (int i = 0; i < 100; i++)
            //{
                new Uri("http://localhost:12123/").InvokeWcfClient<IService1>(binding, c =>
                {
                    var stream = c.GetStream(10000);
                    string line;
                    using (var r = new StreamReader(stream))
                        while (null != (line = r.ReadLine()))
                            Console.WriteLine(line);
                });
            //}
            host.Close();
        }

        public static void InvokeWcfClient<TChannel>(
            this Uri uri, Binding binding, Action<TChannel> action)
            where TChannel : class
        {
            TChannel client = ChannelFactory<TChannel>.CreateChannel(
                binding, new EndpointAddress(uri));
            var co = (ICommunicationObject)client;
            try
            {
                co.Open();
                action(client);
            }
            finally
            {
                if (co.State == CommunicationState.Faulted)
                    co.Abort();
                else
                    co.Close();
            }
        }
    }

    這樣就可以完美運行了

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.