优雅的在WinForm/WPF/控制台 中使用特性封装WebApi

优雅的在WinForm/WPF/控制台 中使用特性封装WebApi

说明

在C/S端作为Server,建立HTTP请求,方便快捷。

1.使用到的类库

Newtonsoft.dll

2.封装 HttpListener

HttpApi类
    public class HttpApi
    {

        private static List<HttpListener> HttpListenerList = new List<HttpListener>();

        /// <summary>
        /// 初始化服务
        /// </summary>
        public static void InitService()
        {

            //获取程序集下面的所有的类
            Type[] types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes();
            foreach (Type item_type in types)
            {
                //定义是否有类的特性标识
                bool IsHasFormApi = false;
                //取类上的自定义特性
                object[] objs = item_type.GetCustomAttributes(typeof(FromApi), true);
                foreach (object obj in objs)
                {
                    FromApi fromApi = obj as FromApi;
                    if (fromApi != null)
                    {
                        IsHasFormApi = true;
                        break;
                    }
                }
                if (IsHasFormApi)
                {
                    // 获取完全名称
                    String className = item_type.FullName;

                    // 根据命名空间反射类的Type
                    Type type = Type.GetType(className);
                    object objInstance = type.Assembly.CreateInstance(className);

                    // 获取所有的方法
                    MethodInfo[] info = type.GetMethods();

                    // 遍历所有的方法
                    foreach (MethodInfo item in info)
                    {

                        // 获取Http请求方法
                        HttpMethod httpMethod = item.GetCustomAttribute<HttpMethod>();
                        // 获取Action
                        ActionName actionName = item.GetCustomAttribute<ActionName>();

                        // 判断有没有特性
                        if (httpMethod != null || actionName != null)
                        {
                            HttpListener listerner = new HttpListener();
                            listerner.AuthenticationSchemes = AuthenticationSchemes.Anonymous;//指定身份验证 Anonymous匿名访问
                            string url = "http://127.0.0.1:8011";
                            if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["httpserver"]))
                            {
                                url = "http://" + ConfigurationManager.AppSettings["httpserver"];
                            }
                            listerner.Prefixes.Add(url + actionName.URL + "/");

                            //开启服务
                            if (!listerner.IsListening)
                            {
                                listerner.Start();
                                AsyncCallback ac = new AsyncCallback(GetContextAsyncCallback);
                                CallbackObject callback = new CallbackObject() { Listerner = listerner, MethodItem = item, ClassInstance = objInstance, HttpMethod = httpMethod.method };
                                listerner.BeginGetContext(ac, callback);
                                HttpListenerList.Add(listerner);
                            }
                        }

                    }
                }
            }


        }

        /// <summary>
        /// 收到监听请求回调
        /// </summary>
        /// <param name="ia"></param>
        private static void GetContextAsyncCallback(IAsyncResult ia)
        {
            CallbackObject state = ia.AsyncState as CallbackObject;
            if (ia.IsCompleted)
            {
                HttpListenerContext ctx = state.Listerner.EndGetContext(ia);

                var request = ctx.Request;

                HttpListenerResponse response = ctx.Response;


                try
                {

                    //判断 请求 方式
                    if (request.HttpMethod.ToUpper() == state.HttpMethod.ToString().ToUpper() || Method.All.ToString().ToUpper() == state.HttpMethod.ToString().ToUpper())
                    {
                        string rawData;

                        using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
                        {
                            rawData = reader.ReadToEnd();
                        }


                        //获取方法参数列表

                        ParameterInfo[] parameterInfos = state.MethodItem.GetParameters();

                        //参数
                        // List<object> paramters = new List<object>();
                        object[] paramters = new object[parameterInfos.Length];

                        for (int i = 0; i < parameterInfos.Length; i++)
                        {
                            ParameterInfo item = parameterInfos[i];
                            if (item.ParameterType == typeof(string) || item.ParameterType == typeof(int) || item.ParameterType == typeof(bool))
                            {
                                paramters[i] = JsonHelper.GetJsonValue(rawData, item.Name);
                            }
                            else
                            {
                                Type t = item.ParameterType;
                                paramters[i] = JsonConvert.DeserializeObject(rawData, t);
                            }
                        }


                        object resobj = state.MethodItem.Invoke(state.ClassInstance, paramters);
                        if (typeof(string) == resobj.GetType())
                        {
                            ResponseWrite(response, resobj.ToString());
                        }
                        else
                        {
                            ResponseWrite(response, JsonConvert.SerializeObject(resobj));
                        }
                    }
                    else
                    {
                        ResponseWrite(response, $"不支持{request.HttpMethod.ToUpper()}方法请求!");
                    }
                }
                catch (Exception ex)
                {
                    ResponseWrite(response, $"服务出现异常,异常信息:{ex.Message}");
                }
            }

            //重新监听  不写的话只能调用一次 
            AsyncCallback ac = new AsyncCallback(GetContextAsyncCallback);
            state.Listerner.BeginGetContext(ac, state);
        }

        /// <summary>
        /// 回写响应
        /// </summary>
        /// <param name="response"></param>
        /// <param name="Content"></param>
        private static void ResponseWrite(HttpListenerResponse response, string Content)
        {
            //使用Writer输出http响应代码
            using (System.IO.StreamWriter writer = new System.IO.StreamWriter(response.OutputStream, new UTF8Encoding()))
            {
                response.ContentType = "application/json; charset=utf-8";
                writer.WriteLine(Content);
                writer.Close();
                response.Close();
            }
        }
    }



    public enum Method
    {
        All, Post, Get
    }

    public class CallbackObject
    {
        /// <summary>
        /// 监听
        /// </summary>
        public HttpListener Listerner { get; set; }

        /// <summary>
        /// 方法
        /// </summary>
        public MethodInfo MethodItem { get; set; }

        /// <summary>
        /// 调用者 对象
        /// </summary>
        public object ClassInstance { get; set; }

        /// <summary>
        /// 调用方式 Get Post
        /// </summary>
        public Method HttpMethod { get; set; }
    }
特性类 ActionName
    [AttributeUsage(AttributeTargets.Method)]
    class ActionName : Attribute
    {
        public string URL { get; set; }
        public ActionName()
        {

        }
        public ActionName(string url)
        {
            this.URL = url;
        }
    }
特性类 HttpMethod
    [AttributeUsage(AttributeTargets.Method)]
    public class HttpMethod : Attribute
    {
        public Method method { get; set; }
        public HttpMethod()
        {
            this.method = Method.All;
        }

        public HttpMethod(Method _method)
        {
            this.method = _method;
        }

    }
特性类 FromApi
    [AttributeUsage(AttributeTargets.Class)]
    public class FromApi : Attribute
    {
        //窗体里的具体方法忽略
    }
帮助类 JsonHelper
    public static class JsonHelper
    {
        public static string GetJsonValue(string json, string key)
        {
            string value = "";
            if (string.IsNullOrEmpty(json)) { return ""; }
            JObject jo = (JObject)JsonConvert.DeserializeObject(json);
            if (jo.ContainsKey(key))
            {
                if (jo[key] != null)
                {
                    value = jo[key].ToString();
                }
            }
            return value;
        }
        public static List<string> GetJsonList(string json, string key)
        {
            List<string> value = new List<string>();
            if (string.IsNullOrEmpty(json)) { return new List<string>(); }
            JObject jo = (JObject)JsonConvert.DeserializeObject(json);
            if (jo.ContainsKey(key))
            {
                if (jo[key] != null)
                {
                    foreach (var item in jo[key])
                    {
                        value.Add(item.ToString());
                    }
                }
            }
            return value;
        }
    }

3.在Web.config中增加

  <appSettings>
    <add key="httpserver" value="127.0.0.1:8022"/>
  </appSettings>

4.使用方法

  • 4.1在窗体类上增加 [FromApi] 特性
    [FromApi]
    public partial class ScoketForm : Form
    {
        
    }
  • 4.2Program.cs 中增加 这种初始化方式会对程序集中所有带有 [FromApi] 特性的类进行初始化
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    //服务初始化
    HttpApi.InitService();  //这里是增加初始化的代码
    Application.Run(new SocketTest.gg.ScoketForm());
  • 4.3具体使用方法 HttpMethod 后面可以不写,不写的话代表 支持两种请求方式 POST,GET 需要注意命名空间的导入
        /// <summary>
        /// 方法说明
        /// </summary>
        /// <returns></returns>
        [HttpMethod(Method.Post), ActionName("/api/index")]
        public HttpResult Index(List<string> Ids)
        {

            HttpResult httpResult = new HttpResult();

            //具体方法内容
            return httpResult;
        }

感兴趣的可以加QQ群:765907694 一起交流,探讨技术问题

posted @ 2019-08-16 18:21  Yann_123  阅读(927)  评论(0编辑  收藏  举报