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;
}
}
}