FastHttpApi相對於asp.net mvc來講有着更輕量和性能上的優點,性能上面就不在這裏介紹了(具體可查看 https://github.com/IKende/FastHttpApi)。在這裏主要講解一下如何使用FastHttpApi進行網站或WebApi開發,在使用FastHttpApi以前必須瞭解它具有那些功能,它除了提供webapi服務的編寫外還提供了靜態資源的支持,簡單來講FastHttpApi除了能實現基於HTTP的服務交互外還能實現應用網站;雖然不提供視MVC那樣的視圖處理功能,但能夠經過現有比較成熟的先後端分離技術來實現應用網站的編寫。如下是簡單地描述一下FastHttpApi的功能:css
- 支持以函數的方式來制定HTTP請求邏輯
- 支持使用者處理異步響應
- 支持Filter功能,以便更好地控制請求方法的處理
- 支持自定義Http Body解釋器,方便制定基於json,xml,protobuf,msgpack等數據格式的傳輸
- 支持QueryString參數和Cookies
- 支持外置或內嵌到DLL的靜態資源輸出(默認對html,js,css資源進行GZIP處理)
- 支持SSL
(在後續版升級主要功能:同一服務端口的控制器邏輯會同時兼容http和websocket兩種協議請求)html
經過以上功能徹底能夠用來構建高效全安的應用網站。如下經過一些例子詳細講述如何使用FastHttpApi。git
定義HTTP請求的方法
在FastHttpApi定義HTTP請求的方法和asp.net webapi差很少,都是經過定義一個控制器而後定義相關請求方法便可,固然使用起來會簡單一些。如下以Northwind的數據做爲基礎制定了一個簡單的數據訪問控制器github
[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請求。web
異步應答處理
對於HTTP來講,一個請求就必需要應答,由於這是HTTP協議規範;在實際業務中每每方法處理完成就進行應答,但有些狀況下須要異步應答;當一個業務須要處理大量IO的業務時那就會把線程處於等待狀態,爲了更好地處理這種狀況組件提供了異步應答處理;經過異步應答能夠在大量IO處理異步回調後再進行應答處理。json
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攔截器。api
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消息體的解釋和一些錯誤狀態返回的數據websocket
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)