中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》
  • 首頁 > 
  • 教程 > 
  • 開發技術 > 
  • 在 MVC Controller 中,不依靠定制路由,隨心所欲地攔截請求和處理請求,想怎么輸入輸出都

在 MVC Controller 中,不依靠定制路由,隨心所欲地攔截請求和處理請求,想怎么輸入輸出都

發布時間:2020-04-11 09:45:27 來源:網絡 閱讀:305 作者:jmcooler 欄目:開發技術
  Asp.net 中的 MVC,其主要面向 “text” 類型的 Content-Type 來處理 HTTP 請求,除了文件傳輸之外,就連 json、xml 也都是文本類型。

  因此,對于 text 類型的輸入輸出,MVC 自然處理得很好。可有時候,這并不能令我們滿意。

  當我們要傳輸二進制 byte[] 數組、序列化結構數據、以及任何特殊請求的處理時,該怎么辦呢?難道非要將它們以 base64 編碼,抑或是為特殊請求定制一個路由,譬如轉到 IHttpHandler/IRouteHandler 去處理嗎?

  我也是一個 Asp.net 的初學者,更是一個 MVC 的初學者,剛開始我也跟著這個思路去做,結果發現越增加路由,就會給程序帶來意想不到的麻煩。我就加了一句話: routes.Add( "myRouteName", new Route( "ac/aucenter", new MyHttpRouteHandler() ) ); 就引起視圖頁面的所有鏈接,全都變成了 http://host/ac/aucenter?,而為這些鏈接指定的控制器,Action,全都變成了該 Url 的參數。

  當然,我可以不增加這個路由,而是將 “加密后的二進制數據” 進行 base64 編碼后再傳輸,可是,這在一個 C++ 客戶端 DLL 中,我又怎么能做好 base64 編碼呢?在 C++ 中,與 asp.net 服務端進行交互非常困難,直接發送和接收二進制、序列化數據最簡單。反正,我一定不要增加路由,在路由上想任何辦法,都是 “打補丁” 的思維方式。

  本著我對 C++ 和 Windows 十多年的經驗,我猜想?MVC 一定能讓我任意地攔截 HTTP 請求,不讓它進入系統的路由中逗一圈,而是在進入路由之前,讓我捕獲,以轉入我自己的處理。但是在網上找了半天也沒找到如意的,有說加 Filter 的,有說處理 404 錯誤的,方法非常多,但都有這樣那樣的問題。 譬如說,加 Filter 吧,我既然都不調用?routes.Add() ,那么加 Filter 沒用啊;處理 404? 這得要全局攔截,在 Application 中攔截 404,你放心嗎?還居然有 server.GetLastError() 的調用都來了,這明顯是取服務器最后一個錯誤啊,那么多錯誤同時發生,你就攔截最后一個錯誤?

  在路由上,我實在找不到辦法,于是就轉入 Controller 本身,看看它能否直接處理二進制數據,特別關注 Controller 是怎么把響應數據發回給客戶端的,ContentResult,JsonResult,FileStreamResult?等等,都是用來發回響應的,我于是翻看了下?ContentResult 的 .NET 源代碼,然后恍然大悟。
public class ContentResult : ActionResult
{
    public override void ExecuteResult(ControllerContext context)
    {
        if( context == null )
            throw new ArgumentNullException("context");

        HttpResponseBase response = context.HttpContext.Response;
        if( !string.IsNullOrEmpty( this.ContentType ) )
            response.ContentType = this.ContentType;

        if( this.ContentEncoding != null )
            response.ContentEncoding = this.ContentEncoding;

        if( this.Content != null )
            response.Write(this.Content);
    }

    public string Content { get; set; }

    public Encoding ContentEncoding { get; set; }

    public string ContentType { get; set; }
}
  在 ContentResult?中,它的 ExecuteResult() 不就是調用 HttpContext.Response.Write() 把數據寫入 response,發回客戶端的嗎。只是,ExecuteResult() 不是由我們直接調用的,而是在我們的?Controller 的 Action() 處理結束返回該?ContentResult 對象后,由 MVC 接著調用的。

  為啥非要讓 MVC 調用?Response.Write(),我直接調用不也可以嗎?我調用完之后,返回一個 EmptyResult,讓它啥也不干,不就好了嗎?

  再翻看?EmptyResult 的 .NET 源碼發現,它確實啥也不干,空空如也。其內部只實現了一個單例模型。

  再來看看 Request 請求,我測試后發現,服務器端確實能接收到二進制流,如下所示:
public class TestController : Controller
{
    [HttpPost]
    public ActionResult Index()
    {
        MemoryStream inStream = new MemStream( Math.Max( Request.TotalBytes, 64 ) );
        Request.InputStream.CopyTo( inStream );

        // 對 inStream 做處理,將響應數據放在 rspData 中,然后:

        Response.OutputStream.Write( rspData, 0, rspData.Length );

        return EmptyResult.Instance;
    }
}
  就這么簡單,你想怎樣處理 HTTP 的流進流出,都隨你的意。

  你也可以從?ActionResult 派生一個自己的類,例如 MyResult,在其?ExecuteResult() 接口實現中,參照?ContentResult 的代碼,把響應數據?rspData 發回。而在上面的?TestController.Index() 返回你的 new?MyResult(?rspData ).

?

  接下來,我們來看看,各種編程語言的互操作問題,大家都贊同以 Json,Xml 來序列化數據,然后在各個平臺,各種語言,各個操作系統之間交互,以我看,這并不一定簡單易用。來看看我提供的一個序列化工具,簡單易用,內存占用少,稍作修改就可以跨平臺。

  這個工具,提供 3 個類和一個接口,就是抄的 C# 的 MemoryStream,BinaryWriter,BinaryReader 的源碼來編寫。C# 的實現上,有諸多的小問題,例如,它無法處理 null 字符串,而這個工具能序列化 null 字符串。此外,C# 的這些類,搞了一堆沒啥用的 Dispose(),有時候莫名其妙地,其內部的 Stream 就被 Dispose() 了。而這個工具,不用理會這些,它只隱含繼承基類的 Dispose()。誰創建的 Stream,就由誰負責?Dispose(),否則就亂套了。
internal class BinWriter
    {
        Stream   stream;
        Encoding encoding;
        byte[]   _buffer;

        internal BinWriter( Stream stream, Encoding encoding )
        {
            this.stream = stream;
            this.encoding = encoding;
            _buffer = new byte[8];
        }

        internal void Write( bool value )
        {
            stream.WriteByte( value ? ((byte)1) : ((byte) 0) );
        }

        internal void Write( byte value )
        {
            stream.WriteByte( value );
        }

        internal void Write( short value )
        {
            _buffer[0] = (byte) value;
            _buffer[1] = (byte) (value >> 8);
            stream.Write( _buffer, 0, 2 );
        }

        internal void Write( int value )
        {
            _buffer[0] = (byte) value;
            _buffer[1] = (byte) (value >> 8);
            _buffer[2] = (byte) (value >> 0x10);
            _buffer[3] = (byte) (value >> 0x18);
            stream.Write( _buffer, 0, 4 );
        }

        internal void Write( long value )
        {
            _buffer[0] = (byte) value;
            _buffer[1] = (byte) (value >> 8);
            _buffer[2] = (byte) (value >> 0x10);
            _buffer[3] = (byte) (value >> 0x18);
            _buffer[4] = (byte) (value >> 0x20);
            _buffer[5] = (byte) (value >> 40);
            _buffer[6] = (byte) (value >> 0x30);
            _buffer[7] = (byte) (value >> 0x38);
            stream.Write( _buffer, 0, 8 );
        }

        internal void Write( string value )
        {
            if( value == null )
                Write7BitEncodedInt( stream, Int32.MinValue );
            else if( value.Length == 0 )
                Write7BitEncodedInt( stream, 0 );
            else
            {
                byte[] bstr = encoding.GetBytes( value );
                Write7BitEncodedInt( stream, bstr.Length );
                stream.Write( bstr, 0, bstr.Length );
            }
        }

        internal void Write( ushort value )
        {
            _buffer[0] = (byte) value;
            _buffer[1] = (byte) (value >> 8);
            stream.Write( _buffer, 0, 2 );
        }

        internal void Write( uint value )
        {
            _buffer[0] = (byte) value;
            _buffer[1] = (byte) (value >> 8);
            _buffer[2] = (byte) (value >> 0x10);
            _buffer[3] = (byte) (value >> 0x18);
            stream.Write( _buffer, 0, 4 );
        }

        internal void Write( ulong value )
        {
            _buffer[0] = (byte) value;
            _buffer[1] = (byte) (value >> 8);
            _buffer[2] = (byte) (value >> 0x10);
            _buffer[3] = (byte) (value >> 0x18);
            _buffer[4] = (byte) (value >> 0x20);
            _buffer[5] = (byte) (value >> 40);
            _buffer[6] = (byte) (value >> 0x30);
            _buffer[7] = (byte) (value >> 0x38);
            stream.Write( _buffer, 0, 8 );
        }

        internal void Write( DateTime value )
        {
            Write( value.ToBinary() );
        }

        internal void Write( byte[] buffer, int index, int count )
        {
            stream.Write( buffer, index, count );
        }

        internal static void Write7BitEncodedInt( Stream strm, int value )
        {
            uint num = (uint)value;
            while( num >= 0x80 )
            {
                strm.WriteByte( (byte) (num | 0x80) );
                num = num >> 7;
            }
            strm.WriteByte( (byte)num );
        }
    }

    internal class BinReader
    {
        Stream   stream;
        Encoding encoding;
        byte[]   _buffer;

        internal BinReader( Stream stream, Encoding encoding )
        {
            this.stream = stream;
            this.encoding = encoding;
            _buffer = new byte[128];
        }

        internal int Read( byte[] buffer, int index, int count )
        {
            return stream.Read( buffer, index, count );
        }

        internal bool ReadBool()
        {
            return stream.ReadByte() > 0;
        }

        internal byte ReadByte()
        {
            return (byte)stream.ReadByte();
        }

        internal short ReadInt16()
        {
            stream.Read( _buffer, 0, 2 );
            return (short)(_buffer[0] | (_buffer[1] << 8));
        }

        internal int ReadInt32()
        {
            stream.Read( _buffer, 0, 4 );
            return (((_buffer[0] | (_buffer[1] << 8)) | (_buffer[2] << 0x10)) | (_buffer[3] << 0x18));
        }

        internal long ReadInt64()
        {
            stream.Read( _buffer, 0, 8 );
            uint num = (uint) (((_buffer[0] | (_buffer[1] << 8)) | (_buffer[2] << 0x10)) | (_buffer[3] << 0x18));
            ulong num2 = (ulong) (((_buffer[4] | (_buffer[5] << 8)) | (_buffer[6] << 0x10)) | (_buffer[7] << 0x18));
            return (long) ((num2 << 0x20) | num);
        }

        internal string ReadString()
        {
            int capacity = Read7BitEncodedInt( stream );
            if( capacity == Int32.MinValue )
                return null;
            else if( capacity == 0 )
                return "";

            MemStream memStr = stream as MemStream;
            if( memStr == null )
            {
                if( _buffer.Length < capacity )
                    _buffer = new byte[capacity];

                stream.Read( _buffer, 0, capacity );
                return encoding.GetString( _buffer, 0, capacity );
            }
            else
            {
                string str = encoding.GetString( memStr.GetBuffer(), (int)memStr.Position, capacity );
                memStr.Seek( capacity, SeekOrigin.Current );
                return str;
            }
        }

        internal ushort ReadUInt16()
        {
            stream.Read( _buffer, 0, 2 );
            return (ushort) (_buffer[0] | (_buffer[1] << 8));
        }

        internal uint ReadUInt32()
        {
            stream.Read( _buffer, 0, 4 );
            return (uint) (((_buffer[0] | (_buffer[1] << 8)) | (_buffer[2] << 0x10)) | (_buffer[3] << 0x18));
        }

        internal ulong ReadUInt64()
        {
            stream.Read( _buffer, 0, 8 );
            uint num = (uint) (((_buffer[0] | (_buffer[1] << 8)) | (_buffer[2] << 0x10)) | (_buffer[3] << 0x18));
            ulong num2 = (ulong) (((_buffer[4] | (_buffer[5] << 8)) | (_buffer[6] << 0x10)) | (_buffer[7] << 0x18));
            return ((num2 << 0x20) | num);
        }

        internal DateTime ReadDate()
        {
            return DateTime.FromBinary( ReadInt64() );
        }

        internal static int Read7BitEncodedInt( Stream strm )
        {
            byte num3;
            int num = 0, num2 = 0;
            do
            {
                if( num2 == 0x23 )
                    throw new FormatException( "Stream Format Error" );
                num3 = (byte)strm.ReadByte();
                num |= (num3 & 0x7f) << num2;
                num2 += 7;
            }
            while( (num3 & 0x80) != 0 );
            return num;
        }
    }

    internal class MemStream : Stream
    {
        byte[] _buffer;
        int _capacity, _length;
        int _origin, _position;

        internal MemStream() : this(0)
        {
        }

        internal MemStream( int capacity )
        {
            if( capacity > 0 )
                _buffer = new byte[capacity];
            _capacity = capacity;
        }

        internal MemStream( byte[] buffer )
        {
            SetBuffer( buffer );
        }

        internal MemStream( byte[] buffer, int index, int count )
        {
            SetBuffer( buffer, index, count );
        }

        internal void SetBuffer( byte[] buffer )
        {
            _buffer = buffer;
            _length = _capacity = buffer.Length;
            _origin = _position = 0;
        }

        internal void SetBuffer( byte[] buffer, int index, int count )
        {
            _buffer = buffer;
            _length = _capacity = index + count;
            _origin = _position = index;
        }

        internal bool EnsureCapacity( int value )
        {
            if( value <= _capacity )
                return false;

            int num = value;
            if( num < 0x100 )
                num = 0x100;

            if( num < _capacity * 2 )
                num = _capacity * 2;
            if( _capacity * 2 > 0x7fffffc7 )
                num = (value > 0x7fffffc7) ? value : 0x7fffffc7;
            Capacity = num;
            return true;
        }

        public override void Flush()
        {
        }

        public virtual byte[] GetBuffer()
        {
            return _buffer;
        }

        internal byte[] ToBytesArray()
        {
            int    memLen = (int)this.Length;
            byte[] aryBytes = new byte[memLen];
            if( memLen > 0 )
                Array.Copy( _buffer, _origin, aryBytes, 0, memLen );
            return aryBytes;
        }

        /// <summary>
        /// 從當前流讀取字節序列,并將此流中的位置提升讀取的字節數。
        /// </summary>
        /// <param name="offset">buffer 中的從零開始的字節偏移量,從此處開始存儲從當前流中讀取的數據。</param>
        /// <param name="count">要從當前流中最多讀取的字節數</param>
        /// <returns>讀入緩沖區中的總字節數。如果當前可用的字節數沒有請求的字節數那么多,則總字節數可能小于請求的字節數;如果已到達流的末尾,則為零 (0)。</returns>
        public override int Read( byte[] buffer, int offset, int count )
        {
            int byteCount = _length - _position;
            if( byteCount > count )
                byteCount = count;
            if( byteCount <= 0 )
                return 0;
            if( byteCount <= 8 )
            {
                int num2 = byteCount;
                while( --num2 >= 0 )
                    buffer[offset + num2] = _buffer[_position + num2];
            }
            else
                Array.Copy( _buffer, _position, buffer, offset, byteCount );
            _position += byteCount;
            return byteCount;
        }

        public override int ReadByte()
        {
            if( _position >= _length )
                return -1;
            return _buffer[_position++];
        }

        public override long Seek( long offset, SeekOrigin loc )
        {
            switch( loc )
            {
                case SeekOrigin.Begin:
                {
                    int num = _origin + (int)offset;
                    if( offset < 0L || num < _origin )
                        throw new IOException( "IO.IO_SeekBeforeBegin" );
                    _position = num;
                    break;
                }
                case SeekOrigin.Current:
                {
                    int num2 = _position + (int)offset;
                    if( (_position + offset) < _origin || num2 < _origin )
                        throw new IOException( "IO.IO_SeekBeforeBegin" );
                    _position = num2;
                    break;
                }
                case SeekOrigin.End:
                {
                    int num3 = _length + (int)offset;
                    if( (_length + offset) < _origin || num3 < _origin )
                        throw new IOException( "IO.IO_SeekBeforeBegin" );
                    _position = num3;
                    break;
                }
                default:
                    throw new ArgumentException( "Argument_InvalidSeekOrigin" );
            }
            return (long)_position;
        }

        public override void SetLength( long value )
        {
            if( value > 0x7fffffff - _origin )
                throw new ArgumentOutOfRangeException( "value", "ArgumentOutOfRange_StreamLength" );
            int num = _origin + (int)value;
            if( !EnsureCapacity( num ) && num > _length )
                Array.Clear( _buffer, _length, num - _length );

            _length = num;
            if( _position > num )
                _position = num;
        }

        public override void Write( byte[] buffer, int offset, int count )
        {
            int num = _position + count;
            if( num > _length )
            {
                bool flag = _position > _length;
                if( num > _capacity && EnsureCapacity( num ) )
                    flag = false;
                if( flag )
                    Array.Clear( _buffer, _length, num - _length );
                _length = num;
            }
            if( count <= 8 && buffer != _buffer )
            {
                int num2 = count;
                while( --num2 >= 0 )
                    _buffer[_position + num2] = buffer[offset + num2];
            }
            else
                Array.Copy( buffer, offset, _buffer, _position, count );
            _position = num;
        }

        public override void WriteByte( byte value )
        {
            if( _position >= _length )
            {
                int num   = _position + 1;
                bool flag = _position > _length;
                if( num >= _capacity && EnsureCapacity( num ) )
                    flag = false;
                if( flag )
                    Array.Clear( _buffer, _length, _position - _length );
                _length = num;
            }
            _buffer[_position++] = value;
        }

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

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

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

        public virtual int Capacity
        {
            get { return _capacity - _origin; }
            set
            {
                if( value != _capacity )
                {
                    if( value > 0 )
                    {
                        byte[] dst = new byte[value];
                        if( _length > 0 )
                            Array.Copy( _buffer, 0, dst, 0, _length );
                        _buffer = dst;
                    }
                    else
                        _buffer = null;
                    _capacity = value;
                }
            }
        }

        public override long Length
        {
            get { return (long)(_length - _origin); }
        }

        public override long Position
        {
            get { return (long)(_position - _origin); }
            set { _position = _origin + ((int)value); }
        }

        internal void Write7BitEncodedInt( int value )
        {
            BinWriter.Write7BitEncodedInt( this, value );
        }

        internal int Read7BitEncodedInt()
        {
            return BinReader.Read7BitEncodedInt( this );
        }
    }
  任何想用這個工具進行序列化的類,只需要實現下面的借口:
public abstract BinSerializer
{
    // 將各成員的數據寫入 stream,這是一個輔助函數,派生類一般不需要重載
    public virtual void ToStream( MemStream stream )
    {
        ToBinary( new BinWriter( stream, Encoding.UTF8 ) );
    }

    // 從 stream 中讀取各成員的數據,這是一個輔助函數,派生類一般不需要重載
    public virtual void FromStream( MemStream stream )
    {
        FromBinary( new BinReader( stream, Encoding.UTF8 ) );
    }

    protected abstract void ToBinary( BinWriter bw ); // 派生類實現此函數
    protected abstract void FromBinary( BinReader br ); // 派生類實現此函數

}

舉個例子:

public class MyTest :?BinSerializer

{
    public int  x;
    public bool y;
    public string z;
    public DateTime dt;
? ? 
    protected overide void ToBinary( BinWriter bw )?// 派生類實現此函數

    {
        bw.Write( x );
        bw.Write( y );
        bw.Write( z );
        bw.Write( dt );
    }

? ? protected overide void FromBinary( BinReader br ) // 派生類實現此函數
    {
        x = br.ReadInt32();
        y = br.ReadBool();
        z = br.ReadString();
        dt = br.ReadDate();
    }
}
using( MemStream stream = new MemStream() )

{

    MyTest tester = new?MyTest();

    tester.ToStream( stream ); // 將各成員的數據寫入 stream

    stream.Position = 0;? // 將流的位置 Seek 到 Beginning,下面將從它讀取數據

    MyTest newTester = new?MyTest();?

    newTester.FromStream(?stream );?// 從 stream 中讀取各成員的數據
}
  雖然沒有 C# 的?[Serializable] 類屬性來得簡單,但這對各平臺互操作有利。是?[Serializable] 和 Json 之間的一種折中方案。

  同時,它不會引入一堆 Json 和 XML 中的描述標簽,而是直接反映內存數據。確保各個成員的讀寫順序一致,并確保各個平臺的 int, long, uint, ulong 的字節數一致,就可以交互
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

新竹市| 邓州市| 义乌市| 屏东县| 焉耆| 壶关县| 微博| 神木县| 连江县| 佛坪县| 钟山县| 临沭县| 班玛县| 安阳市| 崇阳县| 凯里市| 扎兰屯市| 勃利县| 涞源县| 上栗县| 沾益县| 谢通门县| 时尚| 通榆县| 留坝县| 隆安县| 雅江县| 池州市| 赤城县| 屯门区| 文山县| 新乡市| 鄂伦春自治旗| 明水县| 洛川县| 青州市| 榆中县| 镇平县| 乌鲁木齐县| 深水埗区| 儋州市|