1. 程式人生 > >dotnet core使用開源組件FastHttpApi進行web應用開發(轉)

dotnet core使用開源組件FastHttpApi進行web應用開發(轉)

接收 web 情況下 nbsp true response vat sel 使用

FastHttpApi相對於asp.net mvc來說有著更輕量和性能上的優勢,性能上面就不在這裏介紹了(具體可查看 https://github.com/IKende/FastHttpApi)。在這裏主要講解一下如何使用FastHttpApi進行網站或WebApi開發,在使用FastHttpApi之前必須了解它具備那些功能,它除了提供webapi服務的編寫外還提供了靜態資源的支持,簡單來說FastHttpApi除了能實現基於HTTP的服務交互外還能實現應用網站;雖然不提供視MVC那樣的視圖處理功能,但可以通過現有比較成熟的前後端分離技術來實現應用網站的編寫。以下是簡單地描述一下FastHttpApi的功能:

  1. 支持以函數的方式來制定HTTP請求邏輯
  2. 支持使用者處理異步響應
  3. 支持Filter功能,以便更好地控制請求方法的處理
  4. 支持自定義Http Body解釋器,方便制定基於json,xml,protobuf,msgpack等數據格式的傳輸
  5. 支持QueryString參數和Cookies
  6. 支持外置或內嵌到DLL的靜態資源輸出(默認對html,js,css資源進行GZIP處理)
  7. 支持SSL

在後續版升級主要功能:同一服務端口的控制器邏輯會同時兼容http和websocket兩種協議請求

通過以上功能完全可以用來構建高效全安的應用網站。以下通過一些例子詳細講述如何使用FastHttpApi。

定義HTTP請求的方法

在FastHttpApi定義HTTP請求的方法和asp.net webapi差不多,都是通過定義一個控制器然後定義相關請求方法即可,當然使用起來會簡單一些。以下以Northwind的數據作為基礎制定了一個簡單的數據訪問控制器

技術分享圖片
    [FastHttpApi.Controller]
    public class Controller
    {
        public Controller()
        {
            mEmployees = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Employee>>(Datas.Employees);
            mCustomers = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Customer>>(Datas.Customers);
            mOrders = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Order>>(Datas.Orders);
        }
        private List<Employee> mEmployees;
        private List<Customer> mCustomers;
        private List<Order> mOrders;
        public Employee GetEmployee(int id)
        {
            Employee result = mEmployees.Find(e => e.EmployeeID == id);
            if (result == null)
                result = new Employee();
            return result;
        }
        public bool EditEmployee(int id, [BodyParameter]Employee emp, FastHttpApi.HttpResponse response)
        {
            Employee record = mEmployees.Find(e => e.EmployeeID == id);
            if (record != null)
            {
                record.City = emp.City;
                record.Address = emp.Address;
                record.Title = emp.Title;
                record.HomePhone = emp.HomePhone;
                return true;
            }
            return false;
        }
        public object ListEmployees()
        {
            return mEmployees;
        }
        public object GetEmployeesName()
        {
            return from e in mEmployees select new { ID = e.EmployeeID, Name = e.FirstName + " " + e.LastName };
        }
        public object GetCustomersName()
        {
            return from c in mCustomers select new { ID = c.CustomerID, Name = c.CompanyName };
        }
        public object ListOrders(int employeeid, string customerid)
        {
            return mOrders.Where(o =>
            (employeeid == 0 || o.EmployeeID == employeeid)
            &&
            (string.IsNullOrEmpty(customerid) || o.CustomerID == customerid));
        }
    }
技術分享圖片

相對於asp.net webapi來說,組件中會把所有控制器Public方法註冊為URL,方法是不區分GET或POST,如果有需要可以通過HttpRequest中獲取;參數根據自己需要來定義,參數有兩種來源一種是通過QueryString獲取而另一種則通過HttpBody獲取;對於HttpResponse和HttpRequest則看情況需要,如果有需要直接在方法中定義相關類型參數即可獲取。當控制器編寫完成後,需要給類寫上[Controller]標簽告訴組件這是一個api控制器接收HTTP請求。

異步應答處理

對於HTTP來說,一個請求就必須要應答,因為這是HTTP協議規範;在實際業務中往往方法處理完成就進行應答,但有些情況下需要異步應答;當一個業務需要處理大量IO的業務時那就會把線程處於等待狀態,為了更好地處理這種情況組件提供了異步應答處理;通過異步應答可以在大量IO處理異步回調後再進行應答處理。

技術分享圖片
        public void asyncHello(string name, HttpResponse response)
        {
            response.Async();
            Task.Run(() =>
            {
                Console.WriteLine("sleep ...");
                System.Threading.Thread.Sleep(5000);
                response.Result(string.Format("[{0}] hello {1}", DateTime.Now, name));
            });
        }
技術分享圖片

通過HttpResponse.Async方法告訴組件是異步應答,組件在這個方法執行完成後不會進行HTTP響應。實際響應是使用者需要顯式地調用HttpResponse.Result方法來進行應答。

filter的應用

相信寫過asp.net mvc的朋友對filter並不陌生,它的主要工作就是對請求方法進行攔截控制。FastHttpApi支持使用都定義任意功能的Filter,用來記錄日誌、控制權限等等。編寫好的控制器可以標記在Controller上,生效於所有相關主求方法;也可以針對個別方法標記上。組件除了提供Filter外還提供了SkipFilter,它的主要作用是移走某些不需要的Filter攔截器。

技術分享圖片
    public class GlobalFilter : FilterAttribute
    {
        public override void Execute(ActionContext context)
        {
            Console.WriteLine(DateTime.Now + " globalFilter execting...");
            context.Execute();
            Console.WriteLine(DateTime.Now + " globalFilter executed");
        }
    }
技術分享圖片

以上是標記一個全局的Filter,用於記錄方法執行前和執行後的時候,context.Execute()是告訴組件往下執行;如果判斷權限,則在這裏可以依據HttpRequest的信息情況來決定是否執行context.Execute(),這樣就起到了權限控制的作用。當希望某個方法不經過這個Filter的情況下可以這樣做:

技術分享圖片
        [SkipFilter(typeof(GlobalFilter))]
        [CustomFilter]
        public string Hello(string name)
        {
            return DateTime.Now + " hello " + name;
        }
技術分享圖片

HTTP消息體解釋器

組件通過IBodySerializer接口來規範HTTP消息體的解釋和一些錯誤狀態返回的數據

技術分享圖片
   public interface IBodySerializer
    {

        int Serialize(PipeStream stream, object data);

        bool TryDeserialize(PipeStream stream, int length, Type type, out object data);

        object GetNotFoundData(HttpResponse response);

        object GetInnerError(Exception e, HttpResponse response, bool outputStackTrace);

        object GetNotSupport(HttpResponse response);

        string ContentType { get; set; }
    }
技術分享圖片

接口提供的功能比較少,主要包括消息的序列化、反序列化和一些HTTP狀態的處理,隨便著功能的完善後期這接口可能會添加更多的方法。以下是針對Json實現的一個解釋器,畢竟在WEB通訊中json是最常用的(如果是網內服務交互為了提高效率可以實現protobuf,msgpack等二進制序列化)。

技術分享圖片
        public virtual int Serialize(PipeStream stream, object data)
        {
            int length = stream.CacheLength;
            string value = Newtonsoft.Json.JsonConvert.SerializeObject(data);
            stream.Write(value);
            return stream.CacheLength - length;
        }

        public virtual bool TryDeserialize(PipeStream stream, int length, Type type, out object data)
        {
            data = null;
            if (stream.Length >= length)
            {
                string value = stream.ReadString(length);
                if (type != null)
                {
                    data = Newtonsoft.Json.JsonConvert.DeserializeObject(value,type);
                }
                else
                {
                    data = Newtonsoft.Json.JsonConvert.DeserializeObject(value);
                }
                return true;
            }
            return false;
        }
技術分享圖片

可能通過以下方式‘mApiServer.ServerConfig.BodySerializer = new JsonBodySerializer();‘來設置相應HTTP服務的消息轉換器。

Cookies處理

FastHttpApi和asp.net mvc處理的方式差不多,通過HttpResponse進行Cookie的寫入,由HttpRequest來獲取Cookie值。

技術分享圖片
        public bool setCookie(string name, string value, HttpResponse response)
        {
            response.SetCookie(name, value);
            return true;
        }

        public void getCookie(string name, HttpRequest request, HttpResponse response)
        {
            string value = request.Cookies[name];
            response.Result(value);
        }
技術分享圖片

網頁資源處理

組件處理的網頁資源需要存放在當前項目的views目錄下,views目錄可以說是網頁資源的根目錄。網頁資源有兩種打包方式,一種是編譯復制到發布目錄下,而另一種則是嵌入到編譯資源中;建議選擇嵌入資源的發布方式,這樣最終發布的時候就只需要復制一個DLL即可,不過這種方式發布需要修改網頁資源都需要重新發布。對於編譯復制發布的好處是可以直接修改,組件會檢則修改情況重新刷新資源緩存。 技術分享圖片組件處理網頁資源有兩種方式,對於image的資源組件是在頭上標識為客戶端緩存,在沒過期的情況客戶端不會二次請求圖片資源。那對於HTML,CSS,JS這些文件組件會加個緩存標簽,當文件發生變化會重新響應給客戶端,否則響應304給客戶端。

開發階段調試簡化

由於網頁資源需要編譯才會被重新復制或嵌入的到程序中,這樣每修改一次都要編譯查看結果那是很麻煩的事情,也浪費大量工作時間。所以在啟動服務的時候執行一下HttpApiServer.Debug方法,通過這個方法可以把網頁資源目錄指向項目中網頁資源的目錄,這樣修改網頁也不需要重新編譯即可查看。 HttpApiServer.Debug只有在Debug模式下才能生效。 (提示FastHttpApi的url不區分大小寫)

以下是NorthWind數據訂單查詢的頁面代碼

技術分享圖片
<script>
    $(document).ready(function () {
        $.get("/GetEmployeesName", function (items) {
            items.forEach(function (v, i) {
                $(‘#lstEmployees‘).append(‘ <option value="‘ + v.ID + ‘">‘ + v.Name + ‘</option>‘)
            });
        });
        $.get("/GetCustomersName", function (items) {
            items.forEach(function (v, i) {
                $(‘#lstCustomers‘).append(‘ <option value="‘ + v.ID + ‘">‘ + v.Name + ‘</option>‘)
            });
        });
        search();
    });
    function search() {
        $.get(‘/listorders?employeeid=‘ + $(‘#lstEmployees‘).val() + "&customerid=" + $(‘#lstCustomers‘).val(), function (items) {
            $("#lstbody").empty();
            items.forEach(function (v, i) {
                $("#lstbody").append(‘<tr><td>‘ + i + ‘</td><td>‘ + v.OrderID + ‘</td><td>‘ + v.ShipName + ‘</td><td>‘ + v.ShipAddress + ‘</td><td>‘ + v.ShipCity + ‘</td><td>‘ + v.OrderDate + ‘</td></tr>‘)
            });
        });
    }
</script>
技術分享圖片

技術分享圖片

運行服務

FastHttpApi啟動Http服務非常簡單,並不需要做太多的配置即可運行

技術分享圖片
        private static HttpApiServer mApiServer;
        static void Main(string[] args)
        {
            mApiServer = new HttpApiServer();
            mApiServer.ServerConfig.BodySerializer = new JsonBodySerializer();
            mApiServer.Register(typeof(Program).Assembly);
            //config.SSL = true;
            //mApiServer.ServerConfig.CertificateFile = @"c:\ssltest.pfx";
            //mApiServer.ServerConfig.CertificatePassword = "123456";
            mApiServer.Debug();
            mApiServer.Open();
            Console.Write(mApiServer.BaseServer);
            Console.Read();
        }
技術分享圖片

如果希望修改一些基礎配置信息,如服務IP和端等可以通過HttpApiServer.ServerConfig來修改;也可以通過HttpConfig.json來配置相應信息.

(具體代碼查看:https://github.com/IKende/FastHttpApi/tree/master/samples)

dotnet core使用開源組件FastHttpApi進行web應用開發(轉)