zoukankan      html  css  js  c++  java
  • dotnet core使用开源组件FastHttpApi进行web应用开发

    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

  • 相关阅读:
    poj 2584 T-Shirt Gumbo (二分匹配)
    hdu 1757 A Simple Math Problem (乘法矩阵)
    矩阵之矩阵乘法(转载)
    poj 2239 Selecting Courses (二分匹配)
    hdu 3661 Assignments (贪心)
    hdu 1348 Wall (凸包)
    poj 2060 Taxi Cab Scheme (二分匹配)
    hdu 2202 最大三角形 (凸包)
    hdu 1577 WisKey的眼神 (数学几何)
    poj 1719 Shooting Contest (二分匹配)
  • 原文地址:https://www.cnblogs.com/smark/p/9698566.html
Copyright © 2011-2022 走看看