开源组件websocket-sharp中基于webapi的httpserver使用体验

一、背景

  因为需要做金蝶ERP的二次开发,金蝶ERP的开放性真是不错,但是二次开发金蝶一般使用引用BOS.dll的方式,这个dll对newtonsoft.json.dll这个库是强引用,必须要用4.0版本,而asp.net mvc的webapi client对newtonsoft.json.dll的最低版本是6.0.这样就不能用熟悉的webapi client开发了。金蝶ERP据说支持无dll引用方式,标准的webapi方式,但官方支持有限,网上的文档也有限且参考意义不大。所以最后把目光聚集在自建简单httpserver上,最好是用.net 4作为运行时。在此感谢“C#基于websocket-sharp实现简易httpserver(封装)”作者的分享,了解到这个开源组件。

二、定制和修改

  • 1、修改“注入控制器到IOC容器”的方法适应现有项目的解决方案程序集划分
  • 2、修改“响应HttpPost请求”时方法参数解析和传递方式,增加了“FromBoby”自定义属性来标记参数是个数据传输对象。
  • 3、扩展了返回值类型,增加了HtmlResult和ImageResult等类型

代码:

       1)、修改“注入控制器到IOC容器”的方法

 /// <summary>
        /// 注入控制器到IOC容器
        /// </summary>
        /// <param name="builder"></param>
        public void InitController(ContainerBuilder builder)
        {
            Assembly asb = Assembly.Load("Business.Controller");
            if (asb != null)
            {
                var typesToRegister = asb.GetTypes()
                                      .Where(type => !string.IsNullOrEmpty(type.Namespace))
                                      .Where(type => type.BaseType == typeof(ApiController) || type.BaseType.Name.Equals("K3ErpBaseController"));
                if (typesToRegister.Count() > 0)
                {
                    foreach (var item1 in typesToRegister)
                    {
                        builder.RegisterType(item1).PropertiesAutowired();
                        foreach (var item2 in item1.GetMethods())
                        {
                            IExceptionFilter _exceptionFilter = null;
                            foreach (var item3 in item2.GetCustomAttributes(true))
                            {
                                Attribute temp = (Attribute)item3;
                                Type type = temp.GetType().GetInterface(typeof(IExceptionFilter).Name);
                                if (typeof(IExceptionFilter) == type)
                                {
                                    _exceptionFilter = item3 as IExceptionFilter;
                                }
                            }
                            MAction mAction = new MAction()
                            {
                                RequestRawUrl = @"/" + item1.Name.Replace("Controller", "") + @"/" + item2.Name,
                                Action = item2,
                                TypeName = item1.GetType().Name,
                                ControllerType = item1,
                                ParameterInfo = item2.GetParameters(),
                                ExceptionFilter = _exceptionFilter
                            };
                            dict.Add(mAction.RequestRawUrl, mAction);
                        }
                    }
                }
            }
            container = builder.Build();
        }

  2)、修改“响应HttpPost请求”时方法参数解析和传递方式,增加了“FromBoby”自定义属性;增加了HtmlResult和ImageResult等类型

  /// <summary>
        /// 响应HttpPost请求
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Httpsv_OnPost(object sender, HttpRequestEventArgs e)
        {
            MAction requestAction = new MAction();
            string content = string.Empty;
            try
            {
                byte[] binaryData = new byte[e.Request.ContentLength64];
                content = Encoding.UTF8.GetString(GetBinaryData(e, binaryData));
                string action_name = string.Empty;
                if (e.Request.RawUrl.Contains("?"))
                {
                    int index = e.Request.RawUrl.IndexOf("?");
                    action_name = e.Request.RawUrl.Substring(0, index);
                }
                else
                    action_name = e.Request.RawUrl;
                if (dict.ContainsKey(action_name))
                {
                    requestAction = dict[action_name];
                    object first_para_obj;
                    object[] para_values_objs = new object[requestAction.ParameterInfo.Length];
                    //没有参数,默认为空对象
                    if (requestAction.ParameterInfo.Length == 0)
                    {
                        first_para_obj = new object();
                    }
                    else
                    {
                        int para_count = requestAction.ParameterInfo.Length;
                        for (int i = 0; i < para_count; i++)
                        {
                            var para = requestAction.ParameterInfo[i];
                            if (para.GetCustomAttributes(typeof(FromBodyAttribute), false).Any())
                            {
                                //反序列化Json对象成数据传输对象
                                var dto_object = para.ParameterType;
                                para_values_objs[i] = JsonConvert.DeserializeObject(content, dto_object);
                            }
                            else
                            {
                                //参数含有FromBodyAttribute的只能有一个,且必须是第一个
                                int index = e.Request.RawUrl.IndexOf("?");
                                if (e.Request.RawUrl.Contains("&"))
                                {
                                    bool existsFromBodyParameter = false;
                                    foreach (var item in requestAction.ParameterInfo)
                                    {
                                        if (item.GetCustomAttributes(typeof(FromBodyAttribute), false).Any())
                                        {
                                            existsFromBodyParameter = true;
                                            break;
                                        }
                                    }
                                    string[] url_para = e.Request.RawUrl.Substring(index + 1).Split("&".ToArray(), StringSplitOptions.RemoveEmptyEntries);
                                    if (existsFromBodyParameter)
                                        para_values_objs[i] = url_para[i - 1].Replace(para.Name + "=", "");
                                    else
                                        para_values_objs[i] = url_para[i].Replace(para.Name + "=", "");
                                }
                                else
                                {
                                    para_values_objs[i] = e.Request.RawUrl.Substring(index + 1).Replace(para.Name + "=", "");
                                }
                            }
                        }
                    }
                    var action = container.Resolve(requestAction.ControllerType);
                    var action_result = requestAction.Action.Invoke(action, para_values_objs);
                    if (action_result == null)
                    {
                        e.Response.StatusCode = 204;
                    }
                    else
                    {
                        e.Response.StatusCode = 200;
                        if (requestAction.Action.ReturnType.Name.Equals("ApiActionResult"))
                        {
                            e.Response.ContentType = "application/json";
                            byte[] buffer = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(action_result));
                            e.Response.WriteContent(buffer);
                        }
                        if (requestAction.Action.ReturnType.Name.Equals("agvBackMessage"))
                        {
                            e.Response.ContentType = "application/json";
                            byte[] buffer = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(action_result));
                            e.Response.WriteContent(buffer);
                        }
                        else if (requestAction.Action.ReturnType.Name.Equals("HtmlResult"))
                        {
                            HtmlResult result = (HtmlResult)action_result;
                            e.Response.ContentType = result.ContentType;
                            byte[] buffer = result.Encoder.GetBytes(result.Content);
                            e.Response.WriteContent(buffer);
                        }
                        else if (requestAction.Action.ReturnType.Name.Equals("ImageResult"))
                        {
                            ImageResult apiResult = (ImageResult)action_result;
                            e.Response.ContentType = apiResult.ContentType;
                            byte[] buffer = Convert.FromBase64String(apiResult.Base64Content.Split(",".ToArray(), StringSplitOptions.RemoveEmptyEntries).LastOrDefault());
                            e.Response.WriteContent(buffer);
                        }
                        else
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes(action_result.ToString());
                            e.Response.WriteContent(buffer);
                        }
                    }
                }
                else
                {
                    e.Response.StatusCode = 404;
                }
            }
            catch (Exception ex)
            {
                if (requestAction.ExceptionFilter == null)
                {
                    byte[] buffer = Encoding.UTF8.GetBytes(ex.Message + ex.StackTrace);
                    e.Response.WriteContent(buffer);
                    e.Response.StatusCode = 500;
                }
                else
                {
                    if (requestAction.ExceptionFilter != null)
                    {
                        if (ex.InnerException != null)
                        {
                            requestAction.ExceptionFilter.OnException(ex.InnerException, e);
                        }
                        else
                        {
                            requestAction.ExceptionFilter.OnException(ex, e);
                        }
                    }
                }
            }
        }

三、体验概述

  • 1、稳,可用性很高,简单直接。
  • 2、使用之后对mvc的底层理解提高很多。
  • 3、对Autofac等IOC容器有了新的认识,项目里大量使用了属性注入方式来解除耦合。

四、一些截图

posted @ 2019-05-18 23:50  数据酷软件  阅读(831)  评论(1编辑  收藏