FastHttpApi 相对于 ASP.NET mvc 来说有着更轻量和性能上的优势, 性能上面就不在这里介绍了(具体可查看 https://GitHub.com/IKende/FastHttpApi ). 在这里主要讲解一下如何使用 FastHttpApi 进行网站或 webApi 开发, 在使用 FastHttpApi 之前必须了解它具备那些功能, 它除了提供 webapi 服务的编写外还提供了静态资源的支持, 简单来说 FastHttpApi 除了能实现基于 HTTP 的服务交互外还能实现应用网站; 虽然不提供视 MVC 那样的视图处理功能, 但可以通过现有比较成熟的前后端分离技术来实现应用网站的编写. 以下是简单地描述一下 FastHttpApi 的功能:
支持以函数的方式来制定 HTTP 请求逻辑
支持使用者处理异步响应
支持 Filter 功能, 以便更好地控制请求方法的处理
支持自定义 Http Body 解释器, 方便制定基于 JSON,xml,protobuf,msgpack 等数据格式的传输
支持 QueryString 参数和 Cookies
支持外置或内嵌到 DLL 的静态资源输出(默认对 html,JS,CSS 资源进行 GZIP 处理)
支持 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://www.cnblogs.com/smark/p/9698566.html