using Newtonsoft.Json; using Song.ViewData.Attri; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace Song.ViewData { /// /// 执行具体的方法 /// public class ExecuteMethod { #region 单件模式 private static readonly ExecuteMethod _instance = new ExecuteMethod(); private ExecuteMethod() { } /// /// 返回实例 /// /// public static ExecuteMethod GetInstance() { return _instance; } #endregion #region 创建并缓存实例对象 //存储对象的键值对,key为对象的类名称(全名),value为对象自身 private Dictionary _objects = new Dictionary(); /// /// 创建对象,如果存在,则直接返回;如果不存在,创建后返回 /// /// /// public static object CreateInstance(Letter letter) { string assemblyName = "Song.ViewData"; string classFullName = String.Format("{0}.Methods.{1}", assemblyName, letter.ClassName); object obj = null; //由缓存中查找,是否存在 ExecuteMethod curr = ExecuteMethod.GetInstance(); foreach (KeyValuePair kv in curr._objects) { if (classFullName.Trim().Equals(kv.Key, StringComparison.CurrentCultureIgnoreCase)) { obj = kv.Value; break; } } if (obj != null) return obj; //如果之前未创建,则重新创建 Type type = null; Assembly assembly = Assembly.Load(assemblyName); Type[] types = assembly.GetExportedTypes() .Where(t => t.GetInterfaces().Contains(typeof(IViewAPI))) .ToArray(); foreach (Type info in types) { if (info.FullName.Equals(classFullName, StringComparison.CurrentCultureIgnoreCase)) { type = info; break; } } if (type == null) throw new Exception( string.Format("调用的对象'{0}'不存在, 可能是'{1}'拼写错误", classFullName, letter.ClassName)); obj = System.Activator.CreateInstance(type); //创建对象 ExecuteMethod.GetInstance()._objects.Add(type.FullName, obj); //记录到缓存 return obj; } #endregion /// /// 执行,按实际结果返回 /// /// 客户端递交的参数信息 /// public static object Exec(Letter letter) { //1.创建对象,即$api.get("account/single")中的account object execObj = ExecuteMethod.CreateInstance(letter); //2.获取要执行的方法,即$api.get("account/single")中的single MethodInfo method = getMethod(execObj.GetType(), letter); //3#.验证方法的特性,一是验证Http动词,二是验证是否登录后操作,三是验证权限 //----验证Http谓词访问限制 HttpAttribute.Verify(letter.HTTP_METHOD, method); //LoginAttribute.Verify(method); //----范围控制,本机或局域网,或同域 bool isRange = RangeAttribute.Verify(letter, method); //----验证是否需要登录 LoginAttribute loginattr = LoginAttribute.Verify(method); //4.构建执行该方法所需要的参数 object[] parameters = getInvokeParam(method, letter); //5.执行方法,返回结果 object objResult = null; //结果 //只有get方式时,才使用缓存 CacheAttribute cache = null; if (letter.HTTP_METHOD.Equals("put", StringComparison.CurrentCultureIgnoreCase)) CacheAttribute.Remove(method, letter); if (letter.HTTP_METHOD.Equals("get", StringComparison.CurrentCultureIgnoreCase)) cache = CacheAttribute.GetAttr(method); if (cache != null) { objResult = CacheAttribute.GetResult(method, letter); if (objResult == null) { objResult = method.Invoke(execObj, parameters); CacheAttribute.Insert(cache.Expires, method, letter, objResult); } } else { objResult = method.Invoke(execObj, parameters); } //将执行结果写入日志 LoginAttribute.LogWrite(loginattr, objResult); return objResult; } /// /// 执行,返回结构封装到DataResult对象中 /// /// 客户端递交的参数信息 /// public static DataResult ExecToResult(Letter letter) { DateTime time = DateTime.Now; try { if (!"weishakeji".Equals(letter.HTTP_Mark)) throw VExcept.System("请求标识不正确", 100); //执行方法 object res = Exec(letter); //计算耗时 double span = ((TimeSpan)(DateTime.Now - time)).TotalMilliseconds; // //如果是分页数据 if (res is ListResult) { ListResult list = (ListResult)res; list.ExecSpan = span; return list; } return new Song.ViewData.DataResult(res, span); //普通数据 } catch (Exception ex) { //如果是自定义异常 if (ex.InnerException is VExcept) { VExcept except = (VExcept)ex.InnerException; return new Song.ViewData.DataResult(except, time); } return new Song.ViewData.DataResult(ex, time); } } /// /// 要执行的方法,根据方法名、参数数量 /// /// 要调用的对象的类型 /// /// private static MethodInfo getMethod(Type type, Letter p) { //1、先判断方法是否存在 List methods = new List(); foreach (MethodInfo mi in type.GetMethods()) { if (p.MethodName.Equals(mi.Name, StringComparison.CurrentCultureIgnoreCase)) methods.Add(mi); } if (methods.Count < 1) throw new Exception(string.Format("调用方法'{0}.{1}'不存在", p.ClassName, p.MethodName)); //2、判断方法的参数名称,是否与传递来的参数名称匹配,参数数量必须匹配 //只有一个参数,且类型是Letter MethodInfo mbLetter = null; for (int i = 0; i < methods.Count; i++) { ParameterInfo[] pis = methods[i].GetParameters(); if (pis.Length == 1 && p.GetType().FullName.Equals(pis[0].ParameterType.FullName)) { mbLetter = methods[i]; methods.Remove(methods[i]); break; } } MethodInfo method = null; foreach (MethodInfo mi in methods) { //2-1、判断参数个数是否相同 int paraCount = 0; foreach (ParameterInfo pi in mi.GetParameters()) { if (!pi.IsOut) paraCount++; } //方法的参数个数,和传参的参数个数,必须相等 if (paraCount == p.Params.Count) { method = mi; break; } } //2-2、判断参数名称与传递来的参数名称是否一致 if (method != null) { bool ismatch = true; //是否匹配 foreach (ParameterInfo pi in method.GetParameters()) { //如果参数是Parameter类型,则跳过匹配 if (p.GetType().FullName.Equals(pi.ParameterType.FullName)) continue; //只要有一个参数不匹配,即中断 if (!p.ExistParameter(pi.Name)) { ismatch = false; break; } } if (!ismatch) method = null; } if (method == null) method = mbLetter; if (method == null) throw new Exception( string.Format("所调用方法'{0}.{1}'的参数名称与实际传参不匹配;实际传参:{2}", type.FullName, p.MethodName, p.ToString() == string.Empty ? "null" : p.ToString())); return method; } /// /// 返回方法执行所需要的参数 /// /// 要执行的方法 /// 传递来的参数 /// private static object[] getInvokeParam(MethodInfo method, Letter letter) { ParameterInfo[] paramInfos = method.GetParameters(); object[] objs = new object[paramInfos.Length]; for (int i = 0; i < objs.Length; i++) { ParameterInfo pi = paramInfos[i]; //如果参数是Letter类型,则直接赋值 if (letter.GetType().FullName.Equals(pi.ParameterType.FullName)) { objs[i] = letter; continue; } //接口方法的参数所对应的客户端传来的值 string val = letter[pi.Name].String; //如果参数为输出型的,则不赋值(ViewData接口不允许此类参数) if (pi.IsOut || string.IsNullOrWhiteSpace(val)) { objs[i] = null; continue; } //如果参数是数据实体 if (pi.ParameterType.BaseType != null && pi.ParameterType.BaseType.FullName == "WeiSha.Data.Entity") { //创建实体 object entity = pi.ParameterType.Assembly.CreateInstance(pi.ParameterType.FullName); Dictionary dic = JsonConvert.DeserializeObject>(val); PropertyInfo[] props = pi.ParameterType.GetProperties(); for (int j = 0; j < props.Length; j++) { PropertyInfo opi = props[j]; //实体属性 foreach (KeyValuePair kv in dic) { if (kv.Key.Equals(opi.Name, StringComparison.CurrentCultureIgnoreCase)) { //实体属性的值 object tm = string.IsNullOrEmpty(kv.Value) ? null : WeiSha.Common.DataConvert.ChangeType(kv.Value, opi.PropertyType); opi.SetValue(entity, tm, null); continue; } } } objs[i] = entity; continue; } //将客户端传来的参数,转换为方法对应的参数类型 if (!pi.ParameterType.Name.Equals("string", StringComparison.CurrentCultureIgnoreCase)) { if (string.IsNullOrWhiteSpace(val)) throw new Exception("参数 " + pi.Name + " 的值为空"); } try { switch (pi.ParameterType.Name) { case "DateTime": if (val == null || string.IsNullOrWhiteSpace(val.ToString())) { objs[i] = DateTime.Now; break; } DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); long lTime = long.Parse(val + "0000"); TimeSpan toNow = new TimeSpan(lTime); objs[i] = dt.Add(toNow); break; default: objs[i] = Convert.ChangeType(val, pi.ParameterType); break; } } catch { throw new Exception("参数 " + pi.Name + " 的值,数据格式不正确"); } } return objs; } } }